[flang-commits] [flang] [flang][rfc] Add represention of volatile references (PR #132486)
Asher Mancinelli via flang-commits
flang-commits at lists.llvm.org
Thu Apr 10 19:40:57 PDT 2025
https://github.com/ashermancinelli updated https://github.com/llvm/llvm-project/pull/132486
>From 8a5c2843bccacdfdda53d967a6b3973262b59d40 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Thu, 20 Mar 2025 08:01:56 -0700
Subject: [PATCH 1/4] [flang] Add represention of volatile references
Flang currently lacks support for volatile variables. For some cases, the
compiler produces TODO error messages and others are ignored. Some of our tests
are like the example from C.4 Clause 8 notes: The VOLATILE attribute (8.5.20)
and require volatile variables.
This change is a minimal draft of support for volatility in Fortran. This
misses several important features that will be required for full support,
such as volatile boxes and other reference-like types. This commit only
supports volatility for !fir.ref<T> types and is the minimum needed to
get end-to-end examples working.
---
.../flang/Optimizer/Builder/BoxValue.h | 2 +-
.../flang/Optimizer/Builder/FIRBuilder.h | 9 ++
.../Optimizer/Builder/Runtime/RTBuilder.h | 6 +-
.../include/flang/Optimizer/Dialect/FIROps.h | 6 +
.../include/flang/Optimizer/Dialect/FIROps.td | 40 +++++--
.../flang/Optimizer/Dialect/FIROpsSupport.h | 26 ++--
.../include/flang/Optimizer/Dialect/FIRType.h | 4 +
.../flang/Optimizer/Dialect/FIRTypes.td | 5 +
flang/lib/Lower/Bridge.cpp | 3 +-
flang/lib/Lower/CallInterface.cpp | 8 +-
flang/lib/Lower/ConvertCall.cpp | 24 +++-
flang/lib/Lower/ConvertExprToHLFIR.cpp | 33 +++++-
flang/lib/Lower/HostAssociations.cpp | 16 +--
flang/lib/Lower/IO.cpp | 13 +-
flang/lib/Optimizer/Builder/FIRBuilder.cpp | 27 ++++-
flang/lib/Optimizer/Builder/HLFIRTools.cpp | 3 +-
flang/lib/Optimizer/Builder/MutableBox.cpp | 15 ++-
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 60 ++++++----
flang/lib/Optimizer/Dialect/FIROps.cpp | 111 ++++++++++++++++-
flang/lib/Optimizer/Dialect/FIRType.cpp | 60 ++++++----
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp | 21 +++-
.../HLFIR/Transforms/ConvertToFIR.cpp | 7 +-
.../Transforms/OptimizedBufferization.cpp | 9 +-
flang/test/Fir/volatile.fir | 18 +++
flang/test/HLFIR/volatile.fir | 21 ++++
flang/test/Lower/volatile1.f90 | 93 +++++++++++++++
flang/test/Lower/volatile2.f90 | 63 ++++++++++
flang/test/Lower/volatile3.f90 | 112 ++++++++++++++++++
flang/test/Lower/volatile4.f90 | 91 ++++++++++++++
29 files changed, 799 insertions(+), 107 deletions(-)
create mode 100644 flang/test/Fir/volatile.fir
create mode 100644 flang/test/HLFIR/volatile.fir
create mode 100644 flang/test/Lower/volatile1.f90
create mode 100644 flang/test/Lower/volatile2.f90
create mode 100644 flang/test/Lower/volatile3.f90
create mode 100644 flang/test/Lower/volatile4.f90
diff --git a/flang/include/flang/Optimizer/Builder/BoxValue.h b/flang/include/flang/Optimizer/Builder/BoxValue.h
index 5f9834bfb8ec9..43b70943aced6 100644
--- a/flang/include/flang/Optimizer/Builder/BoxValue.h
+++ b/flang/include/flang/Optimizer/Builder/BoxValue.h
@@ -236,7 +236,7 @@ class AbstractIrBox : public AbstractBox, public AbstractArrayBox {
auto ty = getBoxTy().getEleTy();
if (fir::isa_ref_type(ty))
return ty;
- return fir::ReferenceType::get(ty);
+ return fir::ReferenceType::get(ty, fir::isa_volatile_type(getBoxTy()));
}
/// Get the scalar type related to the described entity
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index ddd4ef7114a63..a12283287a8b7 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -397,6 +397,15 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
mlir::Value val);
+ /// Create a fir.convert op with a volatile cast if the source value's type
+ /// does not match the target type's volatility.
+ mlir::Value createConvertWithVolatileCast(mlir::Location loc, mlir::Type toTy,
+ mlir::Value val);
+
+ /// Create a fir.volatile_cast op.
+ mlir::Value createVolatileCast(mlir::Location loc, bool isVolatile,
+ mlir::Value val);
+
/// Create a fir.store of \p val into \p addr. A lazy conversion
/// of \p val to the element type of \p addr is created if needed.
void createStoreWithConvert(mlir::Location loc, mlir::Value val,
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index a93c98f223839..5440b36c0c628 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -829,14 +829,16 @@ 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.createConvert(loc, fTy.getInput(N), 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.createConvert(loc, fTy.getInput(N), arg));
+ result.emplace_back(
+ builder.createConvertWithVolatileCast(loc, fTy.getInput(N), arg));
createArguments<N + 1>(result, builder, loc, fTy, args...);
}
} // namespace helper
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h
index ed301016ad01c..f3dbf47351ab8 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.h
@@ -50,6 +50,12 @@ struct DebuggingResource
mlir::StringRef getName() final { return "DebuggingResource"; }
};
+/// Model operations which read from/write to volatile memory
+struct VolatileMemoryResource
+ : public mlir::SideEffects::Resource::Base<VolatileMemoryResource> {
+ mlir::StringRef getName() final { return "VolatileMemoryResource"; }
+};
+
class CoordinateIndicesAdaptor;
using IntOrValue = llvm::PointerUnion<mlir::IntegerAttr, mlir::Value>;
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 753e4bd18dc6d..d8d2b0b8389de 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -286,7 +286,7 @@ def fir_FreeMemOp : fir_Op<"freemem", [MemoryEffects<[MemFree]>]> {
let assemblyFormat = "$heapref attr-dict `:` qualified(type($heapref))";
}
-def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
+def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "load a value from a memory reference";
let description = [{
Load a value from a memory reference into an ssa-value (virtual register).
@@ -302,7 +302,7 @@ def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
or null.
}];
- let arguments = (ins Arg<AnyReferenceLike, "", [MemRead]>:$memref,
+ let arguments = (ins AnyReferenceLike:$memref,
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
let builders = [OpBuilder<(ins "mlir::Value":$refVal)>,
@@ -315,7 +315,8 @@ def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
}];
}
-def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
+def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface,
+ DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "store an SSA-value to a memory location";
let description = [{
@@ -335,7 +336,7 @@ def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
}];
let arguments = (ins AnyType:$value,
- Arg<AnyReferenceLike, "", [MemWrite]>:$memref,
+ AnyReferenceLike:$memref,
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
let builders = [OpBuilder<(ins "mlir::Value":$value, "mlir::Value":$memref)>];
@@ -348,7 +349,7 @@ def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
}];
}
-def fir_CopyOp : fir_Op<"copy", []> {
+def fir_CopyOp : fir_Op<"copy", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "copy constant size memory";
let description = [{
@@ -369,8 +370,8 @@ def fir_CopyOp : fir_Op<"copy", []> {
TODO: add FirAliasTagOpInterface to carry TBAA.
}];
- let arguments = (ins Arg<AnyRefOfConstantSizeAggregateType, "", [MemRead]>:$source,
- Arg<AnyRefOfConstantSizeAggregateType, "", [MemWrite]>:$destination,
+ let arguments = (ins AnyRefOfConstantSizeAggregateType:$source,
+ AnyRefOfConstantSizeAggregateType:$destination,
OptionalAttr<UnitAttr>:$no_overlap);
let builders = [OpBuilder<(ins "mlir::Value":$source,
@@ -1373,7 +1374,7 @@ def fir_BoxTypeDescOp : fir_SimpleOneResultOp<"box_tdesc", [NoMemoryEffect]> {
// !- Merge the new and old values into the memory for "A"
// array_merge_store <updated A> to <A's address>
-def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments]> {
+def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "Load an array as a value.";
@@ -1412,7 +1413,7 @@ def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments]> {
}];
let arguments = (ins
- Arg<AnyRefOrBox, "", [MemRead]>:$memref,
+ AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Optional<fir_SliceType>:$slice,
Variadic<AnyIntegerType>:$typeparams
@@ -1624,7 +1625,7 @@ def fir_ArrayAccessOp : fir_Op<"array_access", [AttrSizedOperandSegments,
It is only possible to use `array_access` on an `array_load` result value or
a value that can be trace back transitively to an `array_load` as the
- dominating source. Other array operation such as `array_amend` can be in
+ dominating source. Other array operations such as `array_amend` can be in
between.
TODO: The above restriction is not enforced. The design of the operation
@@ -1685,7 +1686,7 @@ def fir_ArrayAmendOp : fir_Op<"array_amend", [NoMemoryEffect]> {
}
def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
- [AttrSizedOperandSegments]> {
+ [AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "Store merged array value to memory.";
@@ -1714,7 +1715,7 @@ def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
let arguments = (ins
fir_SequenceType:$original,
fir_SequenceType:$sequence,
- Arg<AnyRefOrBox, "", [MemWrite]>:$memref,
+ AnyRefOrBox:$memref,
Optional<fir_SliceType>:$slice,
Variadic<AnyIntegerType>:$typeparams
);
@@ -2752,6 +2753,21 @@ def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoMemoryEffect]> {
let assemblyFormat = "`(` $symbol `)` attr-dict `:` type($resTy)";
}
+def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [NoMemoryEffect]> {
+ let summary = "cast between volatile and non-volatile types";
+ let description = [{
+ Cast between volatile and non-volatile types. The types must be otherwise
+ identical.
+ }];
+ let arguments = (ins AnyRefOrBox:$value);
+ let results = (outs AnyRefOrBox:$res);
+ let assemblyFormat = [{
+ $value attr-dict `:` functional-type($value, results)
+ }];
+ let hasVerifier = 1;
+ let hasFolder = 1;
+}
+
def fir_ConvertOp : fir_SimpleOneResultOp<"convert", [NoMemoryEffect]> {
let summary = "encapsulates all Fortran entity type conversions";
diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
index f7f0a3067b318..8f7ca63ca8d1f 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
@@ -15,13 +15,25 @@
namespace fir {
-/// Return true iff the Operation is a non-volatile LoadOp or ArrayLoadOp.
-inline bool nonVolatileLoad(mlir::Operation *op) {
- if (auto load = mlir::dyn_cast<fir::LoadOp>(op))
- return !load->getAttr("volatile");
- if (auto arrLoad = mlir::dyn_cast<fir::ArrayLoadOp>(op))
- return !arrLoad->getAttr("volatile");
- return false;
+/// The LLVM dialect represents volatile memory accesses as read and write
+/// effects to an unknown memory location, but this may be overly conservative.
+/// LLVM Language Reference only specifies that volatile memory accesses
+/// must not be reordered relative to other volatile memory accesses, so it
+/// is more precise to use a separate memory resource for volatile memory
+/// accesses.
+inline void addVolatileMemoryEffects(
+ mlir::TypeRange type,
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ for (mlir::Type t : type) {
+ if (fir::isa_volatile_type(t)) {
+ effects.emplace_back(mlir::MemoryEffects::Read::get(),
+ fir::VolatileMemoryResource::get());
+ effects.emplace_back(mlir::MemoryEffects::Write::get(),
+ fir::VolatileMemoryResource::get());
+ }
+ }
}
/// Return true iff the Operation is a call.
diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h
index 0dbff258aea86..52b14f15f89bd 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRType.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRType.h
@@ -457,6 +457,10 @@ inline mlir::Type wrapInClassOrBoxType(mlir::Type eleTy,
return fir::BoxType::get(eleTy);
}
+/// Re-create the given type with the given volatility, if this is a type
+/// that can represent volatility.
+mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile);
+
/// Return the elementType where intrinsic types are replaced with none for
/// unlimited polymorphic entities.
///
diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
index 84b3932ea75f6..6fad77dffd9bc 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
@@ -365,6 +365,11 @@ def fir_ReferenceType : FIR_Type<"Reference", "ref"> {
let description = [{
The type of a reference to an entity in memory.
+
+ References can be volatile. Any ops taking an operand of a volatile
+ reference must set their memory effects appropriately. Accesses of
+ volatile references are currently modeled as read and write effects
+ to a specific memory resource.
}];
let parameters = (ins "mlir::Type":$eleTy, "bool":$isVolatile);
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index b4d1197822a43..434fb2053a2e4 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1755,7 +1755,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// tags all result variables with one of the largest types to allow
// them to share the same storage. Convert this to the actual type.
if (resultRef.getType() != resultRefType)
- resultRef = builder->createConvert(loc, resultRefType, resultRef);
+ resultRef = builder->createConvertWithVolatileCast(
+ loc, resultRefType, resultRef);
return builder->create<fir::LoadOp>(loc, resultRef);
});
genExitRoutine(false, resultVal);
diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp
index 226ba1e52c968..73e0984f01635 100644
--- a/flang/lib/Lower/CallInterface.cpp
+++ b/flang/lib/Lower/CallInterface.cpp
@@ -1111,10 +1111,7 @@ class Fortran::lower::CallInterfaceImpl {
addMLIRAttr(fir::getContiguousAttrName());
if (obj.attrs.test(Attrs::Value))
isValueAttr = true; // TODO: do we want an mlir::Attribute as well?
- if (obj.attrs.test(Attrs::Volatile)) {
- TODO(loc, "VOLATILE in procedure interface");
- addMLIRAttr(fir::getVolatileAttrName());
- }
+
// obj.attrs.test(Attrs::Asynchronous) does not impact the way the argument
// is passed given flang implement asynch IO synchronously. However, it's
// added to determine whether the argument is captured.
@@ -1151,7 +1148,8 @@ class Fortran::lower::CallInterfaceImpl {
if (obj.attrs.test(Attrs::Allocatable) || obj.attrs.test(Attrs::Pointer)) {
// Pass as fir.ref<fir.box> or fir.ref<fir.class>
- mlir::Type boxRefType = fir::ReferenceType::get(boxType);
+ const bool isVolatile = obj.attrs.test(Attrs::Volatile);
+ mlir::Type boxRefType = fir::ReferenceType::get(boxType, isVolatile);
addFirOperand(boxRefType, nextPassedArgPosition(), Property::MutableBox,
attrs);
addPassedArg(PassEntityBy::MutableBox, entity, characteristics);
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 6a0f4d1090adc..9394f189ff4b4 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -327,7 +327,6 @@ Fortran::lower::genCallOpAndResult(
charFuncPointerLength = charBox->getLen();
}
}
-
const bool isExprCall =
converter.getLoweringOptions().getLowerToHighLevelFIR() &&
callSiteType.getNumResults() == 1 &&
@@ -519,7 +518,9 @@ Fortran::lower::genCallOpAndResult(
// Do not attempt any reboxing here that could break this.
bool legacyLowering =
!converter.getLoweringOptions().getLowerToHighLevelFIR();
- cast = builder.convertWithSemantics(loc, snd, fst,
+ cast =
+ builder.createVolatileCast(loc, fir::isa_volatile_type(snd), fst);
+ cast = builder.convertWithSemantics(loc, snd, cast,
callingImplicitInterface,
/*allowRebox=*/legacyLowering);
}
@@ -1417,6 +1418,25 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
addr = hlfir::genVariableRawAddress(loc, builder, entity);
}
+ // If the volatility of the input type does not match the dummy type,
+ // we need to cast the argument.
+ if (fir::isa_volatile_type(dummyTypeWithActualRank) !=
+ fir::isa_volatile_type(addr.getType())) {
+ const bool isToTypeVolatile =
+ fir::isa_volatile_type(dummyTypeWithActualRank);
+ mlir::Type volatileAdjustedType =
+ llvm::TypeSwitch<mlir::Type, mlir::Type>(addr.getType())
+ .Case<fir::ReferenceType, fir::BoxType>([&](auto ty) {
+ using TYPE = decltype(ty);
+ return TYPE::get(ty.getElementType(), isToTypeVolatile);
+ })
+ .Default([](auto t) {
+ assert(false && "unexpected type");
+ return t;
+ });
+ addr = builder.create<fir::VolatileCastOp>(loc, volatileAdjustedType, addr);
+ }
+
// For ranked actual passed to assumed-rank dummy, the cast to assumed-rank
// box is inserted when building the fir.call op. Inserting it here would
// cause the fir.if results to be assumed-rank in case of OPTIONAL dummy,
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 09bc1babf079c..a4f43aa2d85e3 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -223,8 +223,25 @@ class HlfirDesignatorBuilder {
designatorNode, getConverter().getFoldingContext(),
/*namedConstantSectionsAreAlwaysContiguous=*/false))
return fir::BoxType::get(resultValueType);
+
+ bool isVolatile = false;
+
+ // Check if the base type is volatile
+ if (partInfo.base.has_value()) {
+ mlir::Type baseType = partInfo.base.value().getType();
+ isVolatile = fir::isa_volatile_type(baseType);
+ }
+
+ // Check if this should be a volatile reference
+ if constexpr (std::is_same_v<std::decay_t<T>,
+ Fortran::evaluate::SymbolRef>) {
+ if (designatorNode.get().GetUltimate().attrs().test(
+ Fortran::semantics::Attr::VOLATILE))
+ isVolatile = true;
+ }
+
// Other designators can be handled as raw addresses.
- return fir::ReferenceType::get(resultValueType);
+ return fir::ReferenceType::get(resultValueType, isVolatile);
}
template <typename T>
@@ -415,10 +432,15 @@ class HlfirDesignatorBuilder {
.Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type {
return fir::SequenceType::get(seqTy.getShape(), newEleTy);
})
- .Case<fir::PointerType, fir::HeapType, fir::ReferenceType, fir::BoxType,
- fir::ClassType>([&](auto t) -> mlir::Type {
+ .Case<fir::PointerType, fir::HeapType, fir::ClassType>(
+ [&](auto t) -> mlir::Type {
+ using FIRT = decltype(t);
+ return FIRT::get(changeElementType(t.getEleTy(), newEleTy));
+ })
+ .Case<fir::ReferenceType, fir::BoxType>([&](auto t) -> mlir::Type {
using FIRT = decltype(t);
- return FIRT::get(changeElementType(t.getEleTy(), newEleTy));
+ return FIRT::get(changeElementType(t.getEleTy(), newEleTy),
+ t.isVolatile());
})
.Default([newEleTy](mlir::Type t) -> mlir::Type { return newEleTy; });
}
@@ -1809,6 +1831,7 @@ class HlfirBuilder {
auto &expr = std::get<const Fortran::lower::SomeExpr &>(iter);
auto &baseOp = std::get<hlfir::EntityWithAttributes>(iter);
std::string name = converter.getRecordTypeFieldName(sym);
+ const bool isVolatile = fir::isa_volatile_type(baseOp.getType());
// Generate DesignateOp for the component.
// The designator's result type is just a reference to the component type,
@@ -1819,7 +1842,7 @@ class HlfirBuilder {
assert(compType && "failed to retrieve component type");
mlir::Value compShape =
designatorBuilder.genComponentShape(sym, compType);
- mlir::Type designatorType = builder.getRefType(compType);
+ mlir::Type designatorType = builder.getRefType(compType, isVolatile);
mlir::Type fieldElemType = hlfir::getFortranElementType(compType);
llvm::SmallVector<mlir::Value, 1> typeParams;
diff --git a/flang/lib/Lower/HostAssociations.cpp b/flang/lib/Lower/HostAssociations.cpp
index 0f75a8a7c312e..e58dc827652ec 100644
--- a/flang/lib/Lower/HostAssociations.cpp
+++ b/flang/lib/Lower/HostAssociations.cpp
@@ -163,8 +163,8 @@ class CapturedSimpleScalars : public CapturedSymbols<CapturedSimpleScalars> {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
mlir::Type typeInTuple = fir::dyn_cast_ptrEleTy(args.addrInTuple.getType());
assert(typeInTuple && "addrInTuple must be an address");
- mlir::Value castBox = builder.createConvert(args.loc, typeInTuple,
- fir::getBase(args.hostValue));
+ mlir::Value castBox = builder.createConvertWithVolatileCast(
+ args.loc, typeInTuple, fir::getBase(args.hostValue));
builder.create<fir::StoreOp>(args.loc, castBox, args.addrInTuple);
}
@@ -194,8 +194,8 @@ class CapturedProcedure : public CapturedSymbols<CapturedProcedure> {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
mlir::Type typeInTuple = fir::dyn_cast_ptrEleTy(args.addrInTuple.getType());
assert(typeInTuple && "addrInTuple must be an address");
- mlir::Value castBox = builder.createConvert(args.loc, typeInTuple,
- fir::getBase(args.hostValue));
+ mlir::Value castBox = builder.createConvertWithVolatileCast(
+ args.loc, typeInTuple, fir::getBase(args.hostValue));
builder.create<fir::StoreOp>(args.loc, castBox, args.addrInTuple);
}
@@ -265,8 +265,8 @@ class CapturedPolymorphicScalar
mlir::Location loc = args.loc;
mlir::Type typeInTuple = fir::dyn_cast_ptrEleTy(args.addrInTuple.getType());
assert(typeInTuple && "addrInTuple must be an address");
- mlir::Value castBox = builder.createConvert(args.loc, typeInTuple,
- fir::getBase(args.hostValue));
+ mlir::Value castBox = builder.createConvertWithVolatileCast(
+ args.loc, typeInTuple, fir::getBase(args.hostValue));
if (Fortran::semantics::IsOptional(sym)) {
auto isPresent =
builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), castBox);
@@ -329,8 +329,8 @@ class CapturedAllocatableAndPointer
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
mlir::Type typeInTuple = fir::dyn_cast_ptrEleTy(args.addrInTuple.getType());
assert(typeInTuple && "addrInTuple must be an address");
- mlir::Value castBox = builder.createConvert(args.loc, typeInTuple,
- fir::getBase(args.hostValue));
+ mlir::Value castBox = builder.createConvertWithVolatileCast(
+ args.loc, typeInTuple, fir::getBase(args.hostValue));
builder.create<fir::StoreOp>(args.loc, castBox, args.addrInTuple);
}
static void getFromTuple(const GetFromTuple &args,
diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 13d612354da84..c6bd65686a6e0 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -720,7 +720,8 @@ static void genOutputItemList(
fir::factory::CharacterExprHelper helper{builder, loc};
if (mlir::isa<fir::BoxType>(argType)) {
mlir::Value box = fir::getBase(converter.genExprBox(loc, *expr, stmtCtx));
- outputFuncArgs.push_back(builder.createConvert(loc, argType, box));
+ outputFuncArgs.push_back(
+ builder.createConvertWithVolatileCast(loc, argType, box));
if (containsDerivedType(itemTy))
outputFuncArgs.push_back(getNonTbpDefinedIoTableAddr(converter));
} else if (helper.isCharacterScalar(itemTy)) {
@@ -730,9 +731,9 @@ static void genOutputItemList(
if (!exv.getCharBox())
llvm::report_fatal_error(
"internal error: scalar character not in CharBox");
- outputFuncArgs.push_back(builder.createConvert(
+ outputFuncArgs.push_back(builder.createConvertWithVolatileCast(
loc, outputFunc.getFunctionType().getInput(1), fir::getBase(exv)));
- outputFuncArgs.push_back(builder.createConvert(
+ outputFuncArgs.push_back(builder.createConvertWithVolatileCast(
loc, outputFunc.getFunctionType().getInput(2), fir::getLen(exv)));
} else {
fir::ExtendedValue itemBox = converter.genExprValue(loc, expr, stmtCtx);
@@ -833,7 +834,11 @@ createIoRuntimeCallForItem(Fortran::lower::AbstractConverter &converter,
} else {
mlir::Value itemAddr = fir::getBase(item);
mlir::Type itemTy = fir::unwrapPassByRefType(itemAddr.getType());
- inputFuncArgs.push_back(builder.createConvert(loc, argType, itemAddr));
+
+ // Handle conversion between volatile and non-volatile reference types
+ // Need to explicitly cast when volatility qualification differs
+ inputFuncArgs.push_back(
+ builder.createConvertWithVolatileCast(loc, argType, itemAddr));
fir::factory::CharacterExprHelper charHelper{builder, loc};
if (charHelper.isCharacterScalar(itemTy)) {
mlir::Value len = fir::getLen(item);
diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index 7fc30ca125a87..96d26ec40de64 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -577,6 +577,23 @@ mlir::Value fir::FirOpBuilder::convertWithSemantics(
return createConvert(loc, toTy, val);
}
+mlir::Value fir::FirOpBuilder::createVolatileCast(mlir::Location loc,
+ bool isVolatile,
+ mlir::Value val) {
+ mlir::Type volatileAdjustedType =
+ fir::updateTypeWithVolatility(val.getType(), isVolatile);
+ if (volatileAdjustedType == val.getType())
+ return val;
+ return create<fir::VolatileCastOp>(loc, volatileAdjustedType, val);
+}
+
+mlir::Value fir::FirOpBuilder::createConvertWithVolatileCast(mlir::Location loc,
+ mlir::Type toTy,
+ mlir::Value val) {
+ val = createVolatileCast(loc, fir::isa_volatile_type(toTy), val);
+ return createConvert(loc, toTy, val);
+}
+
mlir::Value fir::factory::createConvert(mlir::OpBuilder &builder,
mlir::Location loc, mlir::Type toTy,
mlir::Value val) {
@@ -598,8 +615,9 @@ mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc,
void fir::FirOpBuilder::createStoreWithConvert(mlir::Location loc,
mlir::Value val,
mlir::Value addr) {
- mlir::Value cast =
- createConvert(loc, fir::unwrapRefType(addr.getType()), val);
+ mlir::Type unwrapedRefType = fir::unwrapRefType(addr.getType());
+ val = createVolatileCast(loc, fir::isa_volatile_type(unwrapedRefType), val);
+ mlir::Value cast = createConvert(loc, unwrapedRefType, val);
create<fir::StoreOp>(loc, cast, addr);
}
@@ -739,17 +757,18 @@ mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc,
<< itemAddr.getType();
llvm_unreachable("not a memory reference type");
}
+ const bool isVolatile = fir::isa_volatile_type(itemAddr.getType());
mlir::Type boxTy;
mlir::Value tdesc;
// Avoid to wrap a box/class with box/class.
if (mlir::isa<fir::BaseBoxType>(elementType)) {
boxTy = elementType;
} else {
- boxTy = fir::BoxType::get(elementType);
+ boxTy = fir::BoxType::get(elementType, isVolatile);
if (isPolymorphic) {
elementType = fir::updateTypeForUnlimitedPolymorphic(elementType);
if (isAssumedType)
- boxTy = fir::BoxType::get(elementType);
+ boxTy = fir::BoxType::get(elementType, isVolatile);
else
boxTy = fir::ClassType::get(elementType);
}
diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
index 06a3e177da1d0..d019e3972f5e1 100644
--- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -801,7 +801,8 @@ mlir::Type hlfir::getVariableElementType(hlfir::Entity variable) {
} else if (fir::isRecordWithTypeParameters(eleTy)) {
return fir::BoxType::get(eleTy);
}
- return fir::ReferenceType::get(eleTy);
+ const bool isVolatile = fir::isa_volatile_type(variable.getType());
+ return fir::ReferenceType::get(eleTy, isVolatile);
}
mlir::Type hlfir::getEntityElementType(hlfir::Entity entity) {
diff --git a/flang/lib/Optimizer/Builder/MutableBox.cpp b/flang/lib/Optimizer/Builder/MutableBox.cpp
index aeb737acbf567..dd104e4f7d56e 100644
--- a/flang/lib/Optimizer/Builder/MutableBox.cpp
+++ b/flang/lib/Optimizer/Builder/MutableBox.cpp
@@ -28,9 +28,10 @@ createNewFirBox(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::MutableBoxValue &box, mlir::Value addr,
mlir::ValueRange lbounds, mlir::ValueRange extents,
mlir::ValueRange lengths, mlir::Value tdesc = {}) {
- if (mlir::isa<fir::BaseBoxType>(addr.getType()))
+ if (mlir::isa<fir::BaseBoxType>(addr.getType())) {
// The entity is already boxed.
return builder.createConvert(loc, box.getBoxTy(), addr);
+ }
mlir::Value shape;
if (!extents.empty()) {
@@ -76,7 +77,9 @@ createNewFirBox(fir::FirOpBuilder &builder, mlir::Location loc,
cleanedLengths = lengths;
}
mlir::Value emptySlice;
- return builder.create<fir::EmboxOp>(loc, box.getBoxTy(), cleanedAddr, shape,
+ auto boxType = fir::updateTypeWithVolatility(
+ box.getBoxTy(), fir::isa_volatile_type(cleanedAddr.getType()));
+ return builder.create<fir::EmboxOp>(loc, boxType, cleanedAddr, shape,
emptySlice, cleanedLengths, tdesc);
}
@@ -281,6 +284,9 @@ class MutablePropertyWriter {
unsigned allocator = kDefaultAllocator) {
mlir::Value irBox = createNewFirBox(builder, loc, box, addr, lbounds,
extents, lengths, tdesc);
+ const bool valueTypeIsVolatile =
+ fir::isa_volatile_type(fir::unwrapRefType(box.getAddr().getType()));
+ irBox = builder.createVolatileCast(loc, valueTypeIsVolatile, irBox);
builder.create<fir::StoreOp>(loc, irBox, box.getAddr());
}
@@ -346,7 +352,8 @@ mlir::Value fir::factory::createUnallocatedBox(
baseBoxType = baseBoxType.getBoxTypeWithNewShape(/*rank=*/0);
auto baseAddrType = baseBoxType.getEleTy();
if (!fir::isa_ref_type(baseAddrType))
- baseAddrType = builder.getRefType(baseAddrType);
+ baseAddrType =
+ builder.getRefType(baseAddrType, fir::isa_volatile_type(baseBoxType));
auto type = fir::unwrapRefType(baseAddrType);
auto eleTy = fir::unwrapSequenceType(type);
if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy))
@@ -516,7 +523,7 @@ void fir::factory::associateMutableBox(fir::FirOpBuilder &builder,
source.match(
[&](const fir::PolymorphicValue &p) {
mlir::Value sourceBox;
- if (auto polyBox = source.getBoxOf<fir::PolymorphicValue>())
+ if (auto *polyBox = source.getBoxOf<fir::PolymorphicValue>())
sourceBox = polyBox->getSourceBox();
writer.updateMutableBox(p.getAddr(), /*lbounds=*/std::nullopt,
/*extents=*/std::nullopt,
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index b54b497ee4ba1..bd0eb599c3e38 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -689,6 +689,20 @@ struct CmpcOpConversion : public fir::FIROpConversion<fir::CmpcOp> {
}
};
+/// fir.volatile_cast is only useful at the fir level. Once we lower to LLVM,
+/// volatility is described by setting volatile attributes on the LLVM ops.
+struct VolatileCastOpConversion
+ : public fir::FIROpConversion<fir::VolatileCastOp> {
+ using FIROpConversion::FIROpConversion;
+
+ llvm::LogicalResult
+ matchAndRewrite(fir::VolatileCastOp volatileCast, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ rewriter.replaceOp(volatileCast, adaptor.getOperands()[0]);
+ return mlir::success();
+ }
+};
+
/// convert value of from-type to value of to-type
struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
using FIROpConversion::FIROpConversion;
@@ -3224,6 +3238,7 @@ struct LoadOpConversion : public fir::FIROpConversion<fir::LoadOp> {
mlir::ConversionPatternRewriter &rewriter) const override {
mlir::Type llvmLoadTy = convertObjectType(load.getType());
+ const bool isVolatile = fir::isa_volatile_type(load.getMemref().getType());
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(load.getType())) {
// fir.box is a special case because it is considered an ssa value in
// fir, but it is lowered as a pointer to a descriptor. So
@@ -3253,7 +3268,7 @@ struct LoadOpConversion : public fir::FIROpConversion<fir::LoadOp> {
mlir::Value boxSize =
computeBoxSize(loc, boxTypePair, inputBoxStorage, rewriter);
auto memcpy = rewriter.create<mlir::LLVM::MemcpyOp>(
- loc, newBoxStorage, inputBoxStorage, boxSize, /*isVolatile=*/false);
+ loc, newBoxStorage, inputBoxStorage, boxSize, isVolatile);
if (std::optional<mlir::ArrayAttr> optionalTag = load.getTbaa())
memcpy.setTBAATags(*optionalTag);
@@ -3261,8 +3276,10 @@ struct LoadOpConversion : public fir::FIROpConversion<fir::LoadOp> {
attachTBAATag(memcpy, boxTy, boxTy, nullptr);
rewriter.replaceOp(load, newBoxStorage);
} else {
- auto loadOp = rewriter.create<mlir::LLVM::LoadOp>(
+ mlir::LLVM::LoadOp loadOp = rewriter.create<mlir::LLVM::LoadOp>(
load.getLoc(), llvmLoadTy, adaptor.getOperands(), load->getAttrs());
+ if (isVolatile)
+ loadOp.setVolatile_Attr(rewriter.getUnitAttr());
if (std::optional<mlir::ArrayAttr> optionalTag = load.getTbaa())
loadOp.setTBAATags(*optionalTag);
else
@@ -3540,6 +3557,7 @@ struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> {
mlir::Value llvmValue = adaptor.getValue();
mlir::Value llvmMemref = adaptor.getMemref();
mlir::LLVM::AliasAnalysisOpInterface newOp;
+ const bool isVolatile = fir::isa_volatile_type(store.getMemref().getType());
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(storeTy)) {
mlir::Type llvmBoxTy = lowerTy().convertBoxTypeAsStruct(boxTy);
// Always use memcpy because LLVM is not as effective at optimizing
@@ -3547,10 +3565,11 @@ struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> {
TypePair boxTypePair{boxTy, llvmBoxTy};
mlir::Value boxSize =
computeBoxSize(loc, boxTypePair, llvmValue, rewriter);
- newOp = rewriter.create<mlir::LLVM::MemcpyOp>(
- loc, llvmMemref, llvmValue, boxSize, /*isVolatile=*/false);
+ newOp = rewriter.create<mlir::LLVM::MemcpyOp>(loc, llvmMemref, llvmValue,
+ boxSize, isVolatile);
} else {
- newOp = rewriter.create<mlir::LLVM::StoreOp>(loc, llvmValue, llvmMemref);
+ newOp = rewriter.create<mlir::LLVM::StoreOp>(loc, llvmValue, llvmMemref,
+ /*alignment=*/0, isVolatile);
}
if (std::optional<mlir::ArrayAttr> optionalTag = store.getTbaa())
newOp.setTBAATags(*optionalTag);
@@ -4193,21 +4212,22 @@ void fir::populateFIRToLLVMConversionPatterns(
BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
- CmpcOpConversion, ConvertOpConversion, CoordinateOpConversion,
- CopyOpConversion, DTEntryOpConversion, DeclareOpConversion,
- DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
- EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
- FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion,
- GlobalOpConversion, InsertOnRangeOpConversion, IsPresentOpConversion,
- LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
- NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
- SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
- ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
- SliceOpConversion, StoreOpConversion, StringLitOpConversion,
- SubcOpConversion, TypeDescOpConversion, TypeInfoOpConversion,
- UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion,
- UnreachableOpConversion, XArrayCoorOpConversion, XEmboxOpConversion,
- XReboxOpConversion, ZeroOpConversion>(converter, options);
+ CmpcOpConversion, VolatileCastOpConversion, ConvertOpConversion,
+ CoordinateOpConversion, CopyOpConversion, DTEntryOpConversion,
+ DeclareOpConversion, DivcOpConversion, EmboxOpConversion,
+ EmboxCharOpConversion, EmboxProcOpConversion, ExtractValueOpConversion,
+ FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion,
+ GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
+ IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
+ MulcOpConversion, NegcOpConversion, NoReassocOpConversion,
+ SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
+ SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
+ ShiftOpConversion, SliceOpConversion, StoreOpConversion,
+ StringLitOpConversion, SubcOpConversion, TypeDescOpConversion,
+ TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
+ UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
+ XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter,
+ options);
// Patterns that are populated without a type converter do not trigger
// target materializations for the operands of the root op.
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 2d8017d0318d2..6f2cc7bc3352a 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
@@ -29,6 +30,7 @@
#include "mlir/IR/Matchers.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/TypeRange.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TypeSwitch.h"
@@ -853,6 +855,16 @@ std::vector<mlir::Value> fir::ArrayLoadOp::getExtents() {
return {};
}
+void fir::ArrayLoadOp::getEffects(
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ effects.emplace_back(mlir::MemoryEffects::Read::get(),
+ &getOperation()->getOpOperand(0),
+ mlir::SideEffects::DefaultResource::get());
+ addVolatileMemoryEffects({getMemref().getType()}, effects);
+}
+
llvm::LogicalResult fir::ArrayLoadOp::verify() {
auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);
@@ -935,6 +947,16 @@ llvm::LogicalResult fir::ArrayMergeStoreOp::verify() {
return mlir::success();
}
+void fir::ArrayMergeStoreOp::getEffects(
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ effects.emplace_back(mlir::MemoryEffects::Write::get(),
+ &getOperation()->getOpOperand(0),
+ mlir::SideEffects::DefaultResource::get());
+ addVolatileMemoryEffects({getMemref().getType()}, effects);
+}
+
//===----------------------------------------------------------------------===//
// ArrayFetchOp
//===----------------------------------------------------------------------===//
@@ -1322,6 +1344,53 @@ mlir::ParseResult fir::CmpcOp::parse(mlir::OpAsmParser &parser,
return parseCmpOp<fir::CmpcOp>(parser, result);
}
+//===----------------------------------------------------------------------===//
+// VolatileCastOp
+//===----------------------------------------------------------------------===//
+
+static bool typesMatchExceptForVolatility(mlir::Type fromType,
+ mlir::Type toType) {
+ // If we can change only the volatility and get identical types, then we
+ // match.
+ if (fir::updateTypeWithVolatility(fromType, fir::isa_volatile_type(toType)) ==
+ toType)
+ return true;
+
+ // Otherwise, recurse on the element types if the base classes are the same.
+ const bool match =
+ llvm::TypeSwitch<mlir::Type, bool>(fromType)
+ .Case<fir::BoxType, fir::ReferenceType, fir::ClassType>(
+ [&](auto type) {
+ using TYPE = decltype(type);
+ // If we are not the same base class, then we don't match.
+ auto castedToType = mlir::dyn_cast<TYPE>(toType);
+ if (!castedToType)
+ return false;
+ // If we are the same base class, we match if the element types
+ // match.
+ return typesMatchExceptForVolatility(type.getEleTy(),
+ castedToType.getEleTy());
+ })
+ .Default([](mlir::Type) { return false; });
+
+ return match;
+}
+
+llvm::LogicalResult fir::VolatileCastOp::verify() {
+ mlir::Type fromType = getValue().getType();
+ mlir::Type toType = getType();
+ if (!typesMatchExceptForVolatility(fromType, toType))
+ return emitOpError("types must be identical except for volatility ")
+ << fromType << " / " << toType;
+ return mlir::success();
+}
+
+mlir::OpFoldResult fir::VolatileCastOp::fold(FoldAdaptor adaptor) {
+ if (getValue().getType() == getType())
+ return getValue();
+ return {};
+}
+
//===----------------------------------------------------------------------===//
// ConvertOp
//===----------------------------------------------------------------------===//
@@ -1461,7 +1530,13 @@ bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
}
llvm::LogicalResult fir::ConvertOp::verify() {
- if (canBeConverted(getValue().getType(), getType()))
+ mlir::Type inType = getValue().getType();
+ mlir::Type outType = getType();
+ if (fir::isa_volatile_type(inType) != fir::isa_volatile_type(outType))
+ return emitOpError("cannot convert between volatile and non-volatile "
+ "types, use fir.volatile_cast instead ")
+ << inType << " / " << outType;
+ if (canBeConverted(inType, outType))
return mlir::success();
return emitOpError("invalid type conversion")
<< getValue().getType() << " / " << getType();
@@ -2599,6 +2674,16 @@ void fir::LoadOp::print(mlir::OpAsmPrinter &p) {
p << " : " << getMemref().getType();
}
+void fir::LoadOp::getEffects(
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ effects.emplace_back(mlir::MemoryEffects::Read::get(),
+ &getOperation()->getOpOperand(0),
+ mlir::SideEffects::DefaultResource::get());
+ addVolatileMemoryEffects({getMemref().getType()}, effects);
+}
+
//===----------------------------------------------------------------------===//
// DoLoopOp
//===----------------------------------------------------------------------===//
@@ -3951,6 +4036,16 @@ void fir::StoreOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
build(builder, result, value, memref, {});
}
+void fir::StoreOp::getEffects(
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ effects.emplace_back(mlir::MemoryEffects::Write::get(),
+ &getOperation()->getOpOperand(1),
+ mlir::SideEffects::DefaultResource::get());
+ addVolatileMemoryEffects({getMemref().getType()}, effects);
+}
+
//===----------------------------------------------------------------------===//
// CopyOp
//===----------------------------------------------------------------------===//
@@ -3971,6 +4066,20 @@ llvm::LogicalResult fir::CopyOp::verify() {
return mlir::success();
}
+void fir::CopyOp::getEffects(
+ llvm::SmallVectorImpl<
+ mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+ &effects) {
+ effects.emplace_back(mlir::MemoryEffects::Read::get(),
+ &getOperation()->getOpOperand(0),
+ mlir::SideEffects::DefaultResource::get());
+ effects.emplace_back(mlir::MemoryEffects::Write::get(),
+ &getOperation()->getOpOperand(1),
+ mlir::SideEffects::DefaultResource::get());
+ addVolatileMemoryEffects({getDestination().getType(), getSource().getType()},
+ effects);
+}
+
//===----------------------------------------------------------------------===//
// StringLitOp
//===----------------------------------------------------------------------===//
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 1df0ea93b759f..c336377115984 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -20,6 +20,7 @@
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/DialectImplementation.h"
+#include "mlir/Support/LLVM.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TypeSwitch.h"
@@ -32,21 +33,6 @@ using namespace fir;
namespace {
-static llvm::StringRef getVolatileKeyword() { return "volatile"; }
-
-static mlir::ParseResult parseOptionalCommaAndKeyword(mlir::AsmParser &parser,
- mlir::StringRef keyword,
- bool &parsedKeyword) {
- if (!parser.parseOptionalComma()) {
- if (parser.parseKeyword(keyword))
- return mlir::failure();
- parsedKeyword = true;
- return mlir::success();
- }
- parsedKeyword = false;
- return mlir::success();
-}
-
template <typename TYPE>
TYPE parseIntSingleton(mlir::AsmParser &parser) {
int kind = 0;
@@ -91,6 +77,21 @@ bool verifySameLists(llvm::ArrayRef<RecordType::TypePair> a1,
return a1 == a2;
}
+static llvm::StringRef getVolatileKeyword() { return "volatile"; }
+
+static mlir::ParseResult parseOptionalCommaAndKeyword(mlir::AsmParser &parser,
+ mlir::StringRef keyword,
+ bool &parsedKeyword) {
+ if (!parser.parseOptionalComma()) {
+ if (parser.parseKeyword(keyword))
+ return mlir::failure();
+ parsedKeyword = true;
+ return mlir::success();
+ }
+ parsedKeyword = false;
+ return mlir::success();
+}
+
RecordType verifyDerived(mlir::AsmParser &parser, RecordType derivedTy,
llvm::ArrayRef<RecordType::TypePair> lenPList,
llvm::ArrayRef<RecordType::TypePair> typeList) {
@@ -677,18 +678,24 @@ mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType,
.Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type {
return fir::SequenceType::get(seqTy.getShape(), newElementType);
})
- .Case<fir::PointerType, fir::HeapType, fir::ReferenceType,
- fir::ClassType>([&](auto t) -> mlir::Type {
- using FIRT = decltype(t);
- return FIRT::get(
- changeElementType(t.getEleTy(), newElementType, turnBoxIntoClass));
+ .Case<fir::ReferenceType>([&](fir::ReferenceType refTy) -> mlir::Type {
+ auto newEleTy = changeElementType(refTy.getEleTy(), newElementType,
+ turnBoxIntoClass);
+ return fir::ReferenceType::get(newEleTy, refTy.isVolatile());
})
+ .Case<fir::PointerType, fir::HeapType, fir::ClassType>(
+ [&](auto t) -> mlir::Type {
+ using FIRT = decltype(t);
+ return FIRT::get(changeElementType(t.getEleTy(), newElementType,
+ turnBoxIntoClass));
+ })
.Case<fir::BoxType>([&](fir::BoxType t) -> mlir::Type {
mlir::Type newInnerType =
changeElementType(t.getEleTy(), newElementType, false);
+ // TODO: volatility on class types
if (turnBoxIntoClass)
return fir::ClassType::get(newInnerType);
- return fir::BoxType::get(newInnerType);
+ return fir::BoxType::get(newInnerType, t.isVolatile());
})
.Default([&](mlir::Type t) -> mlir::Type {
assert((fir::isa_trivial(t) || llvm::isa<fir::RecordType>(t) ||
@@ -1413,11 +1420,16 @@ changeTypeShape(mlir::Type type,
return fir::SequenceType::get(*newShape, seqTy.getEleTy());
return seqTy.getEleTy();
})
- .Case<fir::PointerType, fir::HeapType, fir::ReferenceType, fir::BoxType,
- fir::ClassType>([&](auto t) -> mlir::Type {
+ .Case<fir::ReferenceType, fir::BoxType>([&](auto t) -> mlir::Type {
using FIRT = decltype(t);
- return FIRT::get(changeTypeShape(t.getEleTy(), newShape));
+ return FIRT::get(changeTypeShape(t.getEleTy(), newShape),
+ t.isVolatile());
})
+ .Case<fir::PointerType, fir::HeapType, fir::ClassType>(
+ [&](auto t) -> mlir::Type {
+ using FIRT = decltype(t);
+ return FIRT::get(changeTypeShape(t.getEleTy(), newShape));
+ })
.Default([&](mlir::Type t) -> mlir::Type {
assert((fir::isa_trivial(t) || llvm::isa<fir::RecordType>(t) ||
llvm::isa<mlir::NoneType>(t) ||
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 8851a3a7187b9..fad4a90222504 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -61,6 +61,7 @@ getIntrinsicEffects(mlir::Operation *self,
// }
for (mlir::OpOperand &operand : self->getOpOperands()) {
mlir::Type opTy = operand.get().getType();
+ fir::addVolatileMemoryEffects({opTy}, effects);
if (fir::isa_ref_type(opTy) || fir::isa_box_type(opTy))
effects.emplace_back(mlir::MemoryEffects::Read::get(), &operand,
mlir::SideEffects::DefaultResource::get());
@@ -164,6 +165,8 @@ void hlfir::AssignOp::getEffects(
}
}
+ fir::addVolatileMemoryEffects({lhsType, rhsType}, effects);
+
if (getRealloc()) {
// Reallocation of the data cannot be precisely described by this API.
effects.emplace_back(mlir::MemoryEffects::Free::get(),
@@ -195,7 +198,7 @@ mlir::Type hlfir::DeclareOp::getHLFIRVariableType(mlir::Type inputType,
bool hasDynamicLengthParams = fir::characterWithDynamicLen(eleType) ||
fir::isRecordWithTypeParameters(eleType);
if (hasExplicitLowerBounds || hasDynamicExtents || hasDynamicLengthParams)
- return fir::BoxType::get(type);
+ return fir::BoxType::get(type, fir::isa_volatile_type(inputType));
return inputType;
}
@@ -214,6 +217,22 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
auto nameAttr = builder.getStringAttr(uniq_name);
mlir::Type inputType = memref.getType();
bool hasExplicitLbs = hasExplicitLowerBounds(shape);
+ if (auto refType = mlir::dyn_cast<fir::ReferenceType>(inputType);
+ fortran_attrs && refType &&
+ bitEnumContainsAny(fortran_attrs.getFlags(),
+ fir::FortranVariableFlagsEnum::fortran_volatile)) {
+ auto eleType = refType.getEleTy();
+ const bool isPointer = bitEnumContainsAny(
+ fortran_attrs.getFlags(), fir::FortranVariableFlagsEnum::pointer);
+ if (isPointer) {
+ // If an entity is a pointer, the entity it points to is volatile, as far
+ // as consumers of the pointer are concerned.
+ eleType = fir::updateTypeWithVolatility(eleType, true);
+ }
+ inputType = fir::ReferenceType::get(eleType, /*isVolatile=*/true);
+ memref =
+ builder.create<fir::VolatileCastOp>(memref.getLoc(), inputType, memref);
+ }
mlir::Type hlfirVariableType =
getHLFIRVariableType(inputType, hasExplicitLbs);
build(builder, result, {hlfirVariableType, inputType}, memref, shape,
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 496a5560ac615..c5bd8b30d5214 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -418,7 +418,9 @@ class DesignateOpConversion
firstElementIndices.push_back(indices[i]);
i = i + (isTriplet ? 3 : 1);
}
- mlir::Type arrayCoorType = fir::ReferenceType::get(baseEleTy);
+ mlir::Type originalDesignateType = designate.getResult().getType();
+ const bool isVolatile = fir::isa_volatile_type(originalDesignateType);
+ mlir::Type arrayCoorType = fir::ReferenceType::get(baseEleTy, isVolatile);
base = builder.create<fir::ArrayCoorOp>(
loc, arrayCoorType, base, shape,
/*slice=*/mlir::Value{}, firstElementIndices, firBaseTypeParameters);
@@ -441,6 +443,7 @@ class DesignateOpConversion
TODO(loc, "hlfir::designate load of pointer or allocatable");
mlir::Type designateResultType = designate.getResult().getType();
+ const bool isVolatile = fir::isa_volatile_type(designateResultType);
llvm::SmallVector<mlir::Value> firBaseTypeParameters;
auto [base, shape] = hlfir::genVariableFirBaseShapeAndParams(
loc, builder, baseEntity, firBaseTypeParameters);
@@ -464,7 +467,7 @@ class DesignateOpConversion
mlir::Type componentType =
mlir::cast<fir::RecordType>(baseEleTy).getType(
designate.getComponent().value());
- mlir::Type coorTy = fir::ReferenceType::get(componentType);
+ mlir::Type coorTy = fir::ReferenceType::get(componentType, isVolatile);
base = builder.create<fir::CoordinateOp>(loc, coorTy, base, fieldIndex);
if (mlir::isa<fir::BaseBoxType>(componentType)) {
auto variableInterface = mlir::cast<fir::FortranVariableOpInterface>(
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp
index 96a3622f4afee..61be2c958a405 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp
@@ -1126,7 +1126,8 @@ class ReductionMaskConversion : public mlir::OpRewritePattern<Op> {
builder.create<fir::StoreOp>(loc, flagSet, flagRef);
mlir::Type resultElemTy =
hlfir::getFortranElementType(resultArr.getType());
- mlir::Type returnRefTy = builder.getRefType(resultElemTy);
+ mlir::Type returnRefTy = builder.getRefType(
+ resultElemTy, fir::isa_volatile_type(flagRef.getType()));
mlir::IndexType idxTy = builder.getIndexType();
for (unsigned int i = 0; i < rank; ++i) {
@@ -1153,7 +1154,8 @@ class ReductionMaskConversion : public mlir::OpRewritePattern<Op> {
auto getAddrFn = [](fir::FirOpBuilder builder, mlir::Location loc,
const mlir::Type &resultElemType, mlir::Value resultArr,
mlir::Value index) {
- mlir::Type resultRefTy = builder.getRefType(resultElemType);
+ mlir::Type resultRefTy = builder.getRefType(
+ resultElemType, fir::isa_volatile_type(resultArr.getType()));
mlir::Value oneIdx =
builder.createIntegerConstant(loc, builder.getIndexType(), 1);
index = builder.create<mlir::arith::AddIOp>(loc, index, oneIdx);
@@ -1162,8 +1164,9 @@ class ReductionMaskConversion : public mlir::OpRewritePattern<Op> {
};
// Initialize the result
+ const bool isVolatile = fir::isa_volatile_type(resultArr.getType());
mlir::Type resultElemTy = hlfir::getFortranElementType(resultArr.getType());
- mlir::Type resultRefTy = builder.getRefType(resultElemTy);
+ mlir::Type resultRefTy = builder.getRefType(resultElemTy, isVolatile);
mlir::Value returnValue =
builder.createIntegerConstant(loc, resultElemTy, 0);
for (unsigned int i = 0; i < rank; ++i) {
diff --git a/flang/test/Fir/volatile.fir b/flang/test/Fir/volatile.fir
new file mode 100644
index 0000000000000..6b3d8709abdeb
--- /dev/null
+++ b/flang/test/Fir/volatile.fir
@@ -0,0 +1,18 @@
+// RUN: fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s -o - | FileCheck %s
+// CHECK: llvm.store volatile %{{.+}}, %{{.+}} : i32, !llvm.ptr
+// CHECK: %{{.+}} = llvm.load volatile %{{.+}} : !llvm.ptr -> i32
+func.func @foo() {
+ %true = arith.constant true
+ %false = arith.constant false
+ %0 = fir.alloca !fir.logical<4> {bindc_name = "a", uniq_name = "_QFEa"}
+ %1 = fir.volatile_cast %0 : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>, volatile>
+ %2 = fir.alloca !fir.logical<4> {bindc_name = "b", uniq_name = "_QFEb"}
+ %3 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+ %4 = fir.convert %false : (i1) -> !fir.logical<4>
+ fir.store %4 to %1 : !fir.ref<!fir.logical<4>, volatile>
+ %5 = fir.load %1 : !fir.ref<!fir.logical<4>, volatile>
+ fir.store %5 to %2 : !fir.ref<!fir.logical<4>>
+ %6 = fir.convert %true : (i1) -> !fir.logical<4>
+ fir.store %6 to %1 : !fir.ref<!fir.logical<4>, volatile>
+ return
+}
diff --git a/flang/test/HLFIR/volatile.fir b/flang/test/HLFIR/volatile.fir
new file mode 100644
index 0000000000000..3404ab2e1f9ea
--- /dev/null
+++ b/flang/test/HLFIR/volatile.fir
@@ -0,0 +1,21 @@
+// RUN: fir-opt --convert-hlfir-to-fir %s -o - | FileCheck %s
+func.func @foo() {
+ %true = arith.constant true
+ %false = arith.constant false
+ %0 = fir.alloca !fir.logical<4> {bindc_name = "a", uniq_name = "_QFEa"}
+ %1 = fir.volatile_cast %0 : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>, volatile>
+ %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEa"} : (!fir.ref<!fir.logical<4>, volatile>) -> (!fir.ref<!fir.logical<4>, volatile>, !fir.ref<!fir.logical<4>, volatile>)
+ %3 = fir.alloca !fir.logical<4> {bindc_name = "b", uniq_name = "_QFEb"}
+ %4:2 = hlfir.declare %3 {uniq_name = "_QFEb"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+ %5 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+ %6:2 = hlfir.declare %5 {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %7 = fir.convert %false : (i1) -> !fir.logical<4>
+ hlfir.assign %7 to %2#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
+ %8 = fir.load %2#0 : !fir.ref<!fir.logical<4>, volatile>
+ hlfir.assign %8 to %4#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+ %9 = fir.convert %true : (i1) -> !fir.logical<4>
+ hlfir.assign %9 to %2#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
+ return
+}
+// CHECK: fir.store %{{.+}} to %{{.+}} : !fir.ref<!fir.logical<4>, volatile>
+// CHECK: %{{.+}} = fir.load %{{.+}} : !fir.ref<!fir.logical<4>, volatile>
diff --git a/flang/test/Lower/volatile1.f90 b/flang/test/Lower/volatile1.f90
new file mode 100644
index 0000000000000..8447704619db0
--- /dev/null
+++ b/flang/test/Lower/volatile1.f90
@@ -0,0 +1,93 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+program p
+ integer,volatile::i,arr(10)
+ call not_declared_volatile_in_this_scope(i)
+ call not_declared_volatile_in_this_scope(arr)
+ call declared_volatile_in_this_scope(arr,10)
+ print*,arr,i
+contains
+ elemental subroutine not_declared_volatile_in_this_scope(v)
+ integer,intent(inout)::v
+ v=1
+ end subroutine
+ subroutine declared_volatile_in_this_scope(v,n)
+ integer,intent(in)::n
+ integer,volatile,intent(inout)::v(n)
+ v=1
+ end subroutine
+end program
+
+
+! CHECK-LABEL: func.func @_QQmain() attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_1:.*]] = arith.constant 8 : i32
+! CHECK: %[[VAL_2:.*]] = arith.constant 6 : i32
+! CHECK: %[[VAL_3:.*]] = arith.constant 10 : i32
+! CHECK: %[[VAL_4:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_5:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_6]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_7]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+! CHECK: %[[VAL_11:.*]] = fir.volatile_cast %[[VAL_10]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {{.+}} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: %[[VAL_13:.*]] = fir.volatile_cast %[[VAL_12]]#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+! CHECK: fir.call @_QFPnot_declared_volatile_in_this_scope(%[[VAL_13]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<i32>) -> ()
+! CHECK: cf.br ^bb1(%[[VAL_4]], %[[VAL_5]] : index, index)
+! CHECK: ^bb1(%[[VAL_14:.*]]: index, %[[VAL_15:.*]]: index):
+! CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_0]] : index
+! CHECK: cf.cond_br %[[VAL_16]], ^bb2, ^bb3
+! CHECK: ^bb2:
+! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_14]]) : (!fir.ref<!fir.array<10xi32>, volatile>, index) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_18:.*]] = fir.volatile_cast %[[VAL_17]] : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+! CHECK: fir.call @_QFPnot_declared_volatile_in_this_scope(%[[VAL_18]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<i32>) -> ()
+! CHECK: %[[VAL_19:.*]] = arith.addi %[[VAL_14]], %[[VAL_4]] overflow<nsw> : index
+! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_15]], %[[VAL_4]] : index
+! CHECK: cf.br ^bb1(%[[VAL_19]], %[[VAL_20]] : index, index)
+! CHECK: ^bb3:
+! CHECK: %[[VAL_21:.*]] = fir.volatile_cast %[[VAL_9]]#0 : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<?xi32>>
+! CHECK: %[[VAL_23:.*]]:3 = hlfir.associate %[[VAL_3]] {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
+! CHECK: fir.call @_QFPdeclared_volatile_in_this_scope(%[[VAL_22]], %[[VAL_23]]#0) fastmath<contract> : (!fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) -> ()
+! CHECK: hlfir.end_associate %[[VAL_23]]#1, %[[VAL_23]]#2 : !fir.ref<i32>, i1
+! CHECK: %[[VAL_24:.*]] = fir.address_of
+! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! CHECK: %[[VAL_26:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[VAL_2]], %[[VAL_25]], %[[VAL_1]]) fastmath<contract> {{.+}} : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+! CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_9]]#0(%[[VAL_7]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_28:.*]] = fir.volatile_cast %[[VAL_27]] : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<none>
+! CHECK: %[[VAL_30:.*]] = fir.call @_FortranAioOutputDescriptor(%[[VAL_26]], %[[VAL_29]]) fastmath<contract> {llvm.nocallback, llvm.nosync} : (!fir.ref<i8>, !fir.box<none>) -> i1
+! CHECK: %[[VAL_31:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref<i32, volatile>
+! CHECK: %[[VAL_32:.*]] = fir.call @_FortranAioOutputInteger32(%[[VAL_26]], %[[VAL_31]]) fastmath<contract> {{.+}} : (!fir.ref<i8>, i32) -> i1
+! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAioEndIoStatement(%[[VAL_26]]) fastmath<contract> {{.+}} : (!fir.ref<i8>) -> i32
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPnot_declared_volatile_in_this_scope(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<i32> {fir.bindc_name = "v"}) attributes {{.+}} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_2]] {{.+}} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_3]]#0 : i32, !fir.ref<i32>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPdeclared_volatile_in_this_scope(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "v"},
+! CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<i32> {fir.bindc_name = "n"}) attributes {{.+}} {
+! CHECK: %[[VAL_2:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %[[VAL_4]] {{.+}} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
+! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i32) -> index
+! CHECK: %[[VAL_8:.*]] = arith.cmpi sgt, %[[VAL_7]], %[[VAL_3]] : index
+! CHECK: %[[VAL_9:.*]] = arith.select %[[VAL_8]], %[[VAL_7]], %[[VAL_3]] : index
+! CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_9]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_11:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>, volatile>
+! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_10]]) dummy_scope %[[VAL_4]] {{.+}} : (!fir.ref<!fir.array<?xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>, volatile>, !fir.ref<!fir.array<?xi32>, volatile>)
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_12]]#0 : i32, !fir.box<!fir.array<?xi32>, volatile>
+! CHECK: return
+! CHECK: }
diff --git a/flang/test/Lower/volatile2.f90 b/flang/test/Lower/volatile2.f90
new file mode 100644
index 0000000000000..4b7f185f24c41
--- /dev/null
+++ b/flang/test/Lower/volatile2.f90
@@ -0,0 +1,63 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+program p
+ print*,a(),b(),c()
+contains
+ function a()
+ integer,volatile::a
+ a=1
+ end function
+ function b() result(r)
+ integer,volatile::r
+ r=2
+ end function
+ function c() result(r)
+ volatile::r
+ r=3
+ end function
+end program
+
+
+! CHECK-LABEL: func.func @_QQmain() attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 4 : i32
+! CHECK: %[[VAL_1:.*]] = arith.constant 6 : i32
+! CHECK: %[[VAL_2:.*]] = fir.address_of
+! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.char<1,{{.+}}>>) -> !fir.ref<i8>
+! CHECK: %[[VAL_4:.*]] = fir.call @_QFPa() fastmath<contract> : () -> i32
+! CHECK: %[[VAL_5:.*]] = fir.call @_QFPb() fastmath<contract> : () -> i32
+! CHECK: %[[VAL_6:.*]] = fir.call @_QFPc() fastmath<contract> : () -> f32
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPa() -> i32 attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFFaEa"}
+! CHECK: %[[VAL_2:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {{.+}} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : i32, !fir.ref<i32, volatile>
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_3]]#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
+! CHECK: return %[[VAL_5]] : i32
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPb() -> i32 attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 2 : i32
+! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "r", uniq_name = "_QFFbEr"}
+! CHECK: %[[VAL_2:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {{.+}} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : i32, !fir.ref<i32, volatile>
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_3]]#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
+! CHECK: return %[[VAL_5]] : i32
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPc() -> f32 attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 3.000000e+00 : f32
+! CHECK: %[[VAL_1:.*]] = fir.alloca f32 {bindc_name = "r", uniq_name = "_QFFcEr"}
+! CHECK: %[[VAL_2:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.ref<f32>) -> !fir.ref<f32, volatile>
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {{.+}} : (!fir.ref<f32, volatile>) -> (!fir.ref<f32, volatile>, !fir.ref<f32, volatile>)
+! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : f32, !fir.ref<f32, volatile>
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_3]]#0 : (!fir.ref<f32, volatile>) -> !fir.ref<f32>
+! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<f32>
+! CHECK: return %[[VAL_5]] : f32
+! CHECK: }
diff --git a/flang/test/Lower/volatile3.f90 b/flang/test/Lower/volatile3.f90
new file mode 100644
index 0000000000000..174e1cc1bf4be
--- /dev/null
+++ b/flang/test/Lower/volatile3.f90
@@ -0,0 +1,112 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+program p
+ integer,volatile::i,arr(10)
+ integer,volatile,target::tgt(10)
+ integer,volatile,pointer,dimension(:)::ptr
+ ptr => tgt
+ i=0
+ arr=1
+ call d(arr)
+ call e(arr)
+ call f(arr)
+ call g(ptr)
+contains
+ subroutine d(arr)
+ integer,volatile::arr(10)
+ end subroutine
+ subroutine e(arr)
+ integer,volatile,dimension(:)::arr
+ end subroutine
+ subroutine f(arr)
+ integer,volatile,dimension(10)::arr
+ end subroutine
+ subroutine g(arr)
+ integer,volatile,dimension(:),pointer::arr
+ end subroutine
+end program
+
+! CHECK-LABEL: func.func @_QQmain() attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
+! CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_3:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_5:.*]] = fir.volatile_cast %[[VAL_3]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_4]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_7]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {{.+}} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_11:.*]] = fir.volatile_cast %[[VAL_10]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {{.+}} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+! CHECK: %[[VAL_13:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_14:.*]] = fir.volatile_cast %[[VAL_13]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]](%[[VAL_4]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_16:.*]] = fir.embox %[[VAL_15]]#0(%[[VAL_4]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_16]] to %[[VAL_12]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_9]]#0 : i32, !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 : i32, !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_17:.*]] = fir.volatile_cast %[[VAL_6]]#0 : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+! CHECK: fir.call @_QFPd(%[[VAL_17]]) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+! CHECK: %[[VAL_18:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_4]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
+! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<?xi32>>
+! CHECK: fir.call @_QFPe(%[[VAL_19]]) fastmath<contract> : (!fir.box<!fir.array<?xi32>>) -> ()
+! CHECK: fir.call @_QFPf(%[[VAL_17]]) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_12]]#0 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>
+! CHECK: fir.call @_QFPg(%[[VAL_20]]) fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> ()
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPd(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "arr"}) attributes {{.+}} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_3]]) dummy_scope %[[VAL_2]] {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPe(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arr"}) attributes {{.+}} {
+! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {{.+}} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPf(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "arr"}) attributes {{.+}} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_3]]) dummy_scope %[[VAL_2]] {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPg(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile> {fir.bindc_name = "arr"}) attributes {{.+}} {
+! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_2:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %[[VAL_1]] {{.+}} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: fir.global internal @_QFEarr : !fir.array<10xi32> {
+! CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.array<10xi32>
+! CHECK: fir.has_value %[[VAL_0]] : !fir.array<10xi32>
+! CHECK: }
+
+! CHECK-LABEL: fir.global internal @_QFEptr : !fir.box<!fir.ptr<!fir.array<?xi32>>> {
+! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_1:.*]] = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_1]](%[[VAL_2]]) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! CHECK: fir.has_value %[[VAL_3]] : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! CHECK: }
+
+! CHECK-LABEL: fir.global internal @_QFEtgt target : !fir.array<10xi32> {
+! CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.array<10xi32>
+! CHECK: fir.has_value %[[VAL_0]] : !fir.array<10xi32>
+! CHECK: }
diff --git a/flang/test/Lower/volatile4.f90 b/flang/test/Lower/volatile4.f90
new file mode 100644
index 0000000000000..ac3abc24a5235
--- /dev/null
+++ b/flang/test/Lower/volatile4.f90
@@ -0,0 +1,91 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+program p
+ integer,volatile::i,arr(10)
+ integer,volatile,target::tgt(10)
+ integer,volatile,pointer,dimension(:)::ptr
+ ptr => tgt
+ i=0
+ arr=1
+ call host_assoc
+contains
+ subroutine host_assoc
+ ptr => tgt
+ i=0
+ arr=1
+ end subroutine
+end program
+
+! CHECK-LABEL: func.func @_QQmain() attributes {{.+}} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
+! CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_3:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_5:.*]] = fir.volatile_cast %[[VAL_3]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_4]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_7]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {{.+}} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_11:.*]] = fir.volatile_cast %[[VAL_10]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {{.+}} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+! CHECK: %[[VAL_13:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_14:.*]] = fir.volatile_cast %[[VAL_13]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]](%[[VAL_4]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_16:.*]] = fir.alloca tuple<!fir.ref<i32>>
+! CHECK: %[[VAL_17:.*]] = fir.coordinate_of %[[VAL_16]], %[[VAL_1]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK: %[[VAL_18:.*]] = fir.volatile_cast %[[VAL_9]]#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+! CHECK: fir.store %[[VAL_18]] to %[[VAL_17]] : !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_15]]#0(%[[VAL_4]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_19]] to %[[VAL_12]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_9]]#0 : i32, !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 : i32, !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: fir.call @_QFPhost_assoc(%[[VAL_16]]) fastmath<contract> : (!fir.ref<tuple<!fir.ref<i32>>>) -> ()
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPhost_assoc(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {{.+}} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 1 : i32
+! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
+! CHECK: %[[VAL_3:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_5:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_6]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_9:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_10:.*]] = fir.volatile_cast %[[VAL_9]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {{.+}} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+! CHECK: %[[VAL_12:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_13:.*]] = fir.volatile_cast %[[VAL_12]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_13]](%[[VAL_6]]) {{.+}} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_15:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_15]] : !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK: %[[VAL_17:.*]] = fir.volatile_cast %[[VAL_16]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {{.+}} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_14]]#0(%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_19]] to %[[VAL_11]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_18]]#0 : i32, !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_8]]#0 : i32, !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: fir.global internal @_QFEarr : !fir.array<10xi32> {
+! CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.array<10xi32>
+! CHECK: fir.has_value %[[VAL_0]] : !fir.array<10xi32>
+! CHECK: }
+
+! CHECK-LABEL: fir.global internal @_QFEptr : !fir.box<!fir.ptr<!fir.array<?xi32>>> {
+! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_1:.*]] = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_1]](%[[VAL_2]]) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! CHECK: fir.has_value %[[VAL_3]] : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! CHECK: }
+
+! CHECK-LABEL: fir.global internal @_QFEtgt target : !fir.array<10xi32> {
+! CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.array<10xi32>
+! CHECK: fir.has_value %[[VAL_0]] : !fir.array<10xi32>
+! CHECK: }
>From 2526bf2e44a058d59559090a846e53056d05c656 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Wed, 9 Apr 2025 16:07:09 -0700
Subject: [PATCH 2/4] comments
---
.../include/flang/Optimizer/Builder/FIRBuilder.h | 4 ++--
flang/include/flang/Optimizer/Dialect/FIROps.td | 6 ++++--
flang/lib/Optimizer/Dialect/FIROps.cpp | 1 -
flang/lib/Optimizer/Dialect/FIRType.cpp | 15 +++++++--------
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index a12283287a8b7..5309ea2c0fc09 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -402,9 +402,9 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
mlir::Value createConvertWithVolatileCast(mlir::Location loc, mlir::Type toTy,
mlir::Value val);
- /// Create a fir.volatile_cast op.
+ /// Cast \p value to have \p isVolatile volatility.
mlir::Value createVolatileCast(mlir::Location loc, bool isVolatile,
- mlir::Value val);
+ mlir::Value value);
/// Create a fir.store of \p val into \p addr. A lazy conversion
/// of \p val to the element type of \p addr is created if needed.
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index d8d2b0b8389de..0212b7e011983 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -286,7 +286,8 @@ def fir_FreeMemOp : fir_Op<"freemem", [MemoryEffects<[MemFree]>]> {
let assemblyFormat = "$heapref attr-dict `:` qualified(type($heapref))";
}
-def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
+def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface,
+ DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "load a value from a memory reference";
let description = [{
Load a value from a memory reference into an ssa-value (virtual register).
@@ -1374,7 +1375,8 @@ def fir_BoxTypeDescOp : fir_SimpleOneResultOp<"box_tdesc", [NoMemoryEffect]> {
// !- Merge the new and old values into the memory for "A"
// array_merge_store <updated A> to <A's address>
-def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
+def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments,
+ DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
let summary = "Load an array as a value.";
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 6f2cc7bc3352a..adc8938ccba05 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/Dialect/FIROps.h"
-#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index c336377115984..763088afd1b24 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -678,12 +678,12 @@ mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType,
.Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type {
return fir::SequenceType::get(seqTy.getShape(), newElementType);
})
- .Case<fir::ReferenceType>([&](fir::ReferenceType refTy) -> mlir::Type {
- auto newEleTy = changeElementType(refTy.getEleTy(), newElementType,
- turnBoxIntoClass);
- return fir::ReferenceType::get(newEleTy, refTy.isVolatile());
+ .Case<fir::ReferenceType, fir::ClassType>([&](auto t) -> mlir::Type {
+ using FIRT = decltype(t);
+ auto newEleTy = changeElementType(t.getEleTy(), newElementType, turnBoxIntoClass);
+ return FIRT::get(newEleTy, t.isVolatile());
})
- .Case<fir::PointerType, fir::HeapType, fir::ClassType>(
+ .Case<fir::PointerType, fir::HeapType>(
[&](auto t) -> mlir::Type {
using FIRT = decltype(t);
return FIRT::get(changeElementType(t.getEleTy(), newElementType,
@@ -692,7 +692,6 @@ mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType,
.Case<fir::BoxType>([&](fir::BoxType t) -> mlir::Type {
mlir::Type newInnerType =
changeElementType(t.getEleTy(), newElementType, false);
- // TODO: volatility on class types
if (turnBoxIntoClass)
return fir::ClassType::get(newInnerType);
return fir::BoxType::get(newInnerType, t.isVolatile());
@@ -1420,12 +1419,12 @@ changeTypeShape(mlir::Type type,
return fir::SequenceType::get(*newShape, seqTy.getEleTy());
return seqTy.getEleTy();
})
- .Case<fir::ReferenceType, fir::BoxType>([&](auto t) -> mlir::Type {
+ .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>([&](auto t) -> mlir::Type {
using FIRT = decltype(t);
return FIRT::get(changeTypeShape(t.getEleTy(), newShape),
t.isVolatile());
})
- .Case<fir::PointerType, fir::HeapType, fir::ClassType>(
+ .Case<fir::PointerType, fir::HeapType>(
[&](auto t) -> mlir::Type {
using FIRT = decltype(t);
return FIRT::get(changeTypeShape(t.getEleTy(), newShape));
>From a9b8676123403bc832ebb63062ad0130e56d8078 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Thu, 10 Apr 2025 19:14:09 -0700
Subject: [PATCH 3/4] Add tests, handle more memcpy cases
---
flang/lib/Lower/ConvertExpr.cpp | 7 +-
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 11 +-
flang/test/Fir/volatile2.fir | 54 ++++++++
flang/test/HLFIR/volatile.fir | 20 ++-
flang/test/HLFIR/volatile1.fir | 160 ++++++++++++++++++++++++
flang/test/HLFIR/volatile2.fir | 66 ++++++++++
flang/test/HLFIR/volatile3.fir | 150 ++++++++++++++++++++++
flang/test/HLFIR/volatile4.fir | 153 ++++++++++++++++++++++
8 files changed, 614 insertions(+), 7 deletions(-)
create mode 100644 flang/test/Fir/volatile2.fir
create mode 100644 flang/test/HLFIR/volatile1.fir
create mode 100644 flang/test/HLFIR/volatile2.fir
create mode 100644 flang/test/HLFIR/volatile3.fir
create mode 100644 flang/test/HLFIR/volatile4.fir
diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 2d61c2ee8dd8e..c1885dfbfdb01 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -6306,7 +6306,8 @@ class ArrayExprLowering {
mlir::Value buffi = computeCoordinate(buff, off);
llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
builder, loc, memcpyType(), buffi, v.getAddr(), byteSz);
- createCallMemcpy(args, /*isVolatile=*/false);
+ const bool isVolatile = fir::isa_volatile_type(v.getAddr().getType());
+ createCallMemcpy(args, isVolatile);
// Save the incremented buffer position.
builder.create<fir::StoreOp>(loc, endOff, buffPos);
@@ -6356,7 +6357,9 @@ class ArrayExprLowering {
mlir::Value buffi = computeCoordinate(buff, off);
llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
builder, loc, memcpyType(), buffi, v.getAddr(), eleSz);
- createCallMemcpy(args, /*isVolatile=*/false);
+ const bool isVolatile =
+ fir::isa_volatile_type(v.getAddr().getType());
+ createCallMemcpy(args, isVolatile);
builder.create<fir::StoreOp>(loc, plusOne, buffPos);
}
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index bd0eb599c3e38..6947bc0de14e2 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3557,7 +3557,9 @@ struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> {
mlir::Value llvmValue = adaptor.getValue();
mlir::Value llvmMemref = adaptor.getMemref();
mlir::LLVM::AliasAnalysisOpInterface newOp;
- const bool isVolatile = fir::isa_volatile_type(store.getMemref().getType());
+ const bool isVolatile =
+ fir::isa_volatile_type(store.getMemref().getType()) ||
+ fir::isa_volatile_type(store.getValue().getType());
if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(storeTy)) {
mlir::Type llvmBoxTy = lowerTy().convertBoxTypeAsStruct(boxTy);
// Always use memcpy because LLVM is not as effective at optimizing
@@ -3588,6 +3590,9 @@ struct CopyOpConversion : public fir::FIROpConversion<fir::CopyOp> {
matchAndRewrite(fir::CopyOp copy, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
mlir::Location loc = copy.getLoc();
+ const bool isVolatile =
+ fir::isa_volatile_type(copy.getSource().getType()) ||
+ fir::isa_volatile_type(copy.getDestination().getType());
mlir::Value llvmSource = adaptor.getSource();
mlir::Value llvmDestination = adaptor.getDestination();
mlir::Type i64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);
@@ -3598,10 +3603,10 @@ struct CopyOpConversion : public fir::FIROpConversion<fir::CopyOp> {
mlir::LLVM::AliasAnalysisOpInterface newOp;
if (copy.getNoOverlap())
newOp = rewriter.create<mlir::LLVM::MemcpyOp>(
- loc, llvmDestination, llvmSource, copySize, /*isVolatile=*/false);
+ loc, llvmDestination, llvmSource, copySize, isVolatile);
else
newOp = rewriter.create<mlir::LLVM::MemmoveOp>(
- loc, llvmDestination, llvmSource, copySize, /*isVolatile=*/false);
+ loc, llvmDestination, llvmSource, copySize, isVolatile);
// TODO: propagate TBAA once FirAliasTagOpInterface added to CopyOp.
attachTBAATag(newOp, copyTy, copyTy, nullptr);
diff --git a/flang/test/Fir/volatile2.fir b/flang/test/Fir/volatile2.fir
new file mode 100644
index 0000000000000..82a8413d2fc02
--- /dev/null
+++ b/flang/test/Fir/volatile2.fir
@@ -0,0 +1,54 @@
+// RUN: fir-opt --fir-to-llvm-ir %s | FileCheck %s
+func.func @_QQmain() {
+ %0 = fir.alloca !fir.box<!fir.array<10xi32>, volatile>
+ %c1 = arith.constant 1 : index
+ %c5_i32 = arith.constant 5 : i32
+ %c10 = arith.constant 10 : index
+ %1 = fir.address_of(@_QFEa) : !fir.ref<!fir.array<10xi32>>
+ %2 = fir.volatile_cast %1 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %3 = fir.address_of(@_QFEb) : !fir.ref<!fir.array<10xi32>>
+ %4 = fir.volatile_cast %3 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %5 = arith.subi %c10, %c1 : index
+ %6 = arith.addi %5, %c1 : index
+ %7 = arith.divsi %6, %c1 : index
+ cf.br ^bb1(%c1, %7 : index, index)
+^bb1(%8: index, %9: index): // 2 preds: ^bb0, ^bb2
+ %c0 = arith.constant 0 : index
+ %10 = arith.cmpi sgt, %9, %c0 : index
+ cf.cond_br %10, ^bb2, ^bb3
+^bb2: // pred: ^bb1
+ %11 = fircg.ext_array_coor %4(%c10)<%8> : (!fir.ref<!fir.array<10xi32>, volatile>, index, index) -> !fir.ref<i32, volatile>
+ fir.store %c5_i32 to %11 : !fir.ref<i32, volatile>
+ %12 = arith.addi %8, %c1 overflow<nsw> : index
+ %c1_0 = arith.constant 1 : index
+ %13 = arith.subi %9, %c1_0 : index
+ cf.br ^bb1(%12, %13 : index, index)
+^bb3: // pred: ^bb1
+ %14 = fircg.ext_embox %4(%c10) : (!fir.ref<!fir.array<10xi32>, volatile>, index) -> !fir.box<!fir.array<10xi32>, volatile>
+ %15 = fircg.ext_embox %2(%c10) : (!fir.ref<!fir.array<10xi32>, volatile>, index) -> !fir.box<!fir.array<10xi32>, volatile>
+ fir.store %15 to %0 : !fir.ref<!fir.box<!fir.array<10xi32>, volatile>>
+ %16 = fir.address_of(@_QQclX8b2af12247fe2a74a66d92bb35ca5038) : !fir.ref<!fir.char<1,13>>
+ %c3_i32 = arith.constant 3 : i32
+ %17 = fir.convert %0 : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
+ %18 = fir.volatile_cast %14 : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+ %19 = fir.convert %18 : (!fir.box<!fir.array<10xi32>>) -> !fir.box<none>
+ %20 = fir.convert %16 : (!fir.ref<!fir.char<1,13>>) -> !fir.ref<i8>
+ fir.call @_FortranAAssign(%17, %19, %20, %c3_i32) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+ return
+}
+fir.global internal @_QFEa : !fir.array<10xi32> {
+ %0 = fir.zero_bits !fir.array<10xi32>
+ fir.has_value %0 : !fir.array<10xi32>
+}
+fir.global internal @_QFEb : !fir.array<10xi32> {
+ %0 = fir.zero_bits !fir.array<10xi32>
+ fir.has_value %0 : !fir.array<10xi32>
+}
+func.func private @_FortranAAssign(!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) attributes {fir.runtime}
+fir.global linkonce @_QQclX8b2af12247fe2a74a66d92bb35ca5038 constant : !fir.char<1,13> {
+ %0 = fir.string_lit "filename.f90\00"(13) : !fir.char<1,13>
+ fir.has_value %0 : !fir.char<1,13>
+}
+// CHECK-LABEL: llvm.func @_QQmain() {
+// CHECK: llvm.store volatile %{{.+}}, %{{.+}} : i32, !llvm.ptr
+// CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %{{.+}}) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
diff --git a/flang/test/HLFIR/volatile.fir b/flang/test/HLFIR/volatile.fir
index 3404ab2e1f9ea..38edb33293370 100644
--- a/flang/test/HLFIR/volatile.fir
+++ b/flang/test/HLFIR/volatile.fir
@@ -1,4 +1,22 @@
// RUN: fir-opt --convert-hlfir-to-fir %s -o - | FileCheck %s
+// CHECK-LABEL: func.func @foo() {
+// CHECK: %[[VAL_0:.*]] = arith.constant true
+// CHECK: %[[VAL_1:.*]] = arith.constant false
+// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.logical<4> {bindc_name = "a", uniq_name = "_QFEa"}
+// CHECK: %[[VAL_3:.*]] = fir.volatile_cast %[[VAL_2]] : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>, volatile>
+// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_3]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEa"} : (!fir.ref<!fir.logical<4>, volatile>) -> !fir.ref<!fir.logical<4>, volatile>
+// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.logical<4> {bindc_name = "b", uniq_name = "_QFEb"}
+// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_5]] {uniq_name = "_QFEb"} : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>>
+// CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> !fir.ref<i32>
+// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_1]] : (i1) -> !fir.logical<4>
+// CHECK: fir.store %[[VAL_9]] to %[[VAL_4]] : !fir.ref<!fir.logical<4>, volatile>
+// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]] : !fir.ref<!fir.logical<4>, volatile>
+// CHECK: fir.store %[[VAL_10]] to %[[VAL_6]] : !fir.ref<!fir.logical<4>>
+// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (i1) -> !fir.logical<4>
+// CHECK: fir.store %[[VAL_11]] to %[[VAL_4]] : !fir.ref<!fir.logical<4>, volatile>
+// CHECK: return
+// CHECK: }
func.func @foo() {
%true = arith.constant true
%false = arith.constant false
@@ -17,5 +35,3 @@ func.func @foo() {
hlfir.assign %9 to %2#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
return
}
-// CHECK: fir.store %{{.+}} to %{{.+}} : !fir.ref<!fir.logical<4>, volatile>
-// CHECK: %{{.+}} = fir.load %{{.+}} : !fir.ref<!fir.logical<4>, volatile>
diff --git a/flang/test/HLFIR/volatile1.fir b/flang/test/HLFIR/volatile1.fir
new file mode 100644
index 0000000000000..de22e999ce6f4
--- /dev/null
+++ b/flang/test/HLFIR/volatile1.fir
@@ -0,0 +1,160 @@
+// RUN: fir-opt %s --bufferize-hlfir --convert-hlfir-to-fir | FileCheck %s
+func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+ %0 = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+ %c10 = arith.constant 10 : index
+ %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %2 = fir.volatile_cast %0 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %3:2 = hlfir.declare %2(%1) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %4 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+ %5 = fir.volatile_cast %4 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+ %6:2 = hlfir.declare %5 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+ %7 = fir.volatile_cast %6#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+ fir.call @_QFPnot_declared_volatile_in_this_scope(%7) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<i32>) -> ()
+ %c1 = arith.constant 1 : index
+ fir.do_loop %arg0 = %c1 to %c10 step %c1 {
+ %22 = hlfir.designate %3#0 (%arg0) : (!fir.ref<!fir.array<10xi32>, volatile>, index) -> !fir.ref<i32, volatile>
+ %23 = fir.volatile_cast %22 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+ fir.call @_QFPnot_declared_volatile_in_this_scope(%23) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<i32>) -> ()
+ }
+ %c10_i32 = arith.constant 10 : i32
+ %8 = fir.volatile_cast %3#0 : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+ %9 = fir.convert %8 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<?xi32>>
+ %10:3 = hlfir.associate %c10_i32 {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
+ fir.call @_QFPdeclared_volatile_in_this_scope(%9, %10#0) fastmath<contract> : (!fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) -> ()
+ hlfir.end_associate %10#1, %10#2 : !fir.ref<i32>, i1
+ %c6_i32 = arith.constant 6 : i32
+ %11 = fir.address_of(@_QQclX28a011e93b63ba43ee03b06f1598b113) : !fir.ref<!fir.char<1,79>>
+ %12 = fir.convert %11 : (!fir.ref<!fir.char<1,79>>) -> !fir.ref<i8>
+ %c8_i32 = arith.constant 8 : i32
+ %13 = fir.call @_FortranAioBeginExternalListOutput(%c6_i32, %12, %c8_i32) fastmath<contract> : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+ %14 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %15 = fir.embox %3#0(%14) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+ %16 = fir.volatile_cast %15 : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+ %17 = fir.convert %16 : (!fir.box<!fir.array<10xi32>>) -> !fir.box<none>
+ %18 = fir.call @_FortranAioOutputDescriptor(%13, %17) fastmath<contract> : (!fir.ref<i8>, !fir.box<none>) -> i1
+ %19 = fir.load %6#0 : !fir.ref<i32, volatile>
+ %20 = fir.call @_FortranAioOutputInteger32(%13, %19) fastmath<contract> : (!fir.ref<i8>, i32) -> i1
+ %21 = fir.call @_FortranAioEndIoStatement(%13) fastmath<contract> : (!fir.ref<i8>) -> i32
+ return
+}
+func.func private @_QFPnot_declared_volatile_in_this_scope(%arg0: !fir.ref<i32> {fir.bindc_name = "v"}) attributes {fir.host_symbol = @_QQmain, fir.proc_attrs = #fir.proc_attrs<elemental, pure>, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1:2 = hlfir.declare %arg0 dummy_scope %0 {fortran_attrs = #fir.var_attrs<intent_inout>, uniq_name = "_QFFnot_declared_volatile_in_this_scopeEv"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %c1_i32 = arith.constant 1 : i32
+ hlfir.assign %c1_i32 to %1#0 : i32, !fir.ref<i32>
+ return
+}
+func.func private @_QFPdeclared_volatile_in_this_scope(%arg0: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "v"}, %arg1: !fir.ref<i32> {fir.bindc_name = "n"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1:2 = hlfir.declare %arg1 dummy_scope %0 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFFdeclared_volatile_in_this_scopeEn"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %2 = fir.load %1#0 : !fir.ref<i32>
+ %3 = fir.convert %2 : (i32) -> i64
+ %4 = fir.convert %3 : (i64) -> index
+ %c0 = arith.constant 0 : index
+ %5 = arith.cmpi sgt, %4, %c0 : index
+ %6 = arith.select %5, %4, %c0 : index
+ %7 = fir.shape %6 : (index) -> !fir.shape<1>
+ %8 = fir.volatile_cast %arg0 : (!fir.ref<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>, volatile>
+ %9:2 = hlfir.declare %8(%7) dummy_scope %0 {fortran_attrs = #fir.var_attrs<intent_inout, volatile>, uniq_name = "_QFFdeclared_volatile_in_this_scopeEv"} : (!fir.ref<!fir.array<?xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>, volatile>, !fir.ref<!fir.array<?xi32>, volatile>)
+ %c1_i32 = arith.constant 1 : i32
+ hlfir.assign %c1_i32 to %9#0 : i32, !fir.box<!fir.array<?xi32>, volatile>
+ return
+}
+fir.global internal @_QFEarr : !fir.array<10xi32> {
+ %0 = fir.zero_bits !fir.array<10xi32>
+ fir.has_value %0 : !fir.array<10xi32>
+}
+
+// CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+// CHECK: %[[VAL_0:.*]] = fir.alloca i32 {adapt.valuebyref}
+// CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]](%[[VAL_3]]) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_6:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+// CHECK: %[[VAL_7:.*]] = fir.volatile_cast %[[VAL_6]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_9:.*]] = fir.volatile_cast %[[VAL_8]] : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+// CHECK: fir.call @_QFPnot_declared_volatile_in_this_scope(%[[VAL_9]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<i32>) -> ()
+// CHECK: %[[VAL_10:.*]] = arith.constant 1 : index
+// CHECK: fir.do_loop %[[VAL_11:.*]] = %[[VAL_10]] to %[[VAL_2]] step %[[VAL_10]] {
+// CHECK: %[[VAL_12:.*]] = fir.array_coor %[[VAL_5]](%[[VAL_3]]) %[[VAL_11]] : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, index) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_13:.*]] = fir.volatile_cast %[[VAL_12]] : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+// CHECK: fir.call @_QFPnot_declared_volatile_in_this_scope(%[[VAL_13]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<i32>) -> ()
+// CHECK: }
+// CHECK: %[[VAL_14:.*]] = arith.constant 10 : i32
+// CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<?xi32>>
+// CHECK: fir.store %[[VAL_14]] to %[[VAL_0]] : !fir.ref<i32>
+// CHECK: %[[VAL_17:.*]] = arith.constant false
+// CHECK: fir.call @_QFPdeclared_volatile_in_this_scope(%[[VAL_16]], %[[VAL_0]]) fastmath<contract> : (!fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) -> ()
+// CHECK: %[[VAL_18:.*]] = arith.constant 6 : i32
+// CHECK: %[[VAL_19:.*]] = fir.address_of(
+// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (
+// CHECK: %[[VAL_21:.*]] = arith.constant 8 : i32
+// CHECK: %[[VAL_22:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[VAL_18]], %[[VAL_20]], %[[VAL_21]]) fastmath<contract> : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+// CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_24:.*]] = fir.embox %[[VAL_5]](%[[VAL_23]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_25:.*]] = fir.volatile_cast %[[VAL_24]] : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<none>
+// CHECK: %[[VAL_27:.*]] = fir.call @_FortranAioOutputDescriptor(%[[VAL_22]], %[[VAL_26]]) fastmath<contract> : (!fir.ref<i8>, !fir.box<none>) -> i1
+// CHECK: %[[VAL_28:.*]] = fir.load %[[VAL_8]] : !fir.ref<i32, volatile>
+// CHECK: %[[VAL_29:.*]] = fir.call @_FortranAioOutputInteger32(%[[VAL_22]], %[[VAL_28]]) fastmath<contract> : (!fir.ref<i8>, i32) -> i1
+// CHECK: %[[VAL_30:.*]] = fir.call @_FortranAioEndIoStatement(%[[VAL_22]]) fastmath<contract> : (!fir.ref<i8>) -> i32
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPnot_declared_volatile_in_this_scope(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<i32> {fir.bindc_name = "v"}) attributes {fir.host_symbol = @_QQmain, fir.proc_attrs = #fir.proc_attrs<elemental, pure>, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<intent_inout>, uniq_name = "_QFFnot_declared_volatile_in_this_scopeEv"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
+// CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32
+// CHECK: fir.store %[[VAL_3]] to %[[VAL_2]] : !fir.ref<i32>
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPdeclared_volatile_in_this_scope(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "v"},
+// CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<i32> {fir.bindc_name = "n"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.array<?xi32>, volatile>
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_1]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFFdeclared_volatile_in_this_scopeEn"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
+// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
+// CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> i64
+// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i64) -> index
+// CHECK: %[[VAL_8:.*]] = arith.constant 0 : index
+// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_7]], %[[VAL_8]] : index
+// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_7]], %[[VAL_8]] : index
+// CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_12:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>, volatile>
+// CHECK: %[[VAL_13:.*]] = fir.declare %[[VAL_12]](%[[VAL_11]]) dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<intent_inout, volatile>, uniq_name = "_QFFdeclared_volatile_in_this_scopeEv"} : (!fir.ref<!fir.array<?xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> !fir.ref<!fir.array<?xi32>, volatile>
+// CHECK: %[[VAL_14:.*]] = fir.embox %[[VAL_13]](%[[VAL_11]]) : (!fir.ref<!fir.array<?xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>, volatile>
+// CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32
+// CHECK: %[[VAL_16:.*]] = fir.alloca i32
+// CHECK: fir.store %[[VAL_15]] to %[[VAL_16]] : !fir.ref<i32>
+// CHECK: %[[VAL_17:.*]] = fir.embox %[[VAL_16]] : (!fir.ref<i32>) -> !fir.box<i32>
+// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_13]](%[[VAL_18]]) : (!fir.ref<!fir.array<?xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>, volatile>
+// CHECK: fir.store %[[VAL_19]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?xi32>, volatile>>
+// CHECK: %[[VAL_20:.*]] = fir.address_of(
+// CHECK: %[[VAL_21:.*]] = arith.constant 79 : index
+// CHECK: %[[VAL_22:.*]] = arith.constant 60 : i32
+// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.array<?xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_17]] : (!fir.box<i32>) -> !fir.box<none>
+// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_20]] : (
+// CHECK: fir.call @_FortranAAssign(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_22]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: fir.global internal @_QFEarr : !fir.array<10xi32> {
+// CHECK: %[[VAL_0:.*]] = fir.zero_bits !fir.array<10xi32>
+// CHECK: fir.has_value %[[VAL_0]] : !fir.array<10xi32>
+// CHECK: }
+// CHECK: func.func private @_FortranAAssign(!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) attributes {fir.runtime}
+
+// CHECK-LABEL: fir.global linkonce @_QQclX6d159f5b212633743d299e4aa5142350 constant : !fir.char<1,79> {
+// CHECK: %[[VAL_0:.*]] = fir.string_lit "/local/home/amancinelli/lorado/src/llvm-project/flang/test/HLFIR/volatile1.fir\00"(79) : !fir.char<1,79>
+// CHECK: fir.has_value %[[VAL_0]] : !fir.char<1,79>
+// CHECK: }
+
diff --git a/flang/test/HLFIR/volatile2.fir b/flang/test/HLFIR/volatile2.fir
new file mode 100644
index 0000000000000..86ac683adad3f
--- /dev/null
+++ b/flang/test/HLFIR/volatile2.fir
@@ -0,0 +1,66 @@
+// RUN: fir-opt %s --bufferize-hlfir --convert-hlfir-to-fir | FileCheck %s
+func.func private @_QFPa() -> i32 attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFFaEa"}
+ %1 = fir.volatile_cast %0 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+ %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFaEa"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+ %c1_i32 = arith.constant 1 : i32
+ hlfir.assign %c1_i32 to %2#0 : i32, !fir.ref<i32, volatile>
+ %3 = fir.volatile_cast %2#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+ %4 = fir.load %3 : !fir.ref<i32>
+ return %4 : i32
+}
+func.func private @_QFPb() -> i32 attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.alloca i32 {bindc_name = "r", uniq_name = "_QFFbEr"}
+ %1 = fir.volatile_cast %0 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+ %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFbEr"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+ %c2_i32 = arith.constant 2 : i32
+ hlfir.assign %c2_i32 to %2#0 : i32, !fir.ref<i32, volatile>
+ %3 = fir.volatile_cast %2#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+ %4 = fir.load %3 : !fir.ref<i32>
+ return %4 : i32
+}
+func.func private @_QFPc() -> f32 attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.alloca f32 {bindc_name = "r", uniq_name = "_QFFcEr"}
+ %1 = fir.volatile_cast %0 : (!fir.ref<f32>) -> !fir.ref<f32, volatile>
+ %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFcEr"} : (!fir.ref<f32, volatile>) -> (!fir.ref<f32, volatile>, !fir.ref<f32, volatile>)
+ %cst = arith.constant 3.000000e+00 : f32
+ hlfir.assign %cst to %2#0 : f32, !fir.ref<f32, volatile>
+ %3 = fir.volatile_cast %2#0 : (!fir.ref<f32, volatile>) -> !fir.ref<f32>
+ %4 = fir.load %3 : !fir.ref<f32>
+ return %4 : f32
+}
+
+
+// CHECK-LABEL: func.func private @_QFPa() -> i32 attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFFaEa"}
+// CHECK: %[[VAL_1:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFaEa"} : (!fir.ref<i32, volatile>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32
+// CHECK: fir.store %[[VAL_3]] to %[[VAL_2]] : !fir.ref<i32, volatile>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_2]] : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
+// CHECK: return %[[VAL_5]] : i32
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPb() -> i32 attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "r", uniq_name = "_QFFbEr"}
+// CHECK: %[[VAL_1:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFbEr"} : (!fir.ref<i32, volatile>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32
+// CHECK: fir.store %[[VAL_3]] to %[[VAL_2]] : !fir.ref<i32, volatile>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_2]] : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
+// CHECK: return %[[VAL_5]] : i32
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPc() -> f32 attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "r", uniq_name = "_QFFcEr"}
+// CHECK: %[[VAL_1:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<f32>) -> !fir.ref<f32, volatile>
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFcEr"} : (!fir.ref<f32, volatile>) -> !fir.ref<f32, volatile>
+// CHECK: %[[VAL_3:.*]] = arith.constant 3.000000e+00 : f32
+// CHECK: fir.store %[[VAL_3]] to %[[VAL_2]] : !fir.ref<f32, volatile>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_2]] : (!fir.ref<f32, volatile>) -> !fir.ref<f32>
+// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<f32>
+// CHECK: return %[[VAL_5]] : f32
+// CHECK: }
+
diff --git a/flang/test/HLFIR/volatile3.fir b/flang/test/HLFIR/volatile3.fir
new file mode 100644
index 0000000000000..88d23bcd4e36c
--- /dev/null
+++ b/flang/test/HLFIR/volatile3.fir
@@ -0,0 +1,150 @@
+// RUN: fir-opt %s --bufferize-hlfir --convert-hlfir-to-fir | FileCheck %s
+func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+ %0 = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+ %c10 = arith.constant 10 : index
+ %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %2 = fir.volatile_cast %0 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %3:2 = hlfir.declare %2(%1) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %4 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+ %5 = fir.volatile_cast %4 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+ %6:2 = hlfir.declare %5 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+ %7 = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %8 = fir.volatile_cast %7 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %9:2 = hlfir.declare %8 {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEptr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+ %10 = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+ %c10_0 = arith.constant 10 : index
+ %11 = fir.shape %c10_0 : (index) -> !fir.shape<1>
+ %12 = fir.volatile_cast %10 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %13:2 = hlfir.declare %12(%11) {fortran_attrs = #fir.var_attrs<target, volatile>, uniq_name = "_QFEtgt"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %14 = fir.shape %c10_0 : (index) -> !fir.shape<1>
+ %15 = fir.embox %13#0(%14) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+ fir.store %15 to %9#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %c0_i32 = arith.constant 0 : i32
+ hlfir.assign %c0_i32 to %6#0 : i32, !fir.ref<i32, volatile>
+ %c1_i32 = arith.constant 1 : i32
+ hlfir.assign %c1_i32 to %3#0 : i32, !fir.ref<!fir.array<10xi32>, volatile>
+ %16 = fir.volatile_cast %3#0 : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+ fir.call @_QFPd(%16) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+ %17 = fir.embox %3#0(%1) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+ %18 = fir.volatile_cast %17 : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+ %19 = fir.convert %18 : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<?xi32>>
+ fir.call @_QFPe(%19) fastmath<contract> : (!fir.box<!fir.array<?xi32>>) -> ()
+ %20 = fir.volatile_cast %3#0 : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+ fir.call @_QFPf(%20) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+ %21 = fir.convert %9#0 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>
+ fir.call @_QFPg(%21) fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> ()
+ return
+}
+func.func private @_QFPd(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %c10 = arith.constant 10 : index
+ %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %2 = fir.volatile_cast %arg0 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %3:2 = hlfir.declare %2(%1) dummy_scope %0 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFdEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ return
+}
+func.func private @_QFPe(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1:2 = hlfir.declare %arg0 dummy_scope %0 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFeEarr"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+ return
+}
+func.func private @_QFPf(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %c10 = arith.constant 10 : index
+ %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %2 = fir.volatile_cast %arg0 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %3:2 = hlfir.declare %2(%1) dummy_scope %0 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFfEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ return
+}
+func.func private @_QFPg(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.volatile_cast %arg0 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %2:2 = hlfir.declare %1 dummy_scope %0 {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFFgEarr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+ return
+}
+
+// CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+// CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]](%[[VAL_3]]) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_6:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+// CHECK: %[[VAL_7:.*]] = fir.volatile_cast %[[VAL_6]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_9:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+// CHECK: %[[VAL_10:.*]] = fir.volatile_cast %[[VAL_9]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_11:.*]] = fir.declare %[[VAL_10]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEptr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_12:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_13:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_12]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_16:.*]] = fir.declare %[[VAL_15]](%[[VAL_14]]) {fortran_attrs = #fir.var_attrs<target, volatile>, uniq_name = "_QFEtgt"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_18:.*]] = fir.embox %[[VAL_16]](%[[VAL_17]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+// CHECK: fir.store %[[VAL_18]] to %[[VAL_11]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_19:.*]] = arith.constant 0 : i32
+// CHECK: fir.store %[[VAL_19]] to %[[VAL_8]] : !fir.ref<i32, volatile>
+// CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32
+// CHECK: %[[VAL_21:.*]] = fir.alloca i32
+// CHECK: fir.store %[[VAL_20]] to %[[VAL_21]] : !fir.ref<i32>
+// CHECK: %[[VAL_22:.*]] = fir.embox %[[VAL_21]] : (!fir.ref<i32>) -> !fir.box<i32>
+// CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_24:.*]] = fir.embox %[[VAL_5]](%[[VAL_23]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: fir.store %[[VAL_24]] to %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<10xi32>, volatile>>
+// CHECK: %[[VAL_25:.*]] = fir.address_of{{.+}}
+// CHECK: %[[VAL_26:.*]] = arith.constant
+// CHECK: %[[VAL_27:.*]] = arith.constant
+// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_22]] : (!fir.box<i32>) -> !fir.box<none>
+// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_25]]
+// CHECK: fir.call @_FortranAAssign(%[[VAL_28]], %[[VAL_29]], %[[VAL_30]], %[[VAL_27]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+// CHECK: %[[VAL_31:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+// CHECK: fir.call @_QFPd(%[[VAL_31]]) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+// CHECK: %[[VAL_32:.*]] = fir.embox %[[VAL_5]](%[[VAL_3]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_33:.*]] = fir.volatile_cast %[[VAL_32]] : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_33]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: fir.call @_QFPe(%[[VAL_34]]) fastmath<contract> : (!fir.box<!fir.array<?xi32>>) -> ()
+// CHECK: %[[VAL_35:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+// CHECK: fir.call @_QFPf(%[[VAL_35]]) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>
+// CHECK: fir.call @_QFPg(%[[VAL_36]]) fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> ()
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPd(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]](%[[VAL_3]]) dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFdEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPe(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFeEarr"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[VAL_3:.*]] = fir.rebox %[[VAL_2]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPf(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]](%[[VAL_3]]) dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFfEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPg(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_2]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFFgEarr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: return
+// CHECK: }
diff --git a/flang/test/HLFIR/volatile4.fir b/flang/test/HLFIR/volatile4.fir
new file mode 100644
index 0000000000000..b2c029cb824de
--- /dev/null
+++ b/flang/test/HLFIR/volatile4.fir
@@ -0,0 +1,153 @@
+// RUN: fir-opt %s --bufferize-hlfir --convert-hlfir-to-fir | FileCheck %s
+func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+ %0 = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+ %c10 = arith.constant 10 : index
+ %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %2 = fir.volatile_cast %0 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %3:2 = hlfir.declare %2(%1) {fortran_attrs = #fir.var_attrs<volatile, internal_assoc>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %4 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+ %5 = fir.volatile_cast %4 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+ %6:2 = hlfir.declare %5 {fortran_attrs = #fir.var_attrs<volatile, internal_assoc>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+ %7 = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %8 = fir.volatile_cast %7 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %9:2 = hlfir.declare %8 {fortran_attrs = #fir.var_attrs<pointer, volatile, internal_assoc>, uniq_name = "_QFEptr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+ %10 = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+ %c10_0 = arith.constant 10 : index
+ %11 = fir.shape %c10_0 : (index) -> !fir.shape<1>
+ %12 = fir.volatile_cast %10 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %13:2 = hlfir.declare %12(%11) {fortran_attrs = #fir.var_attrs<target, volatile, internal_assoc>, uniq_name = "_QFEtgt"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %14 = fir.alloca tuple<!fir.ref<i32>>
+ %c0_i32 = arith.constant 0 : i32
+ %15 = fir.coordinate_of %14, %c0_i32 : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+ %16 = fir.volatile_cast %6#0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+ fir.store %16 to %15 : !fir.llvm_ptr<!fir.ref<i32>>
+ %17 = fir.shape %c10_0 : (index) -> !fir.shape<1>
+ %18 = fir.embox %13#0(%17) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+ fir.store %18 to %9#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %c0_i32_1 = arith.constant 0 : i32
+ hlfir.assign %c0_i32_1 to %6#0 : i32, !fir.ref<i32, volatile>
+ %c1_i32 = arith.constant 1 : i32
+ hlfir.assign %c1_i32 to %3#0 : i32, !fir.ref<!fir.array<10xi32>, volatile>
+ fir.call @_QFPhost_assoc(%14) fastmath<contract> : (!fir.ref<tuple<!fir.ref<i32>>>) -> ()
+ return
+}
+func.func private @_QFPhost_assoc(%arg0: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+ %c10 = arith.constant 10 : index
+ %2 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %3 = fir.volatile_cast %1 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %4:2 = hlfir.declare %3(%2) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %5 = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %6 = fir.volatile_cast %5 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %7:2 = hlfir.declare %6 {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEptr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>)
+ %8 = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+ %c10_0 = arith.constant 10 : index
+ %9 = fir.shape %c10_0 : (index) -> !fir.shape<1>
+ %10 = fir.volatile_cast %8 : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+ %11:2 = hlfir.declare %10(%9) {fortran_attrs = #fir.var_attrs<target, volatile>, uniq_name = "_QFEtgt"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+ %c0_i32 = arith.constant 0 : i32
+ %12 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+ %13 = fir.load %12 : !fir.llvm_ptr<!fir.ref<i32>>
+ %14 = fir.volatile_cast %13 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+ %15:2 = hlfir.declare %14 {fortran_attrs = #fir.var_attrs<volatile, host_assoc>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+ %16 = fir.shape %c10_0 : (index) -> !fir.shape<1>
+ %17 = fir.embox %11#0(%16) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+ fir.store %17 to %7#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+ %c0_i32_1 = arith.constant 0 : i32
+ hlfir.assign %c0_i32_1 to %15#0 : i32, !fir.ref<i32, volatile>
+ %c1_i32 = arith.constant 1 : i32
+ hlfir.assign %c1_i32 to %4#0 : i32, !fir.ref<!fir.array<10xi32>, volatile>
+ return
+}
+// CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+// CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]](%[[VAL_3]]) {fortran_attrs = #fir.var_attrs<volatile, internal_assoc>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_6:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+// CHECK: %[[VAL_7:.*]] = fir.volatile_cast %[[VAL_6]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs<volatile, internal_assoc>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_9:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+// CHECK: %[[VAL_10:.*]] = fir.volatile_cast %[[VAL_9]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_11:.*]] = fir.declare %[[VAL_10]] {fortran_attrs = #fir.var_attrs<pointer, volatile, internal_assoc>, uniq_name = "_QFEptr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_12:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_13:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_12]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_16:.*]] = fir.declare %[[VAL_15]](%[[VAL_14]]) {fortran_attrs = #fir.var_attrs<target, volatile, internal_assoc>, uniq_name = "_QFEtgt"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_17:.*]] = fir.alloca tuple<!fir.ref<i32>>
+// CHECK: %[[VAL_18:.*]] = arith.constant 0 : i32
+// CHECK: %[[VAL_19:.*]] = fir.coordinate_of %[[VAL_17]], %[[VAL_18]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+// CHECK: %[[VAL_20:.*]] = fir.volatile_cast %[[VAL_8]] : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
+// CHECK: fir.store %[[VAL_20]] to %[[VAL_19]] : !fir.llvm_ptr<!fir.ref<i32>>
+// CHECK: %[[VAL_21:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_22:.*]] = fir.embox %[[VAL_16]](%[[VAL_21]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+// CHECK: fir.store %[[VAL_22]] to %[[VAL_11]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_23:.*]] = arith.constant 0 : i32
+// CHECK: fir.store %[[VAL_23]] to %[[VAL_8]] : !fir.ref<i32, volatile>
+// CHECK: %[[VAL_24:.*]] = arith.constant 1 : i32
+// CHECK: %[[VAL_25:.*]] = fir.alloca i32
+// CHECK: fir.store %[[VAL_24]] to %[[VAL_25]] : !fir.ref<i32>
+// CHECK: %[[VAL_26:.*]] = fir.embox %[[VAL_25]] : (!fir.ref<i32>) -> !fir.box<i32>
+// CHECK: %[[VAL_27:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_28:.*]] = fir.embox %[[VAL_5]](%[[VAL_27]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: fir.store %[[VAL_28]] to %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<10xi32>, volatile>>
+// CHECK: %[[VAL_29:.*]] = fir.address_of
+// CHECK: %[[VAL_30:.*]] = arith.constant
+// CHECK: %[[VAL_31:.*]] = arith.constant
+// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_26]] : (!fir.box<i32>) -> !fir.box<none>
+// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_29]] : (!fir.ref<!fir.char<1,79>>) -> !fir.ref<i8>
+// CHECK: fir.call @_FortranAAssign(%[[VAL_32]], %[[VAL_33]], %[[VAL_34]], %[[VAL_31]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+// CHECK: fir.call @_QFPhost_assoc(%[[VAL_17]]) fastmath<contract> : (!fir.ref<tuple<!fir.ref<i32>>>) -> ()
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: func.func private @_QFPhost_assoc(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_3:.*]] = fir.address_of(@_QFEarr) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_4:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_3]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_7:.*]] = fir.declare %[[VAL_6]](%[[VAL_5]]) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_8:.*]] = fir.address_of(@_QFEptr) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+// CHECK: %[[VAL_9:.*]] = fir.volatile_cast %[[VAL_8]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_10:.*]] = fir.declare %[[VAL_9]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEptr"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_11:.*]] = fir.address_of(@_QFEtgt) : !fir.ref<!fir.array<10xi32>>
+// CHECK: %[[VAL_12:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_14:.*]] = fir.volatile_cast %[[VAL_11]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_15:.*]] = fir.declare %[[VAL_14]](%[[VAL_13]]) {fortran_attrs = #fir.var_attrs<target, volatile>, uniq_name = "_QFEtgt"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+// CHECK: %[[VAL_16:.*]] = arith.constant 0 : i32
+// CHECK: %[[VAL_17:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_16]] : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+// CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]] : !fir.llvm_ptr<!fir.ref<i32>>
+// CHECK: %[[VAL_19:.*]] = fir.volatile_cast %[[VAL_18]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_20:.*]] = fir.declare %[[VAL_19]] {fortran_attrs = #fir.var_attrs<volatile, host_assoc>, uniq_name = "_QFEi"} : (!fir.ref<i32, volatile>) -> !fir.ref<i32, volatile>
+// CHECK: %[[VAL_21:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_22:.*]] = fir.embox %[[VAL_15]](%[[VAL_21]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+// CHECK: fir.store %[[VAL_22]] to %[[VAL_10]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+// CHECK: %[[VAL_23:.*]] = arith.constant 0 : i32
+// CHECK: fir.store %[[VAL_23]] to %[[VAL_20]] : !fir.ref<i32, volatile>
+// CHECK: %[[VAL_24:.*]] = arith.constant 1 : i32
+// CHECK: %[[VAL_25:.*]] = fir.alloca i32
+// CHECK: fir.store %[[VAL_24]] to %[[VAL_25]] : !fir.ref<i32>
+// CHECK: %[[VAL_26:.*]] = fir.embox %[[VAL_25]] : (!fir.ref<i32>) -> !fir.box<i32>
+// CHECK: %[[VAL_27:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_28:.*]] = fir.embox %[[VAL_7]](%[[VAL_27]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+// CHECK: fir.store %[[VAL_28]] to %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<10xi32>, volatile>>
+// CHECK: %[[VAL_29:.*]] = fir.address_of
+// CHECK: %[[VAL_30:.*]] = arith.constant
+// CHECK: %[[VAL_31:.*]] = arith.constant
+// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_26]] : (!fir.box<i32>) -> !fir.box<none>
+// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_29]] : (!fir.ref<!fir.char<1,79>>) -> !fir.ref<i8>
+// CHECK: fir.call @_FortranAAssign(%[[VAL_32]], %[[VAL_33]], %[[VAL_34]], %[[VAL_31]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+// CHECK: return
+// CHECK: }
+// CHECK: func.func private @_FortranAAssign(!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) attributes {fir.runtime}
+
>From 8da078b083447188a89b84049a095a2ea33e107c Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Thu, 10 Apr 2025 19:40:27 -0700
Subject: [PATCH 4/4] Fix tests on windows
---
flang/test/HLFIR/volatile1.fir | 6 +++---
flang/test/HLFIR/volatile3.fir | 2 +-
flang/test/HLFIR/volatile4.fir | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/flang/test/HLFIR/volatile1.fir b/flang/test/HLFIR/volatile1.fir
index de22e999ce6f4..dcc8697e2903e 100644
--- a/flang/test/HLFIR/volatile1.fir
+++ b/flang/test/HLFIR/volatile1.fir
@@ -90,7 +90,7 @@ fir.global internal @_QFEarr : !fir.array<10xi32> {
// CHECK: %[[VAL_17:.*]] = arith.constant false
// CHECK: fir.call @_QFPdeclared_volatile_in_this_scope(%[[VAL_16]], %[[VAL_0]]) fastmath<contract> : (!fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) -> ()
// CHECK: %[[VAL_18:.*]] = arith.constant 6 : i32
-// CHECK: %[[VAL_19:.*]] = fir.address_of(
+// CHECK: %[[VAL_19:.*]] = fir.address_of
// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (
// CHECK: %[[VAL_21:.*]] = arith.constant 8 : i32
// CHECK: %[[VAL_22:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[VAL_18]], %[[VAL_20]], %[[VAL_21]]) fastmath<contract> : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
@@ -138,8 +138,8 @@ fir.global internal @_QFEarr : !fir.array<10xi32> {
// CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_13]](%[[VAL_18]]) : (!fir.ref<!fir.array<?xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>, volatile>
// CHECK: fir.store %[[VAL_19]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?xi32>, volatile>>
// CHECK: %[[VAL_20:.*]] = fir.address_of(
-// CHECK: %[[VAL_21:.*]] = arith.constant 79 : index
-// CHECK: %[[VAL_22:.*]] = arith.constant 60 : i32
+// CHECK: %[[VAL_21:.*]] = arith.constant
+// CHECK: %[[VAL_22:.*]] = arith.constant
// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.array<?xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_17]] : (!fir.box<i32>) -> !fir.box<none>
// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_20]] : (
diff --git a/flang/test/HLFIR/volatile3.fir b/flang/test/HLFIR/volatile3.fir
index 88d23bcd4e36c..41e42916e8ee5 100644
--- a/flang/test/HLFIR/volatile3.fir
+++ b/flang/test/HLFIR/volatile3.fir
@@ -93,7 +93,7 @@ func.func private @_QFPg(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>,
// CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
// CHECK: %[[VAL_24:.*]] = fir.embox %[[VAL_5]](%[[VAL_23]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
// CHECK: fir.store %[[VAL_24]] to %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<10xi32>, volatile>>
-// CHECK: %[[VAL_25:.*]] = fir.address_of{{.+}}
+// CHECK: %[[VAL_25:.*]] = fir.address_of
// CHECK: %[[VAL_26:.*]] = arith.constant
// CHECK: %[[VAL_27:.*]] = arith.constant
// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
diff --git a/flang/test/HLFIR/volatile4.fir b/flang/test/HLFIR/volatile4.fir
index b2c029cb824de..cbf0aa31cb9f3 100644
--- a/flang/test/HLFIR/volatile4.fir
+++ b/flang/test/HLFIR/volatile4.fir
@@ -100,7 +100,7 @@ func.func private @_QFPhost_assoc(%arg0: !fir.ref<tuple<!fir.ref<i32>>> {fir.hos
// CHECK: %[[VAL_31:.*]] = arith.constant
// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_26]] : (!fir.box<i32>) -> !fir.box<none>
-// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_29]] : (!fir.ref<!fir.char<1,79>>) -> !fir.ref<i8>
+// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_29]]
// CHECK: fir.call @_FortranAAssign(%[[VAL_32]], %[[VAL_33]], %[[VAL_34]], %[[VAL_31]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
// CHECK: fir.call @_QFPhost_assoc(%[[VAL_17]]) fastmath<contract> : (!fir.ref<tuple<!fir.ref<i32>>>) -> ()
// CHECK: return
@@ -145,7 +145,7 @@ func.func private @_QFPhost_assoc(%arg0: !fir.ref<tuple<!fir.ref<i32>>> {fir.hos
// CHECK: %[[VAL_31:.*]] = arith.constant
// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.array<10xi32>, volatile>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_26]] : (!fir.box<i32>) -> !fir.box<none>
-// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_29]] : (!fir.ref<!fir.char<1,79>>) -> !fir.ref<i8>
+// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_29]]
// CHECK: fir.call @_FortranAAssign(%[[VAL_32]], %[[VAL_33]], %[[VAL_34]], %[[VAL_31]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
// CHECK: return
// CHECK: }
More information about the flang-commits
mailing list