[flang-commits] [flang] 8836bce - [flang] Add lowering of volatile references (#132486)
via flang-commits
flang-commits at lists.llvm.org
Wed Apr 30 08:46:37 PDT 2025
Author: Asher Mancinelli
Date: 2025-04-30T08:46:33-07:00
New Revision: 8836bce84208737f5807c396345a41e688d3ec11
URL: https://github.com/llvm/llvm-project/commit/8836bce84208737f5807c396345a41e688d3ec11
DIFF: https://github.com/llvm/llvm-project/commit/8836bce84208737f5807c396345a41e688d3ec11.diff
LOG: [flang] Add lowering of volatile references (#132486)
[RFC on
discourse](https://discourse.llvm.org/t/rfc-volatile-representation-in-flang/85404/1)
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.
Prior commits:
```
c9ec1bc753b0 [flang] Handle volatility in lowering and codegen (#135311)
e42f8609858f [flang][nfc] Support volatility in Fir ops (#134858)
b2711e1526f9 [flang][nfc] Support volatile on ref, box, and class types (#134386)
```
Added:
flang/test/Fir/volatile.fir
flang/test/Fir/volatile2.fir
flang/test/HLFIR/volatile.fir
flang/test/Lower/volatile-openmp.f90
flang/test/Lower/volatile-string.f90
flang/test/Lower/volatile1.f90
flang/test/Lower/volatile2.f90
flang/test/Lower/volatile3.f90
flang/test/Lower/volatile4.f90
Modified:
flang/docs/FortranStandardsSupport.md
flang/docs/ReleaseNotes.md
flang/include/flang/Optimizer/Builder/BoxValue.h
flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
flang/include/flang/Optimizer/Dialect/FIROps.td
flang/include/flang/Optimizer/Dialect/FIRType.h
flang/include/flang/Optimizer/Dialect/FIRTypes.td
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/CallInterface.cpp
flang/lib/Lower/ConvertCall.cpp
flang/lib/Lower/ConvertExpr.cpp
flang/lib/Lower/ConvertExprToHLFIR.cpp
flang/lib/Lower/HostAssociations.cpp
flang/lib/Lower/IO.cpp
flang/lib/Optimizer/Builder/Character.cpp
flang/lib/Optimizer/Builder/FIRBuilder.cpp
flang/lib/Optimizer/Builder/HLFIRTools.cpp
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
flang/lib/Optimizer/Dialect/FIRType.cpp
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
flang/test/Fir/cse.fir
Removed:
################################################################################
diff --git a/flang/docs/FortranStandardsSupport.md b/flang/docs/FortranStandardsSupport.md
index 78f5aa4f5dd8d..f54c65b59f23b 100644
--- a/flang/docs/FortranStandardsSupport.md
+++ b/flang/docs/FortranStandardsSupport.md
@@ -104,7 +104,6 @@ All features except those listed in the following table are supported.
|------------------------------------------------------------|--------|---------------------------------------------------------|
| Parameterized Derived Types | P | PDT with length type parameters is not supported. See [Proposal](ParameterizedDerivedTypes.md) |
| Assignment to allocatable | P | Assignment to whole allocatable in FORALL is not implemented |
-| The VOLATILE attribute | P | VOLATILE in procedure interfaces is not implemented |
| Asynchronous input/output | P | IO will happen synchronously |
| MIN/MAX extensions for CHARACTER | P | Some variants are not supported |
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 9396d956e2233..b356f64553d7e 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -24,6 +24,8 @@ page](https://llvm.org/releases/).
## Major New Features
+* Initial support for VOLATILE variables and procedure interface arguments has been added.
+
## Bug Fixes
## Non-comprehensive list of changes in this release
diff --git a/flang/include/flang/Optimizer/Builder/BoxValue.h b/flang/include/flang/Optimizer/Builder/BoxValue.h
index 432a42264f7fc..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, fir::isa_volatile_type(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/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.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index cd5aa139b7391..0ba985641069b 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -2755,7 +2755,7 @@ def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoMemoryEffect]> {
let assemblyFormat = "`(` $symbol `)` attr-dict `:` type($resTy)";
}
-def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [NoMemoryEffect]> {
+def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [Pure]> {
let summary = "cast between volatile and non-volatile types";
let description = [{
Cast between volatile and non-volatile types. The types must be otherwise
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 7b76845b5af05..72c63e4e314d2 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);
@@ -3732,10 +3733,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
builder->createMinusOneInteger(loc, builder->getIndexType())};
mlir::Value baseAddr =
hlfir::genVariableRawAddress(loc, *builder, selector);
+ const bool isVolatile = fir::isa_volatile_type(selector.getType());
mlir::Type eleType =
fir::unwrapSequenceType(fir::unwrapRefType(baseAddr.getType()));
- mlir::Type rank1Type =
- fir::ReferenceType::get(builder->getVarLenSeqTy(eleType, 1));
+ mlir::Type rank1Type = fir::ReferenceType::get(
+ builder->getVarLenSeqTy(eleType, 1), isVolatile);
baseAddr = builder->createConvert(loc, rank1Type, baseAddr);
if (selector.isCharacter()) {
mlir::Value len = hlfir::genCharLength(loc, *builder, selector);
@@ -3755,7 +3757,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(selector.getType()));
mlir::Type newBoxType = boxTy.getBoxTypeWithNewShape(rank);
if (fir::isa_ref_type(selector.getType()))
- newBoxType = fir::ReferenceType::get(newBoxType);
+ newBoxType = fir::ReferenceType::get(
+ newBoxType, fir::isa_volatile_type(selector.getType()));
// Give rank info to value via cast, and get rid of the box if not needed
// (simple scalars, contiguous arrays... This is done by
// translateVariableToExtendedValue).
@@ -5491,8 +5494,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// return, PassBy::AddressAndLength should be retired.
mlir::Location loc = toLocation();
fir::factory::CharacterExprHelper charHelp{*builder, loc};
- mlir::Value box =
- charHelp.createEmboxChar(arg.firArgument, arg.firLength);
+ mlir::Value casted =
+ builder->createVolatileCast(loc, false, arg.firArgument);
+ mlir::Value box = charHelp.createEmboxChar(casted, arg.firLength);
mapBlockArgToDummyOrResult(arg.entity->get(), box, isResult);
} else {
if (arg.entity.has_value()) {
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 f28778ce6c1c9..a5b85e25b1af0 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -1369,7 +1369,10 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
// it according to the interface.
mlir::Value addr;
if (mlir::isa<fir::BoxCharType>(dummyTypeWithActualRank)) {
- addr = hlfir::genVariableBoxChar(loc, builder, entity);
+ // Cast the argument to match the volatility of the dummy argument.
+ auto nonVolatileEntity = hlfir::Entity{builder.createVolatileCast(
+ loc, fir::isa_volatile_type(dummyType), entity)};
+ addr = hlfir::genVariableBoxChar(loc, builder, nonVolatileEntity);
} else if (mlir::isa<fir::BaseBoxType>(dummyTypeWithActualRank)) {
entity = hlfir::genVariableBox(loc, builder, entity);
// Ensures the box has the right attributes and that it holds an
diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 2d61c2ee8dd8e..f3430bfa3021e 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -2705,7 +2705,7 @@ class ScalarExprLowering {
mlir::isa<fir::BoxCharType>(funcTy.getResult(0))) {
auto boxTy =
mlir::cast<fir::BoxCharType>(funcTy.getResult(0));
- mlir::Value ref = builder.createConvert(
+ mlir::Value ref = builder.createConvertWithVolatileCast(
loc, builder.getRefType(boxTy.getEleTy()), x.getAddr());
auto len = builder.create<fir::UndefOp>(
loc, builder.getCharacterLengthType());
@@ -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);
}
@@ -7013,7 +7016,8 @@ class ArrayExprLowering {
components.resetExtendCoorRef();
auto ptrEleTy = fir::PointerType::get(eleTy);
auto ptrAddr = builder.createConvert(loc, ptrEleTy, addr);
- auto boxTy = fir::BoxType::get(ptrEleTy);
+ auto boxTy = fir::BoxType::get(
+ ptrEleTy, fir::isa_volatile_type(addr.getType()));
// FIXME: The typeparams to the load may be
diff erent than those of
// the subobject.
if (components.hasExtendCoorRef())
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index ba0a3e7f816b7..a3be50ac072d4 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -204,6 +204,7 @@ class HlfirDesignatorBuilder {
!partInfo.resultShape)
partInfo.resultShape =
hlfir::genShape(getLoc(), getBuilder(), *partInfo.base);
+
// Dynamic type of polymorphic base must be kept if the designator is
// polymorphic.
if (isPolymorphic(designatorNode))
@@ -215,7 +216,25 @@ class HlfirDesignatorBuilder {
return fir::BoxCharType::get(charType.getContext(), charType.getFKind());
// When volatile is enabled, enable volatility on the designatory type.
- const bool isVolatile = false;
+ bool isVolatile = false;
+
+ // 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;
+ } else if constexpr (std::is_same_v<std::decay_t<T>,
+ Fortran::evaluate::ArrayRef>) {
+ if (designatorNode.base().GetLastSymbol().attrs().test(
+ Fortran::semantics::Attr::VOLATILE))
+ isVolatile = true;
+ } else if constexpr (std::is_same_v<std::decay_t<T>,
+ Fortran::evaluate::Component>) {
+ if (designatorNode.GetLastSymbol().attrs().test(
+ Fortran::semantics::Attr::VOLATILE))
+ isVolatile = true;
+ }
// Arrays with non default lower bounds or dynamic length or dynamic extent
// need a fir.box to hold the dynamic or lower bound information.
@@ -230,6 +249,12 @@ class HlfirDesignatorBuilder {
/*namedConstantSectionsAreAlwaysContiguous=*/false))
return fir::BoxType::get(resultValueType, isVolatile);
+ // 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);
+ }
+
// Other designators can be handled as raw addresses.
return fir::ReferenceType::get(resultValueType, isVolatile);
}
@@ -441,7 +466,10 @@ class HlfirDesignatorBuilder {
// hlfir.designate result will be a pointer/allocatable.
PartInfo partInfo;
mlir::Type componentType = visitComponentImpl(component, partInfo).second;
- mlir::Type designatorType = fir::ReferenceType::get(componentType);
+ const auto isVolatile =
+ fir::isa_volatile_type(partInfo.base.value().getBase().getType());
+ mlir::Type designatorType =
+ fir::ReferenceType::get(componentType, isVolatile);
fir::FortranVariableFlagsAttr attributes =
Fortran::lower::translateSymbolAttributes(getBuilder().getContext(),
component.GetLastSymbol());
diff --git a/flang/lib/Lower/HostAssociations.cpp b/flang/lib/Lower/HostAssociations.cpp
index ab6e76902b466..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);
}
diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index d98f669496d6c..63a612d7ead61 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -836,7 +836,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
diff ers
+ 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/Character.cpp b/flang/lib/Optimizer/Builder/Character.cpp
index 844630996ccb2..cd7ffd27117d3 100644
--- a/flang/lib/Optimizer/Builder/Character.cpp
+++ b/flang/lib/Optimizer/Builder/Character.cpp
@@ -271,7 +271,9 @@ fir::factory::CharacterExprHelper::createElementAddr(mlir::Value buffer,
auto extent = fir::SequenceType::getUnknownExtent();
if (charTy.getLen() != fir::CharacterType::unknownLen())
extent = charTy.getLen();
- auto coorTy = builder.getRefType(fir::SequenceType::get({extent}, singleTy));
+ const bool isVolatile = fir::isa_volatile_type(buffer.getType());
+ auto sequenceType = fir::SequenceType::get({extent}, singleTy);
+ auto coorTy = builder.getRefType(sequenceType, isVolatile);
auto coor = builder.createConvert(loc, coorTy, buffer);
auto i = builder.createConvert(loc, builder.getIndexType(), index);
@@ -330,6 +332,8 @@ void fir::factory::CharacterExprHelper::createCopy(
// If the src and dest are the same KIND, then use memmove to move the bits.
// We don't have to worry about overlapping ranges with memmove.
if (getCharacterKind(dest.getBuffer().getType()) == kind) {
+ const bool isVolatile = fir::isa_volatile_type(fromBuff.getType()) ||
+ fir::isa_volatile_type(toBuff.getType());
auto bytes = builder.getKindMap().getCharacterBitsize(kind) / 8;
auto i64Ty = builder.getI64Type();
auto kindBytes = builder.createIntegerConstant(loc, i64Ty, bytes);
@@ -341,7 +345,7 @@ void fir::factory::CharacterExprHelper::createCopy(
auto toPtr = builder.createConvert(loc, llvmPointerType, toBuff);
auto fromPtr = builder.createConvert(loc, llvmPointerType, fromBuff);
builder.create<mlir::LLVM::MemmoveOp>(loc, toPtr, fromPtr, totalBytes,
- /*isVolatile=*/false);
+ isVolatile);
return;
}
diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index 3cf9b5ae72d9e..1d6e1502ed0f9 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -615,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);
}
diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
index 558ebcb876ddb..51ea7305d3d26 100644
--- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -16,6 +16,7 @@
#include "flang/Optimizer/Builder/MutableBox.h"
#include "flang/Optimizer/Builder/Runtime/Allocatable.h"
#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "mlir/IR/IRMapping.h"
#include "mlir/Support/LLVM.h"
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 662ec8e30a56c..e534cfa5591c6 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3556,7 +3556,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
@@ -3595,6 +3597,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);
@@ -3605,10 +3610,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/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 21cedb1030896..8a24608336495 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1529,7 +1529,14 @@ bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
llvm::LogicalResult fir::ConvertOp::verify() {
mlir::Type inType = getValue().getType();
mlir::Type outType = getType();
- if (fir::isa_volatile_type(inType) != fir::isa_volatile_type(outType))
+ // If we're converting to an LLVM pointer type or an integer, we don't
+ // need to check for volatility mismatch - volatility will be handled by the
+ // memory operations themselves in llvm code generation and ptr-to-int can't
+ // represent volatility.
+ const bool toLLVMPointer = mlir::isa<mlir::LLVM::LLVMPointerType>(outType);
+ const bool toInteger = fir::isa_integer(outType);
+ if (fir::isa_volatile_type(inType) != fir::isa_volatile_type(outType) &&
+ !toLLVMPointer && !toInteger)
return emitOpError("cannot convert between volatile and non-volatile "
"types, use fir.volatile_cast instead ")
<< inType << " / " << outType;
@@ -1830,6 +1837,29 @@ llvm::LogicalResult fir::TypeInfoOp::verify() {
// EmboxOp
//===----------------------------------------------------------------------===//
+// Conversions from reference types to box types must preserve volatility.
+static llvm::LogicalResult
+verifyEmboxOpVolatilityInvariants(mlir::Type memrefType,
+ mlir::Type resultType) {
+ mlir::Type boxElementType =
+ llvm::TypeSwitch<mlir::Type, mlir::Type>(resultType)
+ .Case<fir::BoxType, fir::ClassType>(
+ [&](auto type) { return type.getEleTy(); })
+ .Default([&](mlir::Type type) { return type; });
+
+ // If the embox is simply wrapping a non-volatile type into a volatile box,
+ // we're not losing any volatility information.
+ if (boxElementType == memrefType) {
+ return mlir::success();
+ }
+
+ // Otherwise, the volatility of the input and result must match.
+ const bool volatilityMatches =
+ fir::isa_volatile_type(memrefType) == fir::isa_volatile_type(resultType);
+
+ return mlir::success(volatilityMatches);
+}
+
llvm::LogicalResult fir::EmboxOp::verify() {
auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());
bool isArray = false;
@@ -1859,10 +1889,11 @@ llvm::LogicalResult fir::EmboxOp::verify() {
return emitOpError("slice must not be provided for a scalar");
if (getSourceBox() && !mlir::isa<fir::ClassType>(getResult().getType()))
return emitOpError("source_box must be used with fir.class result type");
- if (fir::isa_volatile_type(getMemref().getType()) !=
- fir::isa_volatile_type(getResult().getType()))
- return emitOpError("cannot convert between volatile and non-volatile "
- "types, use fir.volatile_cast instead");
+ if (failed(verifyEmboxOpVolatilityInvariants(getMemref().getType(),
+ getResult().getType())))
+ return emitOpError(
+ "cannot convert between volatile and non-volatile types:")
+ << " " << getMemref().getType() << " " << getResult().getType();
return mlir::success();
}
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index b76856d72a017..1e6e95393c2f7 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) {
@@ -1419,8 +1420,13 @@ 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, fir::ClassType>(
+ [&](auto t) -> mlir::Type {
+ using FIRT = decltype(t);
+ return FIRT::get(changeTypeShape(t.getEleTy(), newShape),
+ t.isVolatile());
+ })
+ .Case<fir::PointerType, fir::HeapType>([&](auto t) -> mlir::Type {
using FIRT = decltype(t);
return FIRT::get(changeTypeShape(t.getEleTy(), newShape));
})
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 79e7ba8459c25..c5ed76753ea0c 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());
@@ -95,7 +96,7 @@ static llvm::LogicalResult areMatchingTypes(Op &op, mlir::Type type1,
}
//===----------------------------------------------------------------------===//
-// DeclareOp
+// AssignOp
//===----------------------------------------------------------------------===//
/// Is this a fir.[ref/ptr/heap]<fir.[box/class]<fir.heap<T>>> type?
@@ -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(),
@@ -204,6 +207,34 @@ static bool hasExplicitLowerBounds(mlir::Value shape) {
mlir::isa<fir::ShapeShiftType, fir::ShiftType>(shape.getType());
}
+static std::pair<mlir::Type, mlir::Value> updateDeclareInputTypeWithVolatility(
+ mlir::Type inputType, mlir::Value memref, mlir::OpBuilder &builder,
+ fir::FortranVariableFlagsAttr fortran_attrs) {
+ if (mlir::isa<fir::BoxType, fir::ReferenceType>(inputType) && fortran_attrs &&
+ bitEnumContainsAny(fortran_attrs.getFlags(),
+ fir::FortranVariableFlagsEnum::fortran_volatile)) {
+ const bool isPointer = bitEnumContainsAny(
+ fortran_attrs.getFlags(), fir::FortranVariableFlagsEnum::pointer);
+ auto updateType = [&](auto t) {
+ using FIRT = decltype(t);
+ // If an entity is a pointer, the entity it points to is volatile, as far
+ // as consumers of the pointer are concerned.
+ auto elementType = t.getEleTy();
+ const bool elementTypeIsVolatile =
+ isPointer || fir::isa_volatile_type(elementType);
+ auto newEleTy =
+ fir::updateTypeWithVolatility(elementType, elementTypeIsVolatile);
+ inputType = FIRT::get(newEleTy, true);
+ };
+ llvm::TypeSwitch<mlir::Type>(inputType)
+ .Case<fir::ReferenceType, fir::BoxType>(updateType)
+ .Default([](mlir::Type t) { return t; });
+ memref =
+ builder.create<fir::VolatileCastOp>(memref.getLoc(), inputType, memref);
+ }
+ return std::make_pair(inputType, memref);
+}
+
void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
mlir::OperationState &result, mlir::Value memref,
llvm::StringRef uniq_name, mlir::Value shape,
@@ -214,6 +245,8 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
auto nameAttr = builder.getStringAttr(uniq_name);
mlir::Type inputType = memref.getType();
bool hasExplicitLbs = hasExplicitLowerBounds(shape);
+ std::tie(inputType, memref) = updateDeclareInputTypeWithVolatility(
+ inputType, memref, builder, fortran_attrs);
mlir::Type hlfirVariableType =
getHLFIRVariableType(inputType, hasExplicitLbs);
build(builder, result, {hlfirVariableType, inputType}, memref, shape,
@@ -390,6 +423,12 @@ llvm::LogicalResult hlfir::DesignateOp::verify() {
unsigned outputRank = 0;
mlir::Type outputElementType;
bool hasBoxComponent;
+ if (fir::isa_volatile_type(memrefType) !=
+ fir::isa_volatile_type(getResult().getType())) {
+ return emitOpError("volatility mismatch between memref and result type")
+ << " memref type: " << memrefType
+ << " result type: " << getResult().getType();
+ }
if (getComponent()) {
auto component = getComponent().value();
auto recType = mlir::dyn_cast<fir::RecordType>(baseElementType);
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index c5bd8b30d5214..8721a895b5e05 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -421,6 +421,7 @@ class DesignateOpConversion
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);
@@ -443,10 +444,11 @@ 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);
+ const bool isVolatile = fir::isa_volatile_type(designateResultType) ||
+ fir::isa_volatile_type(base.getType());
mlir::Type baseEleTy = hlfir::getFortranElementType(base.getType());
mlir::Type resultEleTy = hlfir::getFortranElementType(designateResultType);
@@ -468,6 +470,7 @@ class DesignateOpConversion
mlir::cast<fir::RecordType>(baseEleTy).getType(
designate.getComponent().value());
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>(
@@ -566,15 +569,19 @@ class DesignateOpConversion
builder.create<fir::SliceOp>(loc, triples, sliceFields, substring);
else
assert(sliceFields.empty() && substring.empty());
- llvm::SmallVector<mlir::Type> resultType{designateResultType};
+
+ llvm::SmallVector<mlir::Type> resultType{
+ fir::updateTypeWithVolatility(designateResultType, isVolatile)};
+
mlir::Value resultBox;
- if (mlir::isa<fir::BaseBoxType>(base.getType()))
+ if (mlir::isa<fir::BaseBoxType>(base.getType())) {
resultBox =
builder.create<fir::ReboxOp>(loc, resultType, base, shape, slice);
- else
+ } else {
resultBox =
builder.create<fir::EmboxOp>(loc, resultType, base, shape, slice,
firBaseTypeParameters, sourceBox);
+ }
rewriter.replaceOp(designate, resultBox);
return mlir::success();
}
@@ -585,7 +592,8 @@ class DesignateOpConversion
mlir::Type resultAddressType = designateResultType;
if (auto boxCharType =
mlir::dyn_cast<fir::BoxCharType>(designateResultType))
- resultAddressType = fir::ReferenceType::get(boxCharType.getEleTy());
+ resultAddressType =
+ fir::ReferenceType::get(boxCharType.getEleTy(), isVolatile);
// Array element indexing.
if (!designate.getIndices().empty()) {
@@ -609,7 +617,8 @@ class DesignateOpConversion
assert(!mlir::isa<fir::SequenceType>(designateResultType));
auto index = builder.createIntegerConstant(loc, builder.getIndexType(),
*designate.getComplexPart());
- auto coorTy = fir::ReferenceType::get(resultEleTy);
+ auto coorTy = fir::ReferenceType::get(resultEleTy, isVolatile);
+
base = builder.create<fir::CoordinateOp>(loc, coorTy, base, index);
}
@@ -619,9 +628,11 @@ class DesignateOpConversion
"must have character length");
auto emboxChar = builder.create<fir::EmboxCharOp>(
loc, designateResultType, base, designate.getTypeparams()[0]);
+
rewriter.replaceOp(designate, emboxChar.getResult());
} else {
base = builder.createConvert(loc, designateResultType, base);
+
rewriter.replaceOp(designate, base);
}
return mlir::success();
diff --git a/flang/test/Fir/cse.fir b/flang/test/Fir/cse.fir
index 590a9681f7405..bc1e4995bb7e4 100644
--- a/flang/test/Fir/cse.fir
+++ b/flang/test/Fir/cse.fir
@@ -75,3 +75,39 @@ func.func @fun(%arg0: !fir.ref<i64, volatile>) -> i64 {
// CHECK: fir.store %[[VAL_3]] to %arg0 : !fir.ref<i64, volatile>
// CHECK: return %[[VAL_3]] : i64
// CHECK: }
+
+// -----
+
+// Check that volatile hlfir assignments are PRESERVED.
+func.func @_QPdot_product2(%arg0: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "lhs"}, %arg1: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "rhs"}, %arg2: !fir.ref<!fir.logical<4>> {fir.bindc_name = "res"}) {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.volatile_cast %arg0 : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> !fir.box<!fir.array<?x!fir.logical<4>>, volatile>
+ %2:2 = hlfir.declare %1 dummy_scope %0 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFdot_product2Elhs"} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>)
+ %3 = fir.volatile_cast %arg2 : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>, volatile>
+ %4:2 = hlfir.declare %3 dummy_scope %0 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFdot_product2Eres"} : (!fir.ref<!fir.logical<4>, volatile>, !fir.dscope) -> (!fir.ref<!fir.logical<4>, volatile>, !fir.ref<!fir.logical<4>, volatile>)
+ %5 = fir.volatile_cast %arg1 : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> !fir.box<!fir.array<?x!fir.logical<4>>, volatile>
+ %6:2 = hlfir.declare %5 dummy_scope %0 {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFdot_product2Erhs"} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>)
+ %7 = hlfir.dot_product %2#0 %6#0 {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>) -> !fir.logical<4>
+ hlfir.assign %7 to %4#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
+ %8 = hlfir.dot_product %2#0 %6#0 {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>) -> !fir.logical<4>
+ hlfir.assign %8 to %4#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
+ return
+}
+
+// CHECK-LABEL: func.func @_QPdot_product2(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "lhs"},
+// CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "rhs"},
+// CHECK-SAME: %[[VAL_2:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "res"}) {
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> !fir.box<!fir.array<?x!fir.logical<4>>, volatile>
+// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFdot_product2Elhs"} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>)
+// CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_2]] : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>, volatile>
+// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFdot_product2Eres"} : (!fir.ref<!fir.logical<4>, volatile>, !fir.dscope) -> (!fir.ref<!fir.logical<4>, volatile>, !fir.ref<!fir.logical<4>, volatile>)
+// CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> !fir.box<!fir.array<?x!fir.logical<4>>, volatile>
+// CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFdot_product2Erhs"} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>)
+// CHECK: %[[VAL_10:.*]] = hlfir.dot_product %[[VAL_5]]#0 %[[VAL_9]]#0 {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>) -> !fir.logical<4>
+// CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
+// CHECK: %[[VAL_11:.*]] = hlfir.dot_product %[[VAL_5]]#0 %[[VAL_9]]#0 {fastmath = #arith.fastmath<contract>} : (!fir.box<!fir.array<?x!fir.logical<4>>, volatile>, !fir.box<!fir.array<?x!fir.logical<4>>, volatile>) -> !fir.logical<4>
+// CHECK: hlfir.assign %[[VAL_11]] to %[[VAL_7]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>, volatile>
+// CHECK: return
+// CHECK: }
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/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
new file mode 100644
index 0000000000000..453413a93af44
--- /dev/null
+++ b/flang/test/HLFIR/volatile.fir
@@ -0,0 +1,86 @@
+// 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-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 private @_QFPassign_
diff erent_length(%arg0: !fir.boxchar<1> {fir.bindc_name = "string"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+ %c2 = arith.constant 2 : index
+ %c3 = arith.constant 3 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+ %2 = fir.convert %1#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,3>>
+ %3 = fir.volatile_cast %2 : (!fir.ref<!fir.char<1,3>>) -> !fir.ref<!fir.char<1,3>, volatile>
+ %4:2 = hlfir.declare %3 typeparams %c3 dummy_scope %0 {fortran_attrs = #fir.var_attrs<intent_inout, volatile>, uniq_name = "_QFFassign_
diff erent_lengthEstring"} : (!fir.ref<!fir.char<1,3>, volatile>, index, !fir.dscope) -> (!fir.ref<!fir.char<1,3>, volatile>, !fir.ref<!fir.char<1,3>, volatile>)
+ %5 = fir.address_of(@_QQclX626F) : !fir.ref<!fir.char<1,2>>
+ %6:2 = hlfir.declare %5 typeparams %c2 {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX626F"} : (!fir.ref<!fir.char<1,2>>, index) -> (!fir.ref<!fir.char<1,2>>, !fir.ref<!fir.char<1,2>>)
+ hlfir.assign %6#0 to %4#0 : !fir.ref<!fir.char<1,2>>, !fir.ref<!fir.char<1,3>, volatile>
+ return
+}
+// CHECK-LABEL: func.func private @_QFPassign_
diff erent_length(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.boxchar<1> {fir.bindc_name = "string"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+// CHECK: %[[VAL_1:.*]] = arith.constant 2 : index
+// CHECK: %[[VAL_2:.*]] = arith.constant 3 : index
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_4:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,3>>
+// CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref<!fir.char<1,3>>) -> !fir.ref<!fir.char<1,3>, volatile>
+// CHECK: %[[VAL_7:.*]] = fir.declare %[[VAL_6]] typeparams %[[VAL_2]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<intent_inout, volatile>, uniq_name = "_QFFassign_
diff erent_lengthEstring"} : (!fir.ref<!fir.char<1,3>, volatile>, index, !fir.dscope) -> !fir.ref<!fir.char<1,3>, volatile>
+// CHECK: %[[VAL_8:.*]] = fir.address_of(@_QQclX626F) : !fir.ref<!fir.char<1,2>>
+// CHECK: %[[VAL_9:.*]] = fir.declare %[[VAL_8]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX626F"} : (!fir.ref<!fir.char<1,2>>, index) -> !fir.ref<!fir.char<1,2>>
+// CHECK: %[[VAL_10:.*]] = arith.cmpi slt, %[[VAL_2]], %[[VAL_1]] : index
+// CHECK: %[[VAL_11:.*]] = arith.select %[[VAL_10]], %[[VAL_2]], %[[VAL_1]] : index
+// CHECK: %[[VAL_12:.*]] = arith.constant 1 : i64
+// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_11]] : (index) -> i64
+// CHECK: %[[VAL_14:.*]] = arith.muli %[[VAL_12]], %[[VAL_13]] : i64
+// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<!fir.char<1,3>, volatile>) -> !llvm.ptr
+// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<!fir.char<1,2>>) -> !llvm.ptr
+// CHECK: "llvm.intr.memmove"(%[[VAL_15]], %[[VAL_16]], %[[VAL_14]]) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i64) -> ()
+// CHECK: %[[VAL_17:.*]] = arith.constant 1 : index
+// CHECK: %[[VAL_18:.*]] = arith.subi %[[VAL_2]], %[[VAL_17]] : index
+// CHECK: %[[VAL_19:.*]] = arith.constant 32 : i8
+// CHECK: %[[VAL_20:.*]] = fir.undefined !fir.char<1>
+// CHECK: %[[VAL_21:.*]] = fir.insert_value %[[VAL_20]], %[[VAL_19]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1>
+// CHECK: %[[VAL_22:.*]] = arith.constant 1 : index
+// CHECK: fir.do_loop %[[VAL_23:.*]] = %[[VAL_11]] to %[[VAL_18]] step %[[VAL_22]] {
+// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<!fir.char<1,3>, volatile>) -> !fir.ref<!fir.array<3x!fir.char<1>>, volatile>
+// CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_24]], %[[VAL_23]] : (!fir.ref<!fir.array<3x!fir.char<1>>, volatile>, index) -> !fir.ref<!fir.char<1>>
+// CHECK: fir.store %[[VAL_21]] to %[[VAL_25]] : !fir.ref<!fir.char<1>>
+// CHECK: }
+// CHECK: return
+// CHECK: }
diff --git a/flang/test/Lower/volatile-openmp.f90 b/flang/test/Lower/volatile-openmp.f90
new file mode 100644
index 0000000000000..3269af9618f10
--- /dev/null
+++ b/flang/test/Lower/volatile-openmp.f90
@@ -0,0 +1,53 @@
+! RUN: bbc -fopenmp %s -o - | FileCheck %s
+type t
+ integer, pointer :: array(:)
+end type
+integer, volatile, pointer :: array1(:)
+type(t), volatile :: container
+!$omp target enter data map(to: container%array)
+!$omp target enter data map(to: array1)
+end
+
+! CHECK-LABEL: func.func @_QQmain() {
+! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_1:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : index
+! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QFE.n.array) : !fir.ref<!fir.char<1,5>>
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] typeparams %[[VAL_2]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFE.n.array"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QFE.n.t) : !fir.ref<!fir.char<1>>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFE.n.t"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
+! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QFEarray1) : !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:.*]]:2 = hlfir.declare %[[VAL_9]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEarray1"} : (!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_11:.*]] = fir.address_of(@_QFEcontainer) : !fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>
+! CHECK: %[[VAL_12:.*]] = fir.volatile_cast %[[VAL_11]] : (!fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>
+! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEcontainer"} : (!fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>) -> (!fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>, !fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>)
+! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFE.c.t) : !fir.ref<!fir.array<1x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>
+! CHECK: %[[VAL_15:.*]] = fir.shape_shift %[[VAL_0]], %[[VAL_1]] : (index, index) -> !fir.shapeshift<1>
+! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_14]](%[[VAL_15]]) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFE.c.t"} : (!fir.ref<!fir.array<1x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.shapeshift<1>) -> (!fir.box<!fir.array<1x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.ref<!fir.array<1x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>)
+! CHECK: %[[VAL_17:.*]] = fir.address_of(@_QFE.dt.t) : !fir.ref<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>
+! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFE.dt.t"} : (!fir.ref<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>) -> (!fir.ref<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>, !fir.ref<!fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>}>>>>,name:!fir.box<!fir.ptr<!fir.char<1,?>>>,sizeinbytes:i64,uninstantiated:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,kindparameter:!fir.box<!fir.ptr<!fir.array<?xi64>>>,lenparameterkind:!fir.box<!fir.ptr<!fir.array<?xi8>>>,component:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box<!fir.ptr<!fir.type<_QM__fortran_type_infoTderivedtype>>>,lenvalue:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,bounds:!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTprocptrcomponent{name:!fir.box<!fir.ptr<!fir.char<1,?>>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QM__fortran_type_infoTspecialbinding{which:i8,isargdescriptorset:i8,istypebound:i8,isargcontiguousset:i8,__padding0:!fir.array<4xi8>,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,__padding0:!fir.array<4xi8>}>>)
+! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_13]]#0{"array"} {fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>
+! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>
+! CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_20]], %[[VAL_0]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
+! CHECK: %[[VAL_22:.*]] = arith.subi %[[VAL_21]]#1, %[[VAL_1]] : index
+! CHECK: %[[VAL_23:.*]] = omp.map.bounds lower_bound(%[[VAL_0]] : index) upper_bound(%[[VAL_22]] : index) extent(%[[VAL_21]]#1 : index) stride(%[[VAL_21]]#2 : index) start_idx(%[[VAL_21]]#0 : index) {stride_in_bytes = true}
+! CHECK: %[[VAL_24:.*]] = fir.coordinate_of %[[VAL_13]]#0, array : (!fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_25:.*]] = fir.box_offset %[[VAL_24]] base_addr : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+! CHECK: %[[VAL_26:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_25]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) bounds(%[[VAL_23]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
+! CHECK: %[[VAL_27:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.box<!fir.ptr<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> {name = "container%[[VAL_28:.*]]"}
+! CHECK: %[[VAL_29:.*]] = omp.map.info var_ptr(%[[VAL_13]]#1 : !fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>, !fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>) map_clauses(to) capture(ByRef) members(%[[VAL_27]], %[[VAL_26]] : [0], [0, 0] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile> {name = "container", partial_map = true}
+! CHECK: omp.target_enter_data map_entries(%[[VAL_29]], %[[VAL_27]], %[[VAL_26]] : !fir.ref<!fir.type<_QFTt{array:!fir.box<!fir.ptr<!fir.array<?xi32>>>}>, volatile>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>)
+! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_31:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_32:.*]]:3 = fir.box_dims %[[VAL_31]], %[[VAL_0]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, index) -> (index, index, index)
+! CHECK: %[[VAL_33:.*]]:3 = fir.box_dims %[[VAL_30]], %[[VAL_0]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, index) -> (index, index, index)
+! CHECK: %[[VAL_34:.*]] = arith.subi %[[VAL_33]]#1, %[[VAL_1]] : index
+! CHECK: %[[VAL_35:.*]] = omp.map.bounds lower_bound(%[[VAL_0]] : index) upper_bound(%[[VAL_34]] : index) extent(%[[VAL_33]]#1 : index) stride(%[[VAL_33]]#2 : index) start_idx(%[[VAL_32]]#0 : index) {stride_in_bytes = true}
+! CHECK: %[[VAL_36:.*]] = fir.box_offset %[[VAL_10]]#1 base_addr : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+! CHECK: %[[VAL_37:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_36]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) bounds(%[[VAL_35]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
+! CHECK: %[[VAL_38:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>) map_clauses(to) capture(ByRef) members(%[[VAL_37]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile> {name = "array1"}
+! CHECK: omp.target_enter_data map_entries(%[[VAL_38]], %[[VAL_37]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>)
+! CHECK: return
+! CHECK: }
diff --git a/flang/test/Lower/volatile-string.f90 b/flang/test/Lower/volatile-string.f90
new file mode 100644
index 0000000000000..9173268880ace
--- /dev/null
+++ b/flang/test/Lower/volatile-string.f90
@@ -0,0 +1,116 @@
+! RUN: bbc %s -o - | FileCheck %s
+program p
+ character(3), volatile :: string = 'foo'
+ character(3) :: nonvolatile_string
+ integer :: i
+ call assign_same_length(string)
+ call assign_
diff erent_length(string)
+ i = index(string, 'o')
+ i = len(string)
+ string = adjustl(string)
+ nonvolatile_string = trim(string)
+ nonvolatile_string = string
+contains
+ subroutine assign_same_length(x)
+ character(3), intent(inout), volatile :: x
+ x = 'bar'
+ end subroutine
+ subroutine assign_
diff erent_length(string)
+ character(3), intent(inout), volatile :: string
+ string = 'bo'
+ end subroutine
+end program
+
+! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 11 : i32
+! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant true
+! CHECK: %[[VAL_3:.*]] = arith.constant 10 : i32
+! CHECK: %[[VAL_4:.*]] = arith.constant 3 : i32
+! CHECK: %[[VAL_5:.*]] = arith.constant false
+! CHECK: %[[VAL_6:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_7:.*]] = arith.constant 3 : index
+! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>>
+! CHECK: %[[VAL_9:.*]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,3>>>
+! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
+! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_12:.*]] = fir.alloca !fir.char<1,3> {bindc_name = "nonvolatile_string", uniq_name = "_QFEnonvolatile_string"}
+! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] typeparams %[[VAL_7]] {uniq_name = "_QFEnonvolatile_string"} : (!fir.ref<!fir.char<1,3>>, index) -> (!fir.ref<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>)
+! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFEstring) : !fir.ref<!fir.char<1,3>>
+! CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_14]] : (!fir.ref<!fir.char<1,3>>) -> !fir.ref<!fir.char<1,3>, volatile>
+! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]] typeparams %[[VAL_7]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEstring"} : (!fir.ref<!fir.char<1,3>, volatile>, index) -> (!fir.ref<!fir.char<1,3>, volatile>, !fir.ref<!fir.char<1,3>, volatile>)
+! CHECK: %[[VAL_17:.*]] = fir.volatile_cast %[[VAL_16]]#0 : (!fir.ref<!fir.char<1,3>, volatile>) -> !fir.ref<!fir.char<1,3>>
+! CHECK: %[[VAL_18:.*]] = fir.emboxchar %[[VAL_17]], %[[VAL_7]] : (!fir.ref<!fir.char<1,3>>, index) -> !fir.boxchar<1>
+! CHECK: fir.call @_QFPassign_same_length(%[[VAL_18]]) fastmath<contract> : (!fir.boxchar<1>) -> ()
+! CHECK: fir.call @_QFPassign_
diff erent_length(%[[VAL_18]]) fastmath<contract> : (!fir.boxchar<1>) -> ()
+! CHECK: %[[VAL_19:.*]] = fir.address_of(@_QQclX6F) : !fir.ref<!fir.char<1>>
+! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]] typeparams %[[VAL_6]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX6F"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
+! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<!fir.char<1,3>>) -> !fir.ref<i8>
+! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_7]] : (index) -> i64
+! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_20]]#0 : (!fir.ref<!fir.char<1>>) -> !fir.ref<i8>
+! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_6]] : (index) -> i64
+! CHECK: %[[VAL_25:.*]] = fir.call @_FortranAIndex1(%[[VAL_21]], %[[VAL_22]], %[[VAL_23]], %[[VAL_24]], %[[VAL_5]]) fastmath<contract> : (!fir.ref<i8>, i64, !fir.ref<i8>, i64, i1) -> i64
+! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i64) -> i32
+! CHECK: hlfir.assign %[[VAL_26]] to %[[VAL_11]]#0 : i32, !fir.ref<i32>
+! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_11]]#0 : i32, !fir.ref<i32>
+! CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_16]]#0 : (!fir.ref<!fir.char<1,3>, volatile>) -> !fir.box<!fir.char<1,3>, volatile>
+! CHECK: %[[VAL_28:.*]] = fir.zero_bits !fir.heap<!fir.char<1,3>>
+! CHECK: %[[VAL_29:.*]] = fir.embox %[[VAL_28]] : (!fir.heap<!fir.char<1,3>>) -> !fir.box<!fir.heap<!fir.char<1,3>>>
+! CHECK: fir.store %[[VAL_29]] to %[[VAL_9]] : !fir.ref<!fir.box<!fir.heap<!fir.char<1,3>>>>
+! CHECK: %[[VAL_30:.*]] = fir.address_of(
+! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,3>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK: %[[VAL_32:.*]] = fir.volatile_cast %[[VAL_27]] : (!fir.box<!fir.char<1,3>, volatile>) -> !fir.box<!fir.char<1,3>>
+! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.box<!fir.char<1,3>>) -> !fir.box<none>
+! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_30]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! CHECK: fir.call @_FortranAAdjustl(%[[VAL_31]], %[[VAL_33]], %[[VAL_34]], %[[VAL_3]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_9]] : !fir.ref<!fir.box<!fir.heap<!fir.char<1,3>>>>
+! CHECK: %[[VAL_36:.*]] = fir.box_elesize %[[VAL_35]] : (!fir.box<!fir.heap<!fir.char<1,3>>>) -> index
+! CHECK: %[[VAL_37:.*]] = fir.box_addr %[[VAL_35]] : (!fir.box<!fir.heap<!fir.char<1,3>>>) -> !fir.heap<!fir.char<1,3>>
+! CHECK: %[[VAL_38:.*]]:2 = hlfir.declare %[[VAL_37]] typeparams %[[VAL_36]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap<!fir.char<1,3>>, index) -> (!fir.heap<!fir.char<1,3>>, !fir.heap<!fir.char<1,3>>)
+! CHECK: %[[VAL_39:.*]] = hlfir.as_expr %[[VAL_38]]#0 move %[[VAL_2]] : (!fir.heap<!fir.char<1,3>>, i1) -> !hlfir.expr<!fir.char<1,3>>
+! CHECK: hlfir.assign %[[VAL_39]] to %[[VAL_16]]#0 : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>, volatile>
+! CHECK: hlfir.destroy %[[VAL_39]] : !hlfir.expr<!fir.char<1,3>>
+! CHECK: %[[VAL_40:.*]] = fir.zero_bits !fir.heap<!fir.char<1,?>>
+! CHECK: %[[VAL_41:.*]] = fir.embox %[[VAL_40]] typeparams %[[VAL_1]] : (!fir.heap<!fir.char<1,?>>, index) -> !fir.box<!fir.heap<!fir.char<1,?>>>
+! CHECK: fir.store %[[VAL_41]] to %[[VAL_8]] : !fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>>
+! CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK: fir.call @_FortranATrim(%[[VAL_42]], %[[VAL_33]], %[[VAL_34]], %[[VAL_0]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> ()
+! CHECK: %[[VAL_43:.*]] = fir.load %[[VAL_8]] : !fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>>
+! CHECK: %[[VAL_44:.*]] = fir.box_elesize %[[VAL_43]] : (!fir.box<!fir.heap<!fir.char<1,?>>>) -> index
+! CHECK: %[[VAL_45:.*]] = fir.box_addr %[[VAL_43]] : (!fir.box<!fir.heap<!fir.char<1,?>>>) -> !fir.heap<!fir.char<1,?>>
+! CHECK: %[[VAL_46:.*]]:2 = hlfir.declare %[[VAL_45]] typeparams %[[VAL_44]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.heap<!fir.char<1,?>>)
+! CHECK: %[[VAL_47:.*]] = hlfir.as_expr %[[VAL_46]]#0 move %[[VAL_2]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.assign %[[VAL_47]] to %[[VAL_13]]#0 : !hlfir.expr<!fir.char<1,?>>, !fir.ref<!fir.char<1,3>>
+! CHECK: hlfir.destroy %[[VAL_47]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.assign %[[VAL_16]]#0 to %[[VAL_13]]#0 : !fir.ref<!fir.char<1,3>, volatile>, !fir.ref<!fir.char<1,3>>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPassign_same_length(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.boxchar<1> {fir.bindc_name = "x"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 3 : index
+! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_3:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,3>>
+! CHECK: %[[VAL_5:.*]] = fir.volatile_cast %[[VAL_4]] : (!fir.ref<!fir.char<1,3>>) -> !fir.ref<!fir.char<1,3>, volatile>
+! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_1]] dummy_scope %[[VAL_2]] {fortran_attrs = #fir.var_attrs<intent_inout, volatile>, uniq_name = "_QFFassign_same_lengthEx"} : (!fir.ref<!fir.char<1,3>, volatile>, index, !fir.dscope) -> (!fir.ref<!fir.char<1,3>, volatile>, !fir.ref<!fir.char<1,3>, volatile>)
+! CHECK: %[[VAL_7:.*]] = fir.address_of(@_QQclX626172) : !fir.ref<!fir.char<1,3>>
+! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX626172"} : (!fir.ref<!fir.char<1,3>>, index) -> (!fir.ref<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>)
+! CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_6]]#0 : !fir.ref<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>, volatile>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPassign_
diff erent_length(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.boxchar<1> {fir.bindc_name = "string"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 2 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 3 : index
+! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_4:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,3>>
+! CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref<!fir.char<1,3>>) -> !fir.ref<!fir.char<1,3>, volatile>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_2]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<intent_inout, volatile>, uniq_name = "_QFFassign_
diff erent_lengthEstring"} : (!fir.ref<!fir.char<1,3>, volatile>, index, !fir.dscope) -> (!fir.ref<!fir.char<1,3>, volatile>, !fir.ref<!fir.char<1,3>, volatile>)
+! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QQclX626F) : !fir.ref<!fir.char<1,2>>
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX626F"} : (!fir.ref<!fir.char<1,2>>, index) -> (!fir.ref<!fir.char<1,2>>, !fir.ref<!fir.char<1,2>>)
+! CHECK: hlfir.assign %[[VAL_9]]#0 to %[[VAL_7]]#0 : !fir.ref<!fir.char<1,2>>, !fir.ref<!fir.char<1,3>, volatile>
+! CHECK: return
+! CHECK: }
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..dee6642e82593
--- /dev/null
+++ b/flang/test/Lower/volatile3.f90
@@ -0,0 +1,268 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+! Test that all combinations of volatile pointer and target are properly lowered -
+! note that a volatile pointer implies that the target is volatile, even if not specified
+
+program p
+ integer, volatile :: volatile_integer, volatile_array(10), &
+ volatile_array_2d(10,10)
+ integer, volatile, pointer :: volatile_integer_pointer
+ integer :: nonvolatile_array(10)
+ integer, volatile, target :: volatile_integer_target, volatile_array_target(10)
+ integer, target :: nonvolatile_integer_target, nonvolatile_array_target(10)
+ integer, volatile, &
+ pointer, dimension(:) :: volatile_array_pointer
+ integer, pointer, dimension(:) :: nonvolatile_array_pointer
+
+ volatile_array_pointer => volatile_array_target
+ volatile_array_pointer => nonvolatile_array_target
+ volatile_array_pointer => null(volatile_array_pointer)
+ nonvolatile_array_pointer => volatile_array_target
+ nonvolatile_array_pointer => nonvolatile_array_target
+ volatile_integer_pointer => volatile_integer_target
+ volatile_integer_pointer => null(volatile_integer_pointer)
+
+ call sub_nonvolatile_array(volatile_array)
+ call sub_volatile_array_assumed_shape(volatile_array)
+ call sub_volatile_array(volatile_array)
+
+ call sub_volatile_array_assumed_shape(nonvolatile_array)
+ call sub_volatile_array(nonvolatile_array)
+
+ call sub_volatile_array_pointer(volatile_array_pointer)
+ call sub_volatile_array_pointer(nonvolatile_array_pointer)
+
+ call sub_volatile_array_assumed_shape(volatile_array(1:10:1))
+ call sub_volatile_array_assumed_shape_2d(volatile_array_2d(1:10:1,:))
+
+ call sub_select_rank(volatile_array)
+ call sub_select_rank(volatile_array_2d)
+contains
+ subroutine sub_nonvolatile_array(arr)
+ integer :: arr(10)
+ arr(1) = 5
+ end subroutine
+ subroutine sub_volatile_array_assumed_shape(arr)
+ integer, volatile, dimension(:) :: arr
+ arr(1) = 5
+ end subroutine
+ subroutine sub_volatile_array_assumed_shape_2d(arr)
+ integer, volatile, dimension(:,:) :: arr
+ arr(1,1) = 5
+ end subroutine
+ subroutine sub_volatile_array(arr)
+ integer, volatile, dimension(10) :: arr
+ arr(1) = 5
+ end subroutine
+ subroutine sub_volatile_array_pointer(arr)
+ integer, volatile, dimension(:), pointer :: arr
+ arr(1) = 5
+ end subroutine
+ subroutine sub_select_rank(arr)
+ integer, volatile :: arr(..)
+ select rank(arr)
+ rank(1)
+ arr(1) = 5
+ rank(4)
+ arr(1,1,1,1) = 5
+ end select
+ end subroutine
+end program
+
+
+! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "p"} {
+! CHECK: %[[VAL_0:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_3:.*]] = fir.alloca !fir.box<!fir.ptr<i32>, volatile>
+! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: %[[VAL_5:.*]] = fir.address_of(@_QFEnonvolatile_array) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_6]]) {uniq_name = "_QFEnonvolatile_array"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QFEnonvolatile_array_pointer) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFEnonvolatile_array_pointer"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QFEnonvolatile_array_target) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEnonvolatile_array_target"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+! CHECK: %[[VAL_12:.*]] = fir.address_of(@_QFEnonvolatile_integer_target) : !fir.ref<i32>
+! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFEnonvolatile_integer_target"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFEvolatile_array) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_14]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEvolatile_array"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_17:.*]] = fir.address_of(@_QFEvolatile_array_2d) : !fir.ref<!fir.array<10x10xi32>>
+! CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_2]], %[[VAL_2]] : (index, index) -> !fir.shape<2>
+! CHECK: %[[VAL_19:.*]] = fir.volatile_cast %[[VAL_17]] : (!fir.ref<!fir.array<10x10xi32>>) -> !fir.ref<!fir.array<10x10xi32>, volatile>
+! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]](%[[VAL_18]]) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEvolatile_array_2d"} : (!fir.ref<!fir.array<10x10xi32>, volatile>, !fir.shape<2>) -> (!fir.ref<!fir.array<10x10xi32>, volatile>, !fir.ref<!fir.array<10x10xi32>, volatile>)
+! CHECK: %[[VAL_21:.*]] = fir.address_of(@_QFEvolatile_array_pointer) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_22:.*]] = fir.volatile_cast %[[VAL_21]] : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_23:.*]]:2 = hlfir.declare %[[VAL_22]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEvolatile_array_pointer"} : (!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_24:.*]] = fir.address_of(@_QFEvolatile_array_target) : !fir.ref<!fir.array<10xi32>>
+! CHECK: %[[VAL_25:.*]] = fir.volatile_cast %[[VAL_24]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_25]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs<target, volatile>, uniq_name = "_QFEvolatile_array_target"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_27:.*]] = fir.alloca i32 {bindc_name = "volatile_integer", uniq_name = "_QFEvolatile_integer"}
+! CHECK: %[[VAL_28:.*]] = fir.volatile_cast %[[VAL_27]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_28]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFEvolatile_integer"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: %[[VAL_30:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "volatile_integer_pointer", uniq_name = "_QFEvolatile_integer_pointer"}
+! CHECK: %[[VAL_31:.*]] = fir.zero_bits !fir.ptr<i32>
+! CHECK: %[[VAL_32:.*]] = fir.embox %[[VAL_31]] : (!fir.ptr<i32>) -> !fir.box<!fir.ptr<i32>>
+! CHECK: fir.store %[[VAL_32]] to %[[VAL_30]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+! CHECK: %[[VAL_33:.*]] = fir.volatile_cast %[[VAL_30]] : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> !fir.ref<!fir.box<!fir.ptr<i32>, volatile>, volatile>
+! CHECK: %[[VAL_34:.*]]:2 = hlfir.declare %[[VAL_33]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFEvolatile_integer_pointer"} : (!fir.ref<!fir.box<!fir.ptr<i32>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.ptr<i32>, volatile>, volatile>, !fir.ref<!fir.box<!fir.ptr<i32>, volatile>, volatile>)
+! CHECK: %[[VAL_35:.*]] = fir.address_of(@_QFEvolatile_integer_target) : !fir.ref<i32>
+! CHECK: %[[VAL_36:.*]] = fir.volatile_cast %[[VAL_35]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_36]] {fortran_attrs = #fir.var_attrs<target, volatile>, uniq_name = "_QFEvolatile_integer_target"} : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK: %[[VAL_38:.*]] = fir.embox %[[VAL_26]]#0(%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_38]] to %[[VAL_23]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_39:.*]] = fir.embox %[[VAL_11]]#0(%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! CHECK: %[[VAL_40:.*]] = fir.volatile_cast %[[VAL_39]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_40]] to %[[VAL_23]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_41:.*]] = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+! CHECK: %[[VAL_42:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_43:.*]] = fir.embox %[[VAL_41]](%[[VAL_42]]) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_43]] to %[[VAL_4]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>>
+! CHECK: %[[VAL_44:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>>)
+! CHECK: %[[VAL_45:.*]] = fir.load %[[VAL_44]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>>
+! CHECK: %[[VAL_46:.*]]:3 = fir.box_dims %[[VAL_45]], %[[VAL_1]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, index) -> (index, index, index)
+! CHECK: %[[VAL_47:.*]] = fir.shift %[[VAL_46]]#0 : (index) -> !fir.shift<1>
+! CHECK: %[[VAL_48:.*]] = fir.rebox %[[VAL_45]](%[[VAL_47]]) : (!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, !fir.shift<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>
+! CHECK: fir.store %[[VAL_48]] to %[[VAL_23]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_49:.*]] = fir.volatile_cast %[[VAL_38]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! CHECK: fir.store %[[VAL_49]] to %[[VAL_9]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: fir.store %[[VAL_39]] to %[[VAL_9]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+! CHECK: %[[VAL_50:.*]] = fir.embox %[[VAL_37]]#0 : (!fir.ref<i32, volatile>) -> !fir.box<!fir.ptr<i32>, volatile>
+! CHECK: fir.store %[[VAL_50]] to %[[VAL_34]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>, volatile>, volatile>
+! CHECK: %[[VAL_51:.*]] = fir.embox %[[VAL_31]] : (!fir.ptr<i32>) -> !fir.box<!fir.ptr<i32>, volatile>
+! CHECK: fir.store %[[VAL_51]] to %[[VAL_3]] : !fir.ref<!fir.box<!fir.ptr<i32>, volatile>>
+! CHECK: %[[VAL_52:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<!fir.box<!fir.ptr<i32>, volatile>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>, volatile>>, !fir.ref<!fir.box<!fir.ptr<i32>, volatile>>)
+! CHECK: %[[VAL_53:.*]] = fir.load %[[VAL_52]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>, volatile>>
+! CHECK: %[[VAL_54:.*]] = fir.box_addr %[[VAL_53]] : (!fir.box<!fir.ptr<i32>, volatile>) -> !fir.ptr<i32>
+! CHECK: %[[VAL_55:.*]] = fir.embox %[[VAL_54]] : (!fir.ptr<i32>) -> !fir.box<!fir.ptr<i32>>
+! CHECK: %[[VAL_56:.*]] = fir.volatile_cast %[[VAL_55]] : (!fir.box<!fir.ptr<i32>>) -> !fir.box<!fir.ptr<i32>, volatile>
+! CHECK: fir.store %[[VAL_56]] to %[[VAL_34]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>, volatile>, volatile>
+! CHECK: %[[VAL_57:.*]] = fir.volatile_cast %[[VAL_16]]#0 : (!fir.ref<!fir.array<10xi32>, volatile>) -> !fir.ref<!fir.array<10xi32>>
+! CHECK: fir.call @_QFPsub_nonvolatile_array(%[[VAL_57]]) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+! CHECK: %[[VAL_58:.*]] = fir.embox %[[VAL_16]]#0(%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_59:.*]] = fir.volatile_cast %[[VAL_58]] : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+! CHECK: %[[VAL_60:.*]] = fir.convert %[[VAL_59]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<?xi32>>
+! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape(%[[VAL_60]]) fastmath<contract> : (!fir.box<!fir.array<?xi32>>) -> ()
+! CHECK: fir.call @_QFPsub_volatile_array(%[[VAL_57]]) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+! CHECK: %[[VAL_61:.*]] = fir.embox %[[VAL_7]]#0(%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
+! CHECK: %[[VAL_62:.*]] = fir.convert %[[VAL_61]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<?xi32>>
+! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape(%[[VAL_62]]) fastmath<contract> : (!fir.box<!fir.array<?xi32>>) -> ()
+! CHECK: fir.call @_QFPsub_volatile_array(%[[VAL_7]]#0) fastmath<contract> : (!fir.ref<!fir.array<10xi32>>) -> ()
+! CHECK: %[[VAL_63:.*]] = fir.convert %[[VAL_23]]#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 @_QFPsub_volatile_array_pointer(%[[VAL_63]]) fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> ()
+! CHECK: %[[VAL_64:.*]] = fir.volatile_cast %[[VAL_9]]#0 : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>
+! CHECK: fir.call @_QFPsub_volatile_array_pointer(%[[VAL_64]]) fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>, volatile>) -> ()
+! CHECK: %[[VAL_65:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_0]]:%[[VAL_2]]:%[[VAL_0]]) shape %[[VAL_6]] : (!fir.ref<!fir.array<10xi32>, volatile>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_66:.*]] = fir.embox %[[VAL_65]](%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_67:.*]] = fir.volatile_cast %[[VAL_66]] : (!fir.box<!fir.array<10xi32>, volatile>) -> !fir.box<!fir.array<10xi32>>
+! CHECK: %[[VAL_68:.*]] = fir.convert %[[VAL_67]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<?xi32>>
+! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape(%[[VAL_68]]) fastmath<contract> : (!fir.box<!fir.array<?xi32>>) -> ()
+! CHECK: %[[VAL_69:.*]] = hlfir.designate %[[VAL_20]]#0 (%[[VAL_0]]:%[[VAL_2]]:%[[VAL_0]], %[[VAL_0]]:%[[VAL_2]]:%[[VAL_0]]) shape %[[VAL_18]] : (!fir.ref<!fir.array<10x10xi32>, volatile>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box<!fir.array<10x10xi32>, volatile>
+! CHECK: %[[VAL_70:.*]] = fir.volatile_cast %[[VAL_69]] : (!fir.box<!fir.array<10x10xi32>, volatile>) -> !fir.box<!fir.array<10x10xi32>>
+! CHECK: %[[VAL_71:.*]] = fir.convert %[[VAL_70]] : (!fir.box<!fir.array<10x10xi32>>) -> !fir.box<!fir.array<?x?xi32>>
+! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape_2d(%[[VAL_71]]) fastmath<contract> : (!fir.box<!fir.array<?x?xi32>>) -> ()
+! CHECK: %[[VAL_72:.*]] = fir.convert %[[VAL_59]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<!fir.array<*:i32>>
+! CHECK: fir.call @_QFPsub_select_rank(%[[VAL_72]]) fastmath<contract> : (!fir.box<!fir.array<*:i32>>) -> ()
+! CHECK: %[[VAL_73:.*]] = fir.embox %[[VAL_20]]#0(%[[VAL_18]]) : (!fir.ref<!fir.array<10x10xi32>, volatile>, !fir.shape<2>) -> !fir.box<!fir.array<10x10xi32>, volatile>
+! CHECK: %[[VAL_74:.*]] = fir.volatile_cast %[[VAL_73]] : (!fir.box<!fir.array<10x10xi32>, volatile>) -> !fir.box<!fir.array<10x10xi32>>
+! CHECK: %[[VAL_75:.*]] = fir.convert %[[VAL_74]] : (!fir.box<!fir.array<10x10xi32>>) -> !fir.box<!fir.array<*:i32>>
+! CHECK: fir.call @_QFPsub_select_rank(%[[VAL_75]]) fastmath<contract> : (!fir.box<!fir.array<*:i32>>) -> ()
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPsub_nonvolatile_array(
+! 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:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : i32
+! CHECK: %[[VAL_3:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_5]]) dummy_scope %[[VAL_4]] {uniq_name = "_QFFsub_nonvolatile_arrayEarr"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+! CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_1]]) : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.ref<i32>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPsub_volatile_array_assumed_shape(
+! 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:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : i32
+! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>, volatile>
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFsub_volatile_array_assumed_shapeEarr"} : (!fir.box<!fir.array<?xi32>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>, volatile>, !fir.box<!fir.array<?xi32>, volatile>)
+! CHECK: %[[VAL_6:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_1]]) : (!fir.box<!fir.array<?xi32>, volatile>, index) -> !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_6]] : i32, !fir.ref<i32, volatile>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPsub_volatile_array_assumed_shape_2d(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : i32
+! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.box<!fir.array<?x?xi32>>) -> !fir.box<!fir.array<?x?xi32>, volatile>
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFsub_volatile_array_assumed_shape_2dEarr"} : (!fir.box<!fir.array<?x?xi32>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<?x?xi32>, volatile>, !fir.box<!fir.array<?x?xi32>, volatile>)
+! CHECK: %[[VAL_6:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_1]], %[[VAL_1]]) : (!fir.box<!fir.array<?x?xi32>, volatile>, index, index) -> !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_6]] : i32, !fir.ref<i32, volatile>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPsub_volatile_array(
+! 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:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : i32
+! CHECK: %[[VAL_3:.*]] = arith.constant 10 : index
+! CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>, volatile>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) dummy_scope %[[VAL_4]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFsub_volatile_arrayEarr"} : (!fir.ref<!fir.array<10xi32>, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>, volatile>, !fir.ref<!fir.array<10xi32>, volatile>)
+! CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_1]]) : (!fir.ref<!fir.array<10xi32>, volatile>, index) -> !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_8]] : i32, !fir.ref<i32, volatile>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPsub_volatile_array_pointer(
+! 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:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : i32
+! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_4:.*]] = 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_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs<pointer, volatile>, uniq_name = "_QFFsub_volatile_array_pointerEarr"} : (!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: %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, volatile>
+! CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_6]] (%[[VAL_1]]) : (!fir.box<!fir.ptr<!fir.array<?xi32>>, volatile>, index) -> !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.ref<i32, volatile>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: func.func private @_QFPsub_select_rank(
+! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<*:i32>> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage<internal>} {
+! CHECK: %[[VAL_1:.*]] = arith.constant 1 : index
+! CHECK: %[[VAL_2:.*]] = arith.constant 5 : i32
+! CHECK: %[[VAL_3:.*]] = arith.constant 4 : i8
+! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i8
+! CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.box<!fir.array<*:i32>>) -> !fir.box<!fir.array<*:i32>, volatile>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] dummy_scope %[[VAL_5]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFsub_select_rankEarr"} : (!fir.box<!fir.array<*:i32>, volatile>, !fir.dscope) -> (!fir.box<!fir.array<*:i32>, volatile>, !fir.box<!fir.array<*:i32>, volatile>)
+! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_7]]#0 : (!fir.box<!fir.array<*:i32>, volatile>) -> !fir.box<!fir.array<*:i32>>
+! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.box<!fir.array<*:i32>>) -> !fir.box<none>
+! CHECK: %[[VAL_10:.*]] = fir.call @_FortranAIsAssumedSize(%[[VAL_9]]) : (!fir.box<none>) -> i1
+! CHECK: cf.cond_br %[[VAL_10]], ^bb4, ^bb1
+! CHECK: ^bb1:
+! CHECK: %[[VAL_11:.*]] = fir.box_rank %[[VAL_7]]#0 : (!fir.box<!fir.array<*:i32>, volatile>) -> i8
+! CHECK: fir.select_case %[[VAL_11]] : i8 [#fir.point, %[[VAL_4]], ^bb2, #fir.point, %[[VAL_3]], ^bb3, unit, ^bb4]
+! CHECK: ^bb2:
+! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.box<!fir.array<*:i32>, volatile>) -> !fir.box<!fir.array<?xi32>, volatile>
+! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFsub_select_rankEarr"} : (!fir.box<!fir.array<?xi32>, volatile>) -> (!fir.box<!fir.array<?xi32>, volatile>, !fir.box<!fir.array<?xi32>, volatile>)
+! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_13]]#0 (%[[VAL_1]]) : (!fir.box<!fir.array<?xi32>, volatile>, index) -> !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_14]] : i32, !fir.ref<i32, volatile>
+! CHECK: cf.br ^bb4
+! CHECK: ^bb3:
+! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.box<!fir.array<*:i32>, volatile>) -> !fir.box<!fir.array<?x?x?x?xi32>, volatile>
+! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]] {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFFsub_select_rankEarr"} : (!fir.box<!fir.array<?x?x?x?xi32>, volatile>) -> (!fir.box<!fir.array<?x?x?x?xi32>, volatile>, !fir.box<!fir.array<?x?x?x?xi32>, volatile>)
+! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_1]], %[[VAL_1]], %[[VAL_1]], %[[VAL_1]]) : (!fir.box<!fir.array<?x?x?x?xi32>, volatile>, index, index, index, index) -> !fir.ref<i32, volatile>
+! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_17]] : i32, !fir.ref<i32, volatile>
+! CHECK: cf.br ^bb4
+! CHECK: ^bb4:
+! CHECK: return
+! CHECK: }
diff --git a/flang/test/Lower/volatile4.f90 b/flang/test/Lower/volatile4.f90
new file mode 100644
index 0000000000000..42d7b68507b53
--- /dev/null
+++ b/flang/test/Lower/volatile4.f90
@@ -0,0 +1,92 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+program p
+ integer,volatile::i,arr(10)
+ integer,volatile,target::tgt(10)
+ integer,volatile,pointer,dimension(:)::ptr
+ i = loc(i)
+ 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: }
More information about the flang-commits
mailing list