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 void createArguments(llvm::SmallVectorImpl &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 void createArguments(llvm::SmallVectorImpl &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(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(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::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 or fir.ref - 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(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(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(funcTy.getResult(0))) { auto boxTy = mlir::cast(funcTy.getResult(0)); - mlir::Value ref = builder.createConvert( + mlir::Value ref = builder.createConvertWithVolatileCast( loc, builder.getRefType(boxTy.getEleTy()), x.getAddr()); auto len = builder.create( loc, builder.getCharacterLengthType()); @@ -6306,7 +6306,8 @@ class ArrayExprLowering { mlir::Value buffi = computeCoordinate(buff, off); llvm::SmallVector 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(loc, endOff, buffPos); @@ -6356,7 +6357,9 @@ class ArrayExprLowering { mlir::Value buffi = computeCoordinate(buff, off); llvm::SmallVector 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(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 different 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, + Fortran::evaluate::SymbolRef>) { + if (designatorNode.get().GetUltimate().attrs().test( + Fortran::semantics::Attr::VOLATILE)) + isVolatile = true; + } else if constexpr (std::is_same_v, + Fortran::evaluate::ArrayRef>) { + if (designatorNode.base().GetLastSymbol().attrs().test( + Fortran::semantics::Attr::VOLATILE)) + isVolatile = true; + } else if constexpr (std::is_same_v, + 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 { 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(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 differs + inputFuncArgs.push_back( + builder.createConvertWithVolatileCast(loc, argType, itemAddr)); fir::factory::CharacterExprHelper charHelper{builder, loc}; if (charHelper.isCharacterScalar(itemTy)) { mlir::Value len = fir::getLen(item); diff --git a/flang/lib/Optimizer/Builder/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(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(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 { 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(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 { 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 { mlir::LLVM::AliasAnalysisOpInterface newOp; if (copy.getNoOverlap()) newOp = rewriter.create( - loc, llvmDestination, llvmSource, copySize, /*isVolatile=*/false); + loc, llvmDestination, llvmSource, copySize, isVolatile); else newOp = rewriter.create( - 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(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(resultType) + .Case( + [&](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(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 TYPE parseIntSingleton(mlir::AsmParser &parser) { int kind = 0; @@ -91,6 +77,21 @@ bool verifySameLists(llvm::ArrayRef 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 lenPList, llvm::ArrayRef typeList) { @@ -1419,8 +1420,13 @@ changeTypeShape(mlir::Type type, return fir::SequenceType::get(*newShape, seqTy.getEleTy()); return seqTy.getEleTy(); }) - .Case([&](auto t) -> mlir::Type { + .Case( + [&](auto t) -> mlir::Type { + using FIRT = decltype(t); + return FIRT::get(changeTypeShape(t.getEleTy(), newShape), + t.isVolatile()); + }) + .Case([&](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]>> 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(shape.getType()); } +static std::pair updateDeclareInputTypeWithVolatility( + mlir::Type inputType, mlir::Value memref, mlir::OpBuilder &builder, + fir::FortranVariableFlagsAttr fortran_attrs) { + if (mlir::isa(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(inputType) + .Case(updateType) + .Default([](mlir::Type t) { return t; }); + memref = + builder.create(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(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( 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 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(baseEleTy).getType( designate.getComponent().value()); mlir::Type coorTy = fir::ReferenceType::get(componentType, isVolatile); + base = builder.create(loc, coorTy, base, fieldIndex); if (mlir::isa(componentType)) { auto variableInterface = mlir::cast( @@ -566,15 +569,19 @@ class DesignateOpConversion builder.create(loc, triples, sliceFields, substring); else assert(sliceFields.empty() && substring.empty()); - llvm::SmallVector resultType{designateResultType}; + + llvm::SmallVector resultType{ + fir::updateTypeWithVolatility(designateResultType, isVolatile)}; + mlir::Value resultBox; - if (mlir::isa(base.getType())) + if (mlir::isa(base.getType())) { resultBox = builder.create(loc, resultType, base, shape, slice); - else + } else { resultBox = builder.create(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(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(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(loc, coorTy, base, index); } @@ -619,9 +628,11 @@ class DesignateOpConversion "must have character length"); auto emboxChar = builder.create( 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 { // CHECK: fir.store %[[VAL_3]] to %arg0 : !fir.ref // CHECK: return %[[VAL_3]] : i64 // CHECK: } + +// ----- + +// Check that volatile hlfir assignments are PRESERVED. +func.func @_QPdot_product2(%arg0: !fir.box>> {fir.bindc_name = "lhs"}, %arg1: !fir.box>> {fir.bindc_name = "rhs"}, %arg2: !fir.ref> {fir.bindc_name = "res"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.volatile_cast %arg0 : (!fir.box>>) -> !fir.box>, volatile> + %2:2 = hlfir.declare %1 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFdot_product2Elhs"} : (!fir.box>, volatile>, !fir.dscope) -> (!fir.box>, volatile>, !fir.box>, volatile>) + %3 = fir.volatile_cast %arg2 : (!fir.ref>) -> !fir.ref, volatile> + %4:2 = hlfir.declare %3 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFdot_product2Eres"} : (!fir.ref, volatile>, !fir.dscope) -> (!fir.ref, volatile>, !fir.ref, volatile>) + %5 = fir.volatile_cast %arg1 : (!fir.box>>) -> !fir.box>, volatile> + %6:2 = hlfir.declare %5 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFdot_product2Erhs"} : (!fir.box>, volatile>, !fir.dscope) -> (!fir.box>, volatile>, !fir.box>, volatile>) + %7 = hlfir.dot_product %2#0 %6#0 {fastmath = #arith.fastmath} : (!fir.box>, volatile>, !fir.box>, volatile>) -> !fir.logical<4> + hlfir.assign %7 to %4#0 : !fir.logical<4>, !fir.ref, volatile> + %8 = hlfir.dot_product %2#0 %6#0 {fastmath = #arith.fastmath} : (!fir.box>, volatile>, !fir.box>, volatile>) -> !fir.logical<4> + hlfir.assign %8 to %4#0 : !fir.logical<4>, !fir.ref, volatile> + return +} + +// CHECK-LABEL: func.func @_QPdot_product2( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "lhs"}, +// CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "rhs"}, +// CHECK-SAME: %[[VAL_2:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref> {fir.bindc_name = "res"}) { +// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_0]] : (!fir.box>>) -> !fir.box>, volatile> +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFdot_product2Elhs"} : (!fir.box>, volatile>, !fir.dscope) -> (!fir.box>, volatile>, !fir.box>, volatile>) +// CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_2]] : (!fir.ref>) -> !fir.ref, volatile> +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFdot_product2Eres"} : (!fir.ref, volatile>, !fir.dscope) -> (!fir.ref, volatile>, !fir.ref, volatile>) +// CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_1]] : (!fir.box>>) -> !fir.box>, volatile> +// CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFdot_product2Erhs"} : (!fir.box>, volatile>, !fir.dscope) -> (!fir.box>, volatile>, !fir.box>, volatile>) +// CHECK: %[[VAL_10:.*]] = hlfir.dot_product %[[VAL_5]]#0 %[[VAL_9]]#0 {fastmath = #arith.fastmath} : (!fir.box>, volatile>, !fir.box>, volatile>) -> !fir.logical<4> +// CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : !fir.logical<4>, !fir.ref, volatile> +// CHECK: %[[VAL_11:.*]] = hlfir.dot_product %[[VAL_5]]#0 %[[VAL_9]]#0 {fastmath = #arith.fastmath} : (!fir.box>, volatile>, !fir.box>, volatile>) -> !fir.logical<4> +// CHECK: hlfir.assign %[[VAL_11]] to %[[VAL_7]]#0 : !fir.logical<4>, !fir.ref, 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.ref, 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, volatile> + %5 = fir.load %1 : !fir.ref, volatile> + fir.store %5 to %2 : !fir.ref> + %6 = fir.convert %true : (i1) -> !fir.logical<4> + fir.store %6 to %1 : !fir.ref, 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, volatile> + %c1 = arith.constant 1 : index + %c5_i32 = arith.constant 5 : i32 + %c10 = arith.constant 10 : index + %1 = fir.address_of(@_QFEa) : !fir.ref> + %2 = fir.volatile_cast %1 : (!fir.ref>) -> !fir.ref, volatile> + %3 = fir.address_of(@_QFEb) : !fir.ref> + %4 = fir.volatile_cast %3 : (!fir.ref>) -> !fir.ref, 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, volatile>, index, index) -> !fir.ref + fir.store %c5_i32 to %11 : !fir.ref + %12 = arith.addi %8, %c1 overflow : 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, volatile>, index) -> !fir.box, volatile> + %15 = fircg.ext_embox %2(%c10) : (!fir.ref, volatile>, index) -> !fir.box, volatile> + fir.store %15 to %0 : !fir.ref, volatile>> + %16 = fir.address_of(@_QQclX8b2af12247fe2a74a66d92bb35ca5038) : !fir.ref> + %c3_i32 = arith.constant 3 : i32 + %17 = fir.convert %0 : (!fir.ref, volatile>>) -> !fir.ref> + %18 = fir.volatile_cast %14 : (!fir.box, volatile>) -> !fir.box> + %19 = fir.convert %18 : (!fir.box>) -> !fir.box + %20 = fir.convert %16 : (!fir.ref>) -> !fir.ref + fir.call @_FortranAAssign(%17, %19, %20, %c3_i32) : (!fir.ref>, !fir.box, !fir.ref, 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, !fir.ref, 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.ref, volatile> + %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEa"} : (!fir.ref, volatile>) -> (!fir.ref, volatile>, !fir.ref, volatile>) + %3 = fir.alloca !fir.logical<4> {bindc_name = "b", uniq_name = "_QFEb"} + %4:2 = hlfir.declare %3 {uniq_name = "_QFEb"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + %5 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"} + %6:2 = hlfir.declare %5 {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %7 = fir.convert %false : (i1) -> !fir.logical<4> + hlfir.assign %7 to %2#0 : !fir.logical<4>, !fir.ref, volatile> + %8 = fir.load %2#0 : !fir.ref, volatile> + hlfir.assign %8 to %4#0 : !fir.logical<4>, !fir.ref> + %9 = fir.convert %true : (i1) -> !fir.logical<4> + hlfir.assign %9 to %2#0 : !fir.logical<4>, !fir.ref, 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.ref, volatile> +// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEa"} : (!fir.ref, volatile>) -> !fir.ref, 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.ref> +// CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"} +// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {uniq_name = "_QFEi"} : (!fir.ref) -> !fir.ref +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_1]] : (i1) -> !fir.logical<4> +// CHECK: fir.store %[[VAL_9]] to %[[VAL_4]] : !fir.ref, volatile> +// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_4]] : !fir.ref, volatile> +// CHECK: fir.store %[[VAL_10]] to %[[VAL_6]] : !fir.ref> +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (i1) -> !fir.logical<4> +// CHECK: fir.store %[[VAL_11]] to %[[VAL_4]] : !fir.ref, volatile> +// CHECK: return +// CHECK: } + +// ----- + +func.func private @_QFPassign_different_length(%arg0: !fir.boxchar<1> {fir.bindc_name = "string"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { + %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>, index) + %2 = fir.convert %1#0 : (!fir.ref>) -> !fir.ref> + %3 = fir.volatile_cast %2 : (!fir.ref>) -> !fir.ref, volatile> + %4:2 = hlfir.declare %3 typeparams %c3 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFassign_different_lengthEstring"} : (!fir.ref, volatile>, index, !fir.dscope) -> (!fir.ref, volatile>, !fir.ref, volatile>) + %5 = fir.address_of(@_QQclX626F) : !fir.ref> + %6:2 = hlfir.declare %5 typeparams %c2 {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX626F"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) + hlfir.assign %6#0 to %4#0 : !fir.ref>, !fir.ref, volatile> + return +} +// CHECK-LABEL: func.func private @_QFPassign_different_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} { +// 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>, index) +// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ref>) -> !fir.ref> +// CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref>) -> !fir.ref, volatile> +// CHECK: %[[VAL_7:.*]] = fir.declare %[[VAL_6]] typeparams %[[VAL_2]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFassign_different_lengthEstring"} : (!fir.ref, volatile>, index, !fir.dscope) -> !fir.ref, volatile> +// CHECK: %[[VAL_8:.*]] = fir.address_of(@_QQclX626F) : !fir.ref> +// CHECK: %[[VAL_9:.*]] = fir.declare %[[VAL_8]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX626F"} : (!fir.ref>, index) -> !fir.ref> +// 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, volatile>) -> !llvm.ptr +// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_9]] : (!fir.ref>) -> !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, volatile>) -> !fir.ref>, volatile> +// CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_24]], %[[VAL_23]] : (!fir.ref>, volatile>, index) -> !fir.ref> +// CHECK: fir.store %[[VAL_21]] to %[[VAL_25]] : !fir.ref> +// 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> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] typeparams %[[VAL_2]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFE.n.array"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QFE.n.t) : !fir.ref> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFE.n.t"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QFEarray1) : !fir.ref>>> +! CHECK: %[[VAL_9:.*]] = fir.volatile_cast %[[VAL_8]] : (!fir.ref>>>) -> !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEarray1"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %[[VAL_11:.*]] = fir.address_of(@_QFEcontainer) : !fir.ref>>}>> +! CHECK: %[[VAL_12:.*]] = fir.volatile_cast %[[VAL_11]] : (!fir.ref>>}>>) -> !fir.ref>>}>, volatile> +! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEcontainer"} : (!fir.ref>>}>, volatile>) -> (!fir.ref>>}>, volatile>, !fir.ref>>}>, volatile>) +! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFE.c.t) : !fir.ref>>,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,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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,value:i64}>>>>,bounds:!fir.box,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, uniq_name = "_QFE.c.t"} : (!fir.ref>>,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,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.shapeshift<1>) -> (!fir.box>>,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,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>, !fir.ref>>,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,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>) +! CHECK: %[[VAL_17:.*]] = fir.address_of(@_QFE.dt.t) : !fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,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>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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, uniq_name = "_QFE.dt.t"} : (!fir.ref,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,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>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,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>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,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>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,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} : (!fir.ref>>}>, volatile>) -> !fir.ref>>, volatile> +! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref>>, volatile> +! CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_20]], %[[VAL_0]] : (!fir.box>>, 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>>}>, volatile>) -> !fir.ref>>> +! CHECK: %[[VAL_25:.*]] = fir.box_offset %[[VAL_24]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +! CHECK: %[[VAL_26:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref>>>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_25]] : !fir.llvm_ptr>>) bounds(%[[VAL_23]]) -> !fir.llvm_ptr>> {name = ""} +! CHECK: %[[VAL_27:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "container%[[VAL_28:.*]]"} +! CHECK: %[[VAL_29:.*]] = omp.map.info var_ptr(%[[VAL_13]]#1 : !fir.ref>>}>, volatile>, !fir.type<_QFTt{array:!fir.box>>}>) map_clauses(to) capture(ByRef) members(%[[VAL_27]], %[[VAL_26]] : [0], [0, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>>}>, volatile> {name = "container", partial_map = true} +! CHECK: omp.target_enter_data map_entries(%[[VAL_29]], %[[VAL_27]], %[[VAL_26]] : !fir.ref>>}>, volatile>, !fir.ref>>>, !fir.llvm_ptr>>) +! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_31:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_32:.*]]:3 = fir.box_dims %[[VAL_31]], %[[VAL_0]] : (!fir.box>, volatile>, index) -> (index, index, index) +! CHECK: %[[VAL_33:.*]]:3 = fir.box_dims %[[VAL_30]], %[[VAL_0]] : (!fir.box>, 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>, volatile>, volatile>) -> !fir.llvm_ptr>> +! CHECK: %[[VAL_37:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref>, volatile>, volatile>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_36]] : !fir.llvm_ptr>>) bounds(%[[VAL_35]]) -> !fir.llvm_ptr>> {name = ""} +! CHECK: %[[VAL_38:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref>, volatile>, volatile>, !fir.box>, volatile>) map_clauses(to) capture(ByRef) members(%[[VAL_37]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>, volatile>, volatile> {name = "array1"} +! CHECK: omp.target_enter_data map_entries(%[[VAL_38]], %[[VAL_37]] : !fir.ref>, volatile>, volatile>, !fir.llvm_ptr>>) +! 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_different_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_different_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>> +! CHECK: %[[VAL_9:.*]] = fir.alloca !fir.box>> +! 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) -> (!fir.ref, !fir.ref) +! 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>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFEstring) : !fir.ref> +! CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_14]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]] typeparams %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEstring"} : (!fir.ref, volatile>, index) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_17:.*]] = fir.volatile_cast %[[VAL_16]]#0 : (!fir.ref, volatile>) -> !fir.ref> +! CHECK: %[[VAL_18:.*]] = fir.emboxchar %[[VAL_17]], %[[VAL_7]] : (!fir.ref>, index) -> !fir.boxchar<1> +! CHECK: fir.call @_QFPassign_same_length(%[[VAL_18]]) fastmath : (!fir.boxchar<1>) -> () +! CHECK: fir.call @_QFPassign_different_length(%[[VAL_18]]) fastmath : (!fir.boxchar<1>) -> () +! CHECK: %[[VAL_19:.*]] = fir.address_of(@_QQclX6F) : !fir.ref> +! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]] typeparams %[[VAL_6]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX6F"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_17]] : (!fir.ref>) -> !fir.ref +! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_7]] : (index) -> i64 +! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_20]]#0 : (!fir.ref>) -> !fir.ref +! 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 : (!fir.ref, i64, !fir.ref, i64, i1) -> i64 +! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i64) -> i32 +! CHECK: hlfir.assign %[[VAL_26]] to %[[VAL_11]]#0 : i32, !fir.ref +! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_11]]#0 : i32, !fir.ref +! CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_16]]#0 : (!fir.ref, volatile>) -> !fir.box, volatile> +! CHECK: %[[VAL_28:.*]] = fir.zero_bits !fir.heap> +! CHECK: %[[VAL_29:.*]] = fir.embox %[[VAL_28]] : (!fir.heap>) -> !fir.box>> +! CHECK: fir.store %[[VAL_29]] to %[[VAL_9]] : !fir.ref>>> +! CHECK: %[[VAL_30:.*]] = fir.address_of( +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_9]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[VAL_32:.*]] = fir.volatile_cast %[[VAL_27]] : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_30]] : (!fir.ref>) -> !fir.ref +! CHECK: fir.call @_FortranAAdjustl(%[[VAL_31]], %[[VAL_33]], %[[VAL_34]], %[[VAL_3]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> () +! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_9]] : !fir.ref>>> +! CHECK: %[[VAL_36:.*]] = fir.box_elesize %[[VAL_35]] : (!fir.box>>) -> index +! CHECK: %[[VAL_37:.*]] = fir.box_addr %[[VAL_35]] : (!fir.box>>) -> !fir.heap> +! CHECK: %[[VAL_38:.*]]:2 = hlfir.declare %[[VAL_37]] typeparams %[[VAL_36]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap>, index) -> (!fir.heap>, !fir.heap>) +! CHECK: %[[VAL_39:.*]] = hlfir.as_expr %[[VAL_38]]#0 move %[[VAL_2]] : (!fir.heap>, i1) -> !hlfir.expr> +! CHECK: hlfir.assign %[[VAL_39]] to %[[VAL_16]]#0 : !hlfir.expr>, !fir.ref, volatile> +! CHECK: hlfir.destroy %[[VAL_39]] : !hlfir.expr> +! CHECK: %[[VAL_40:.*]] = fir.zero_bits !fir.heap> +! CHECK: %[[VAL_41:.*]] = fir.embox %[[VAL_40]] typeparams %[[VAL_1]] : (!fir.heap>, index) -> !fir.box>> +! CHECK: fir.store %[[VAL_41]] to %[[VAL_8]] : !fir.ref>>> +! CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_8]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: fir.call @_FortranATrim(%[[VAL_42]], %[[VAL_33]], %[[VAL_34]], %[[VAL_0]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> () +! CHECK: %[[VAL_43:.*]] = fir.load %[[VAL_8]] : !fir.ref>>> +! CHECK: %[[VAL_44:.*]] = fir.box_elesize %[[VAL_43]] : (!fir.box>>) -> index +! CHECK: %[[VAL_45:.*]] = fir.box_addr %[[VAL_43]] : (!fir.box>>) -> !fir.heap> +! CHECK: %[[VAL_46:.*]]:2 = hlfir.declare %[[VAL_45]] typeparams %[[VAL_44]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.heap>, index) -> (!fir.boxchar<1>, !fir.heap>) +! CHECK: %[[VAL_47:.*]] = hlfir.as_expr %[[VAL_46]]#0 move %[[VAL_2]] : (!fir.boxchar<1>, i1) -> !hlfir.expr> +! CHECK: hlfir.assign %[[VAL_47]] to %[[VAL_13]]#0 : !hlfir.expr>, !fir.ref> +! CHECK: hlfir.destroy %[[VAL_47]] : !hlfir.expr> +! CHECK: hlfir.assign %[[VAL_16]]#0 to %[[VAL_13]]#0 : !fir.ref, volatile>, !fir.ref> +! 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} { +! 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>, index) +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_5:.*]] = fir.volatile_cast %[[VAL_4]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_1]] dummy_scope %[[VAL_2]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFassign_same_lengthEx"} : (!fir.ref, volatile>, index, !fir.dscope) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_7:.*]] = fir.address_of(@_QQclX626172) : !fir.ref> +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX626172"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_6]]#0 : !fir.ref>, !fir.ref, volatile> +! CHECK: return +! CHECK: } + +! CHECK-LABEL: func.func private @_QFPassign_different_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} { +! 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>, index) +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_6:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_2]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFassign_different_lengthEstring"} : (!fir.ref, volatile>, index, !fir.dscope) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QQclX626F) : !fir.ref> +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] typeparams %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX626F"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: hlfir.assign %[[VAL_9]]#0 to %[[VAL_7]]#0 : !fir.ref>, !fir.ref, 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> +! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_6]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_7]]) {{.+}} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"} +! CHECK: %[[VAL_11:.*]] = fir.volatile_cast %[[VAL_10]] : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {{.+}} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_13:.*]] = fir.volatile_cast %[[VAL_12]]#0 : (!fir.ref) -> !fir.ref +! CHECK: fir.call @_QFPnot_declared_volatile_in_this_scope(%[[VAL_13]]) proc_attrs fastmath : (!fir.ref) -> () +! 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, volatile>, index) -> !fir.ref +! CHECK: %[[VAL_18:.*]] = fir.volatile_cast %[[VAL_17]] : (!fir.ref) -> !fir.ref +! CHECK: fir.call @_QFPnot_declared_volatile_in_this_scope(%[[VAL_18]]) proc_attrs fastmath : (!fir.ref) -> () +! CHECK: %[[VAL_19:.*]] = arith.addi %[[VAL_14]], %[[VAL_4]] overflow : 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, volatile>) -> !fir.ref> +! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_23:.*]]:3 = hlfir.associate %[[VAL_3]] {adapt.valuebyref} : (i32) -> (!fir.ref, !fir.ref, i1) +! CHECK: fir.call @_QFPdeclared_volatile_in_this_scope(%[[VAL_22]], %[[VAL_23]]#0) fastmath : (!fir.ref>, !fir.ref) -> () +! CHECK: hlfir.end_associate %[[VAL_23]]#1, %[[VAL_23]]#2 : !fir.ref, i1 +! CHECK: %[[VAL_24:.*]] = fir.address_of +! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (!fir.ref>) -> !fir.ref +! CHECK: %[[VAL_26:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[VAL_2]], %[[VAL_25]], %[[VAL_1]]) fastmath {{.+}} : (i32, !fir.ref, i32) -> !fir.ref +! CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_9]]#0(%[[VAL_7]]) : (!fir.ref, volatile>, !fir.shape<1>) -> !fir.box, volatile> +! CHECK: %[[VAL_28:.*]] = fir.volatile_cast %[[VAL_27]] : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_30:.*]] = fir.call @_FortranAioOutputDescriptor(%[[VAL_26]], %[[VAL_29]]) fastmath {llvm.nocallback, llvm.nosync} : (!fir.ref, !fir.box) -> i1 +! CHECK: %[[VAL_31:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref +! CHECK: %[[VAL_32:.*]] = fir.call @_FortranAioOutputInteger32(%[[VAL_26]], %[[VAL_31]]) fastmath {{.+}} : (!fir.ref, i32) -> i1 +! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAioEndIoStatement(%[[VAL_26]]) fastmath {{.+}} : (!fir.ref) -> 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 {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, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_3]]#0 : i32, !fir.ref +! 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.bindc_name = "v"}, +! CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref {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, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! 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.ref, volatile> +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_10]]) dummy_scope %[[VAL_4]] {{.+}} : (!fir.ref, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.box, volatile>, !fir.ref, volatile>) +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_12]]#0 : i32, !fir.box, 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.ref +! CHECK: %[[VAL_4:.*]] = fir.call @_QFPa() fastmath : () -> i32 +! CHECK: %[[VAL_5:.*]] = fir.call @_QFPb() fastmath : () -> i32 +! CHECK: %[[VAL_6:.*]] = fir.call @_QFPc() fastmath : () -> 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) -> !fir.ref +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {{.+}} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : i32, !fir.ref +! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_3]]#0 : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref +! 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) -> !fir.ref +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {{.+}} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : i32, !fir.ref +! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_3]]#0 : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref +! 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) -> !fir.ref +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {{.+}} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : f32, !fir.ref +! CHECK: %[[VAL_4:.*]] = fir.volatile_cast %[[VAL_3]]#0 : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref +! 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, volatile> +! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.box>, volatile> +! CHECK: %[[VAL_5:.*]] = fir.address_of(@_QFEnonvolatile_array) : !fir.ref> +! 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.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QFEnonvolatile_array_pointer) : !fir.ref>>> +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEnonvolatile_array_pointer"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QFEnonvolatile_array_target) : !fir.ref> +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEnonvolatile_array_target"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_12:.*]] = fir.address_of(@_QFEnonvolatile_integer_target) : !fir.ref +! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEnonvolatile_integer_target"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_14:.*]] = fir.address_of(@_QFEvolatile_array) : !fir.ref> +! CHECK: %[[VAL_15:.*]] = fir.volatile_cast %[[VAL_14]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_array"} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_17:.*]] = fir.address_of(@_QFEvolatile_array_2d) : !fir.ref> +! 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.ref, volatile> +! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]](%[[VAL_18]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_array_2d"} : (!fir.ref, volatile>, !fir.shape<2>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_21:.*]] = fir.address_of(@_QFEvolatile_array_pointer) : !fir.ref>>> +! CHECK: %[[VAL_22:.*]] = fir.volatile_cast %[[VAL_21]] : (!fir.ref>>>) -> !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_23:.*]]:2 = hlfir.declare %[[VAL_22]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_array_pointer"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %[[VAL_24:.*]] = fir.address_of(@_QFEvolatile_array_target) : !fir.ref> +! CHECK: %[[VAL_25:.*]] = fir.volatile_cast %[[VAL_24]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_25]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_array_target"} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, 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) -> !fir.ref +! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_28]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_integer"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_30:.*]] = fir.alloca !fir.box> {bindc_name = "volatile_integer_pointer", uniq_name = "_QFEvolatile_integer_pointer"} +! CHECK: %[[VAL_31:.*]] = fir.zero_bits !fir.ptr +! CHECK: %[[VAL_32:.*]] = fir.embox %[[VAL_31]] : (!fir.ptr) -> !fir.box> +! CHECK: fir.store %[[VAL_32]] to %[[VAL_30]] : !fir.ref>> +! CHECK: %[[VAL_33:.*]] = fir.volatile_cast %[[VAL_30]] : (!fir.ref>>) -> !fir.ref, volatile>, volatile> +! CHECK: %[[VAL_34:.*]]:2 = hlfir.declare %[[VAL_33]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_integer_pointer"} : (!fir.ref, volatile>, volatile>) -> (!fir.ref, volatile>, volatile>, !fir.ref, volatile>, volatile>) +! CHECK: %[[VAL_35:.*]] = fir.address_of(@_QFEvolatile_integer_target) : !fir.ref +! CHECK: %[[VAL_36:.*]] = fir.volatile_cast %[[VAL_35]] : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_36]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEvolatile_integer_target"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_38:.*]] = fir.embox %[[VAL_26]]#0(%[[VAL_6]]) : (!fir.ref, volatile>, !fir.shape<1>) -> !fir.box>, volatile> +! CHECK: fir.store %[[VAL_38]] to %[[VAL_23]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_39:.*]] = fir.embox %[[VAL_11]]#0(%[[VAL_6]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box>> +! CHECK: %[[VAL_40:.*]] = fir.volatile_cast %[[VAL_39]] : (!fir.box>>) -> !fir.box>, volatile> +! CHECK: fir.store %[[VAL_40]] to %[[VAL_23]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_41:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_42:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_43:.*]] = fir.embox %[[VAL_41]](%[[VAL_42]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>, volatile> +! CHECK: fir.store %[[VAL_43]] to %[[VAL_4]] : !fir.ref>, volatile>> +! CHECK: %[[VAL_44:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref>, volatile>>) -> (!fir.ref>, volatile>>, !fir.ref>, volatile>>) +! CHECK: %[[VAL_45:.*]] = fir.load %[[VAL_44]]#0 : !fir.ref>, volatile>> +! CHECK: %[[VAL_46:.*]]:3 = fir.box_dims %[[VAL_45]], %[[VAL_1]] : (!fir.box>, 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>, volatile>, !fir.shift<1>) -> !fir.box>, volatile> +! CHECK: fir.store %[[VAL_48]] to %[[VAL_23]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_49:.*]] = fir.volatile_cast %[[VAL_38]] : (!fir.box>, volatile>) -> !fir.box>> +! CHECK: fir.store %[[VAL_49]] to %[[VAL_9]]#0 : !fir.ref>>> +! CHECK: fir.store %[[VAL_39]] to %[[VAL_9]]#0 : !fir.ref>>> +! CHECK: %[[VAL_50:.*]] = fir.embox %[[VAL_37]]#0 : (!fir.ref) -> !fir.box, volatile> +! CHECK: fir.store %[[VAL_50]] to %[[VAL_34]]#0 : !fir.ref, volatile>, volatile> +! CHECK: %[[VAL_51:.*]] = fir.embox %[[VAL_31]] : (!fir.ptr) -> !fir.box, volatile> +! CHECK: fir.store %[[VAL_51]] to %[[VAL_3]] : !fir.ref, volatile>> +! CHECK: %[[VAL_52:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref, volatile>>) -> (!fir.ref, volatile>>, !fir.ref, volatile>>) +! CHECK: %[[VAL_53:.*]] = fir.load %[[VAL_52]]#0 : !fir.ref, volatile>> +! CHECK: %[[VAL_54:.*]] = fir.box_addr %[[VAL_53]] : (!fir.box, volatile>) -> !fir.ptr +! CHECK: %[[VAL_55:.*]] = fir.embox %[[VAL_54]] : (!fir.ptr) -> !fir.box> +! CHECK: %[[VAL_56:.*]] = fir.volatile_cast %[[VAL_55]] : (!fir.box>) -> !fir.box, volatile> +! CHECK: fir.store %[[VAL_56]] to %[[VAL_34]]#0 : !fir.ref, volatile>, volatile> +! CHECK: %[[VAL_57:.*]] = fir.volatile_cast %[[VAL_16]]#0 : (!fir.ref, volatile>) -> !fir.ref> +! CHECK: fir.call @_QFPsub_nonvolatile_array(%[[VAL_57]]) fastmath : (!fir.ref>) -> () +! CHECK: %[[VAL_58:.*]] = fir.embox %[[VAL_16]]#0(%[[VAL_6]]) : (!fir.ref, volatile>, !fir.shape<1>) -> !fir.box, volatile> +! CHECK: %[[VAL_59:.*]] = fir.volatile_cast %[[VAL_58]] : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_60:.*]] = fir.convert %[[VAL_59]] : (!fir.box>) -> !fir.box> +! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape(%[[VAL_60]]) fastmath : (!fir.box>) -> () +! CHECK: fir.call @_QFPsub_volatile_array(%[[VAL_57]]) fastmath : (!fir.ref>) -> () +! CHECK: %[[VAL_61:.*]] = fir.embox %[[VAL_7]]#0(%[[VAL_6]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> +! CHECK: %[[VAL_62:.*]] = fir.convert %[[VAL_61]] : (!fir.box>) -> !fir.box> +! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape(%[[VAL_62]]) fastmath : (!fir.box>) -> () +! CHECK: fir.call @_QFPsub_volatile_array(%[[VAL_7]]#0) fastmath : (!fir.ref>) -> () +! CHECK: %[[VAL_63:.*]] = fir.convert %[[VAL_23]]#0 : (!fir.ref>, volatile>, volatile>) -> !fir.ref>>, volatile> +! CHECK: fir.call @_QFPsub_volatile_array_pointer(%[[VAL_63]]) fastmath : (!fir.ref>>, volatile>) -> () +! CHECK: %[[VAL_64:.*]] = fir.volatile_cast %[[VAL_9]]#0 : (!fir.ref>>>) -> !fir.ref>>, volatile> +! CHECK: fir.call @_QFPsub_volatile_array_pointer(%[[VAL_64]]) fastmath : (!fir.ref>>, volatile>) -> () +! CHECK: %[[VAL_65:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_0]]:%[[VAL_2]]:%[[VAL_0]]) shape %[[VAL_6]] : (!fir.ref, volatile>, index, index, index, !fir.shape<1>) -> !fir.ref, volatile> +! CHECK: %[[VAL_66:.*]] = fir.embox %[[VAL_65]](%[[VAL_6]]) : (!fir.ref, volatile>, !fir.shape<1>) -> !fir.box, volatile> +! CHECK: %[[VAL_67:.*]] = fir.volatile_cast %[[VAL_66]] : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_68:.*]] = fir.convert %[[VAL_67]] : (!fir.box>) -> !fir.box> +! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape(%[[VAL_68]]) fastmath : (!fir.box>) -> () +! 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, volatile>, index, index, index, index, index, index, !fir.shape<2>) -> !fir.box, volatile> +! CHECK: %[[VAL_70:.*]] = fir.volatile_cast %[[VAL_69]] : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_71:.*]] = fir.convert %[[VAL_70]] : (!fir.box>) -> !fir.box> +! CHECK: fir.call @_QFPsub_volatile_array_assumed_shape_2d(%[[VAL_71]]) fastmath : (!fir.box>) -> () +! CHECK: %[[VAL_72:.*]] = fir.convert %[[VAL_59]] : (!fir.box>) -> !fir.box> +! CHECK: fir.call @_QFPsub_select_rank(%[[VAL_72]]) fastmath : (!fir.box>) -> () +! CHECK: %[[VAL_73:.*]] = fir.embox %[[VAL_20]]#0(%[[VAL_18]]) : (!fir.ref, volatile>, !fir.shape<2>) -> !fir.box, volatile> +! CHECK: %[[VAL_74:.*]] = fir.volatile_cast %[[VAL_73]] : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_75:.*]] = fir.convert %[[VAL_74]] : (!fir.box>) -> !fir.box> +! CHECK: fir.call @_QFPsub_select_rank(%[[VAL_75]]) fastmath : (!fir.box>) -> () +! 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.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { +! 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.shape<1>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_1]]) : (!fir.ref>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.ref +! 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.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { +! 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.box, volatile> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_volatile_array_assumed_shapeEarr"} : (!fir.box, volatile>, !fir.dscope) -> (!fir.box, volatile>, !fir.box, volatile>) +! CHECK: %[[VAL_6:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_1]]) : (!fir.box, volatile>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_6]] : i32, !fir.ref +! 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.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { +! 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.box, volatile> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_volatile_array_assumed_shape_2dEarr"} : (!fir.box, volatile>, !fir.dscope) -> (!fir.box, volatile>, !fir.box, volatile>) +! CHECK: %[[VAL_6:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_1]], %[[VAL_1]]) : (!fir.box, volatile>, index, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_6]] : i32, !fir.ref +! 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.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { +! 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.ref, volatile> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) dummy_scope %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_volatile_arrayEarr"} : (!fir.ref, volatile>, !fir.shape<1>, !fir.dscope) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_1]]) : (!fir.ref, volatile>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_8]] : i32, !fir.ref +! 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>>, volatile> {fir.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { +! 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>>, volatile>) -> !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] dummy_scope %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_volatile_array_pointerEarr"} : (!fir.ref>, volatile>, volatile>, !fir.dscope) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_7:.*]] = hlfir.designate %[[VAL_6]] (%[[VAL_1]]) : (!fir.box>, volatile>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.ref +! 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.bindc_name = "arr"}) attributes {fir.host_symbol = @_QQmain, llvm.linkage = #llvm.linkage} { +! 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.box, volatile> +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] dummy_scope %[[VAL_5]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_select_rankEarr"} : (!fir.box, volatile>, !fir.dscope) -> (!fir.box, volatile>, !fir.box, volatile>) +! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_7]]#0 : (!fir.box, volatile>) -> !fir.box> +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.box>) -> !fir.box +! CHECK: %[[VAL_10:.*]] = fir.call @_FortranAIsAssumedSize(%[[VAL_9]]) : (!fir.box) -> i1 +! CHECK: cf.cond_br %[[VAL_10]], ^bb4, ^bb1 +! CHECK: ^bb1: +! CHECK: %[[VAL_11:.*]] = fir.box_rank %[[VAL_7]]#0 : (!fir.box, 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, volatile>) -> !fir.box, volatile> +! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_select_rankEarr"} : (!fir.box, volatile>) -> (!fir.box, volatile>, !fir.box, volatile>) +! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_13]]#0 (%[[VAL_1]]) : (!fir.box, volatile>, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_14]] : i32, !fir.ref +! CHECK: cf.br ^bb4 +! CHECK: ^bb3: +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.box, volatile>) -> !fir.box, volatile> +! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFFsub_select_rankEarr"} : (!fir.box, volatile>) -> (!fir.box, volatile>, !fir.box, volatile>) +! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_1]], %[[VAL_1]], %[[VAL_1]], %[[VAL_1]]) : (!fir.box, volatile>, index, index, index, index) -> !fir.ref +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_17]] : i32, !fir.ref +! 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> +! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_5:.*]] = fir.volatile_cast %[[VAL_3]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_4]]) {{.+}} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"} +! CHECK: %[[VAL_8:.*]] = fir.volatile_cast %[[VAL_7]] : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {{.+}} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QFEptr) : !fir.ref>>> +! CHECK: %[[VAL_11:.*]] = fir.volatile_cast %[[VAL_10]] : (!fir.ref>>>) -> !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {{.+}} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %[[VAL_13:.*]] = fir.address_of(@_QFEtgt) : !fir.ref> +! CHECK: %[[VAL_14:.*]] = fir.volatile_cast %[[VAL_13]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]](%[[VAL_4]]) {{.+}} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_16:.*]] = fir.alloca tuple> +! CHECK: %[[VAL_17:.*]] = fir.coordinate_of %[[VAL_16]], %[[VAL_1]] : (!fir.ref>>, i32) -> !fir.llvm_ptr> +! CHECK: %[[VAL_18:.*]] = fir.volatile_cast %[[VAL_9]]#0 : (!fir.ref) -> !fir.ref +! CHECK: fir.store %[[VAL_18]] to %[[VAL_17]] : !fir.llvm_ptr> +! CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_15]]#0(%[[VAL_4]]) : (!fir.ref, volatile>, !fir.shape<1>) -> !fir.box>, volatile> +! CHECK: fir.store %[[VAL_19]] to %[[VAL_12]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_9]]#0 : i32, !fir.ref +! CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 : i32, !fir.ref, volatile> +! CHECK: fir.call @_QFPhost_assoc(%[[VAL_16]]) fastmath : (!fir.ref>>) -> () +! 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>> {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> +! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_7:.*]] = fir.volatile_cast %[[VAL_5]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_6]]) {{.+}} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_9:.*]] = fir.address_of(@_QFEptr) : !fir.ref>>> +! CHECK: %[[VAL_10:.*]] = fir.volatile_cast %[[VAL_9]] : (!fir.ref>>>) -> !fir.ref>, volatile>, volatile> +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {{.+}} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %[[VAL_12:.*]] = fir.address_of(@_QFEtgt) : !fir.ref> +! CHECK: %[[VAL_13:.*]] = fir.volatile_cast %[[VAL_12]] : (!fir.ref>) -> !fir.ref, volatile> +! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_13]](%[[VAL_6]]) {{.+}} : (!fir.ref, volatile>, !fir.shape<1>) -> (!fir.ref, volatile>, !fir.ref, volatile>) +! CHECK: %[[VAL_15:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref>>, i32) -> !fir.llvm_ptr> +! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_15]] : !fir.llvm_ptr> +! CHECK: %[[VAL_17:.*]] = fir.volatile_cast %[[VAL_16]] : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {{.+}} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_14]]#0(%[[VAL_6]]) : (!fir.ref, volatile>, !fir.shape<1>) -> !fir.box>, volatile> +! CHECK: fir.store %[[VAL_19]] to %[[VAL_11]]#0 : !fir.ref>, volatile>, volatile> +! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_18]]#0 : i32, !fir.ref +! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_8]]#0 : i32, !fir.ref, 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>> { +! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_1:.*]] = fir.zero_bits !fir.ptr> +! CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]] : (index) -> !fir.shape<1> +! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_1]](%[[VAL_2]]) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> +! CHECK: fir.has_value %[[VAL_3]] : !fir.box>> +! 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: }