Skip to content

Commit 9bbc441

Browse files
ashermancinelliGeorgeARM
authored andcommitted
[flang] Add lowering of volatile references (llvm#132486)
[RFC on discourse](https://discourse.llvm.org/t/rfc-volatile-representation-in-flang/85404/1) Flang currently lacks support for volatile variables. For some cases, the compiler produces TODO error messages and others are ignored. Some of our tests are like the example from _C.4 Clause 8 notes: The VOLATILE attribute (8.5.20)_ and require volatile variables. Prior commits: ``` c9ec1bc [flang] Handle volatility in lowering and codegen (llvm#135311) e42f860 [flang][nfc] Support volatility in Fir ops (llvm#134858) b2711e1 [flang][nfc] Support volatile on ref, box, and class types (llvm#134386) ```
1 parent e01eb16 commit 9bbc441

32 files changed

+1092
-62
lines changed

flang/docs/FortranStandardsSupport.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ All features except those listed in the following table are supported.
104104
|------------------------------------------------------------|--------|---------------------------------------------------------|
105105
| Parameterized Derived Types | P | PDT with length type parameters is not supported. See [Proposal](ParameterizedDerivedTypes.md) |
106106
| Assignment to allocatable | P | Assignment to whole allocatable in FORALL is not implemented |
107-
| The VOLATILE attribute | P | VOLATILE in procedure interfaces is not implemented |
108107
| Asynchronous input/output | P | IO will happen synchronously |
109108
| MIN/MAX extensions for CHARACTER | P | Some variants are not supported |
110109

flang/docs/ReleaseNotes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ page](https://llvm.org/releases/).
2424

2525
## Major New Features
2626

27+
* Initial support for VOLATILE variables and procedure interface arguments has been added.
28+
2729
## Bug Fixes
2830

2931
## Non-comprehensive list of changes in this release

flang/include/flang/Optimizer/Builder/BoxValue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ class AbstractIrBox : public AbstractBox, public AbstractArrayBox {
236236
auto ty = getBoxTy().getEleTy();
237237
if (fir::isa_ref_type(ty))
238238
return ty;
239-
return fir::ReferenceType::get(ty, fir::isa_volatile_type(ty));
239+
return fir::ReferenceType::get(ty, fir::isa_volatile_type(getBoxTy()));
240240
}
241241

242242
/// Get the scalar type related to the described entity

flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,14 +829,16 @@ template <int N, typename A>
829829
void createArguments(llvm::SmallVectorImpl<mlir::Value> &result,
830830
fir::FirOpBuilder &builder, mlir::Location loc,
831831
mlir::FunctionType fTy, A arg) {
832-
result.emplace_back(builder.createConvert(loc, fTy.getInput(N), arg));
832+
result.emplace_back(
833+
builder.createConvertWithVolatileCast(loc, fTy.getInput(N), arg));
833834
}
834835

835836
template <int N, typename A, typename... As>
836837
void createArguments(llvm::SmallVectorImpl<mlir::Value> &result,
837838
fir::FirOpBuilder &builder, mlir::Location loc,
838839
mlir::FunctionType fTy, A arg, As... args) {
839-
result.emplace_back(builder.createConvert(loc, fTy.getInput(N), arg));
840+
result.emplace_back(
841+
builder.createConvertWithVolatileCast(loc, fTy.getInput(N), arg));
840842
createArguments<N + 1>(result, builder, loc, fTy, args...);
841843
}
842844
} // namespace helper

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2755,7 +2755,7 @@ def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoMemoryEffect]> {
27552755
let assemblyFormat = "`(` $symbol `)` attr-dict `:` type($resTy)";
27562756
}
27572757

2758-
def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [NoMemoryEffect]> {
2758+
def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [Pure]> {
27592759
let summary = "cast between volatile and non-volatile types";
27602760
let description = [{
27612761
Cast between volatile and non-volatile types. The types must be otherwise

flang/include/flang/Optimizer/Dialect/FIRType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,10 @@ inline mlir::Type wrapInClassOrBoxType(mlir::Type eleTy,
457457
return fir::BoxType::get(eleTy);
458458
}
459459

460+
/// Re-create the given type with the given volatility, if this is a type
461+
/// that can represent volatility.
462+
mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile);
463+
460464
/// Return the elementType where intrinsic types are replaced with none for
461465
/// unlimited polymorphic entities.
462466
///

flang/include/flang/Optimizer/Dialect/FIRTypes.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,11 @@ def fir_ReferenceType : FIR_Type<"Reference", "ref"> {
365365

366366
let description = [{
367367
The type of a reference to an entity in memory.
368+
369+
References can be volatile. Any ops taking an operand of a volatile
370+
reference must set their memory effects appropriately. Accesses of
371+
volatile references are currently modeled as read and write effects
372+
to a specific memory resource.
368373
}];
369374

370375
let parameters = (ins "mlir::Type":$eleTy, "bool":$isVolatile);

flang/lib/Lower/Bridge.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,7 +1755,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
17551755
// tags all result variables with one of the largest types to allow
17561756
// them to share the same storage. Convert this to the actual type.
17571757
if (resultRef.getType() != resultRefType)
1758-
resultRef = builder->createConvert(loc, resultRefType, resultRef);
1758+
resultRef = builder->createConvertWithVolatileCast(
1759+
loc, resultRefType, resultRef);
17591760
return builder->create<fir::LoadOp>(loc, resultRef);
17601761
});
17611762
genExitRoutine(false, resultVal);
@@ -3732,10 +3733,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
37323733
builder->createMinusOneInteger(loc, builder->getIndexType())};
37333734
mlir::Value baseAddr =
37343735
hlfir::genVariableRawAddress(loc, *builder, selector);
3736+
const bool isVolatile = fir::isa_volatile_type(selector.getType());
37353737
mlir::Type eleType =
37363738
fir::unwrapSequenceType(fir::unwrapRefType(baseAddr.getType()));
3737-
mlir::Type rank1Type =
3738-
fir::ReferenceType::get(builder->getVarLenSeqTy(eleType, 1));
3739+
mlir::Type rank1Type = fir::ReferenceType::get(
3740+
builder->getVarLenSeqTy(eleType, 1), isVolatile);
37393741
baseAddr = builder->createConvert(loc, rank1Type, baseAddr);
37403742
if (selector.isCharacter()) {
37413743
mlir::Value len = hlfir::genCharLength(loc, *builder, selector);
@@ -3755,7 +3757,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
37553757
mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(selector.getType()));
37563758
mlir::Type newBoxType = boxTy.getBoxTypeWithNewShape(rank);
37573759
if (fir::isa_ref_type(selector.getType()))
3758-
newBoxType = fir::ReferenceType::get(newBoxType);
3760+
newBoxType = fir::ReferenceType::get(
3761+
newBoxType, fir::isa_volatile_type(selector.getType()));
37593762
// Give rank info to value via cast, and get rid of the box if not needed
37603763
// (simple scalars, contiguous arrays... This is done by
37613764
// translateVariableToExtendedValue).
@@ -5491,8 +5494,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
54915494
// return, PassBy::AddressAndLength should be retired.
54925495
mlir::Location loc = toLocation();
54935496
fir::factory::CharacterExprHelper charHelp{*builder, loc};
5494-
mlir::Value box =
5495-
charHelp.createEmboxChar(arg.firArgument, arg.firLength);
5497+
mlir::Value casted =
5498+
builder->createVolatileCast(loc, false, arg.firArgument);
5499+
mlir::Value box = charHelp.createEmboxChar(casted, arg.firLength);
54965500
mapBlockArgToDummyOrResult(arg.entity->get(), box, isResult);
54975501
} else {
54985502
if (arg.entity.has_value()) {

flang/lib/Lower/CallInterface.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,10 +1111,7 @@ class Fortran::lower::CallInterfaceImpl {
11111111
addMLIRAttr(fir::getContiguousAttrName());
11121112
if (obj.attrs.test(Attrs::Value))
11131113
isValueAttr = true; // TODO: do we want an mlir::Attribute as well?
1114-
if (obj.attrs.test(Attrs::Volatile)) {
1115-
TODO(loc, "VOLATILE in procedure interface");
1116-
addMLIRAttr(fir::getVolatileAttrName());
1117-
}
1114+
11181115
// obj.attrs.test(Attrs::Asynchronous) does not impact the way the argument
11191116
// is passed given flang implement asynch IO synchronously. However, it's
11201117
// added to determine whether the argument is captured.
@@ -1151,7 +1148,8 @@ class Fortran::lower::CallInterfaceImpl {
11511148

11521149
if (obj.attrs.test(Attrs::Allocatable) || obj.attrs.test(Attrs::Pointer)) {
11531150
// Pass as fir.ref<fir.box> or fir.ref<fir.class>
1154-
mlir::Type boxRefType = fir::ReferenceType::get(boxType);
1151+
const bool isVolatile = obj.attrs.test(Attrs::Volatile);
1152+
mlir::Type boxRefType = fir::ReferenceType::get(boxType, isVolatile);
11551153
addFirOperand(boxRefType, nextPassedArgPosition(), Property::MutableBox,
11561154
attrs);
11571155
addPassedArg(PassEntityBy::MutableBox, entity, characteristics);

flang/lib/Lower/ConvertCall.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,10 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
13691369
// it according to the interface.
13701370
mlir::Value addr;
13711371
if (mlir::isa<fir::BoxCharType>(dummyTypeWithActualRank)) {
1372-
addr = hlfir::genVariableBoxChar(loc, builder, entity);
1372+
// Cast the argument to match the volatility of the dummy argument.
1373+
auto nonVolatileEntity = hlfir::Entity{builder.createVolatileCast(
1374+
loc, fir::isa_volatile_type(dummyType), entity)};
1375+
addr = hlfir::genVariableBoxChar(loc, builder, nonVolatileEntity);
13731376
} else if (mlir::isa<fir::BaseBoxType>(dummyTypeWithActualRank)) {
13741377
entity = hlfir::genVariableBox(loc, builder, entity);
13751378
// Ensures the box has the right attributes and that it holds an

0 commit comments

Comments
 (0)