Skip to content

Commit 8f23d42

Browse files
Reland "[flang][nfc] Support volatility in Fir ops" (#135039)
#134858 had an extraneous include which caused the shared library builds to break.
1 parent 7b4b43b commit 8f23d42

File tree

9 files changed

+249
-25
lines changed

9 files changed

+249
-25
lines changed

flang/include/flang/Optimizer/Builder/FIRBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,11 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
397397
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
398398
mlir::Value val);
399399

400+
/// Create a fir.convert op with a volatile cast if the source value's type
401+
/// does not match the target type's volatility.
402+
mlir::Value createConvertWithVolatileCast(mlir::Location loc, mlir::Type toTy,
403+
mlir::Value val);
404+
400405
/// Create a fir.store of \p val into \p addr. A lazy conversion
401406
/// of \p val to the element type of \p addr is created if needed.
402407
void createStoreWithConvert(mlir::Location loc, mlir::Value val,

flang/include/flang/Optimizer/Dialect/FIROps.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ struct DebuggingResource
5050
mlir::StringRef getName() final { return "DebuggingResource"; }
5151
};
5252

53+
/// Model operations which read from/write to volatile memory
54+
struct VolatileMemoryResource
55+
: public mlir::SideEffects::Resource::Base<VolatileMemoryResource> {
56+
mlir::StringRef getName() final { return "VolatileMemoryResource"; }
57+
};
58+
5359
class CoordinateIndicesAdaptor;
5460
using IntOrValue = llvm::PointerUnion<mlir::IntegerAttr, mlir::Value>;
5561

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

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,8 @@ def fir_FreeMemOp : fir_Op<"freemem", [MemoryEffects<[MemFree]>]> {
286286
let assemblyFormat = "$heapref attr-dict `:` qualified(type($heapref))";
287287
}
288288

289-
def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
289+
def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface,
290+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
290291
let summary = "load a value from a memory reference";
291292
let description = [{
292293
Load a value from a memory reference into an ssa-value (virtual register).
@@ -302,7 +303,7 @@ def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
302303
or null.
303304
}];
304305

305-
let arguments = (ins Arg<AnyReferenceLike, "", [MemRead]>:$memref,
306+
let arguments = (ins AnyReferenceLike:$memref,
306307
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
307308

308309
let builders = [OpBuilder<(ins "mlir::Value":$refVal)>,
@@ -315,7 +316,8 @@ def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
315316
}];
316317
}
317318

318-
def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
319+
def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface,
320+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
319321
let summary = "store an SSA-value to a memory location";
320322

321323
let description = [{
@@ -335,7 +337,7 @@ def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
335337
}];
336338

337339
let arguments = (ins AnyType:$value,
338-
Arg<AnyReferenceLike, "", [MemWrite]>:$memref,
340+
AnyReferenceLike:$memref,
339341
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
340342

341343
let builders = [OpBuilder<(ins "mlir::Value":$value, "mlir::Value":$memref)>];
@@ -348,7 +350,7 @@ def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
348350
}];
349351
}
350352

351-
def fir_CopyOp : fir_Op<"copy", []> {
353+
def fir_CopyOp : fir_Op<"copy", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
352354
let summary = "copy constant size memory";
353355

354356
let description = [{
@@ -369,8 +371,8 @@ def fir_CopyOp : fir_Op<"copy", []> {
369371
TODO: add FirAliasTagOpInterface to carry TBAA.
370372
}];
371373

372-
let arguments = (ins Arg<AnyRefOfConstantSizeAggregateType, "", [MemRead]>:$source,
373-
Arg<AnyRefOfConstantSizeAggregateType, "", [MemWrite]>:$destination,
374+
let arguments = (ins AnyRefOfConstantSizeAggregateType:$source,
375+
AnyRefOfConstantSizeAggregateType:$destination,
374376
OptionalAttr<UnitAttr>:$no_overlap);
375377

376378
let builders = [OpBuilder<(ins "mlir::Value":$source,
@@ -1373,7 +1375,8 @@ def fir_BoxTypeDescOp : fir_SimpleOneResultOp<"box_tdesc", [NoMemoryEffect]> {
13731375
// !- Merge the new and old values into the memory for "A"
13741376
// array_merge_store <updated A> to <A's address>
13751377

1376-
def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments]> {
1378+
def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments,
1379+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
13771380

13781381
let summary = "Load an array as a value.";
13791382

@@ -1412,7 +1415,7 @@ def fir_ArrayLoadOp : fir_Op<"array_load", [AttrSizedOperandSegments]> {
14121415
}];
14131416

14141417
let arguments = (ins
1415-
Arg<AnyRefOrBox, "", [MemRead]>:$memref,
1418+
AnyRefOrBox:$memref,
14161419
Optional<AnyShapeOrShiftType>:$shape,
14171420
Optional<fir_SliceType>:$slice,
14181421
Variadic<AnyIntegerType>:$typeparams
@@ -1624,7 +1627,7 @@ def fir_ArrayAccessOp : fir_Op<"array_access", [AttrSizedOperandSegments,
16241627

16251628
It is only possible to use `array_access` on an `array_load` result value or
16261629
a value that can be trace back transitively to an `array_load` as the
1627-
dominating source. Other array operation such as `array_amend` can be in
1630+
dominating source. Other array operations such as `array_amend` can be in
16281631
between.
16291632

16301633
TODO: The above restriction is not enforced. The design of the operation
@@ -1685,7 +1688,7 @@ def fir_ArrayAmendOp : fir_Op<"array_amend", [NoMemoryEffect]> {
16851688
}
16861689

16871690
def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
1688-
[AttrSizedOperandSegments]> {
1691+
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
16891692

16901693
let summary = "Store merged array value to memory.";
16911694

@@ -1714,7 +1717,7 @@ def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
17141717
let arguments = (ins
17151718
fir_SequenceType:$original,
17161719
fir_SequenceType:$sequence,
1717-
Arg<AnyRefOrBox, "", [MemWrite]>:$memref,
1720+
AnyRefOrBox:$memref,
17181721
Optional<fir_SliceType>:$slice,
17191722
Variadic<AnyIntegerType>:$typeparams
17201723
);
@@ -2752,6 +2755,22 @@ def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoMemoryEffect]> {
27522755
let assemblyFormat = "`(` $symbol `)` attr-dict `:` type($resTy)";
27532756
}
27542757

2758+
def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [NoMemoryEffect]> {
2759+
let summary = "cast between volatile and non-volatile types";
2760+
let description = [{
2761+
Cast between volatile and non-volatile types. The types must be otherwise
2762+
identical. A value's volatility cannot be changed by a fir.convert operation.
2763+
Reinterpreting a value as volatile must be done explicitly using this operation.
2764+
}];
2765+
let arguments = (ins AnyRefOrBox:$value);
2766+
let results = (outs AnyRefOrBox:$res);
2767+
let assemblyFormat = [{
2768+
$value attr-dict `:` functional-type($value, results)
2769+
}];
2770+
let hasVerifier = 1;
2771+
let hasFolder = 1;
2772+
}
2773+
27552774
def fir_ConvertOp : fir_SimpleOneResultOp<"convert", [NoMemoryEffect]> {
27562775
let summary = "encapsulates all Fortran entity type conversions";
27572776

flang/include/flang/Optimizer/Dialect/FIROpsSupport.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,26 @@
1515

1616
namespace fir {
1717

18-
/// Return true iff the Operation is a non-volatile LoadOp or ArrayLoadOp.
19-
inline bool nonVolatileLoad(mlir::Operation *op) {
20-
if (auto load = mlir::dyn_cast<fir::LoadOp>(op))
21-
return !load->getAttr("volatile");
22-
if (auto arrLoad = mlir::dyn_cast<fir::ArrayLoadOp>(op))
23-
return !arrLoad->getAttr("volatile");
24-
return false;
18+
/// The LLVM dialect represents volatile memory accesses as read and write
19+
/// effects to an unknown memory location, but this may be overly conservative.
20+
/// LLVM Language Reference only specifies that volatile memory accesses
21+
/// must not be reordered relative to other volatile memory accesses, so it
22+
/// is more precise to use a separate memory resource for volatile memory
23+
/// accesses.
24+
inline void addVolatileMemoryEffects(
25+
mlir::TypeRange type,
26+
llvm::SmallVectorImpl<
27+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
28+
&effects) {
29+
for (mlir::Type t : type) {
30+
if (fir::isa_volatile_type(t)) {
31+
effects.emplace_back(mlir::MemoryEffects::Read::get(),
32+
fir::VolatileMemoryResource::get());
33+
effects.emplace_back(mlir::MemoryEffects::Write::get(),
34+
fir::VolatileMemoryResource::get());
35+
break;
36+
}
37+
}
2538
}
2639

2740
/// Return true iff the Operation is a call.

flang/lib/Lower/ConvertExprToHLFIR.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,13 @@ class HlfirDesignatorBuilder {
415415
.Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type {
416416
return fir::SequenceType::get(seqTy.getShape(), newEleTy);
417417
})
418-
.Case<fir::PointerType, fir::HeapType, fir::ReferenceType, fir::BoxType,
419-
fir::ClassType>([&](auto t) -> mlir::Type {
418+
.Case<fir::ReferenceType, fir::BoxType, fir::ClassType>(
419+
[&](auto t) -> mlir::Type {
420+
using FIRT = decltype(t);
421+
return FIRT::get(changeElementType(t.getEleTy(), newEleTy),
422+
t.isVolatile());
423+
})
424+
.Case<fir::PointerType, fir::HeapType>([&](auto t) -> mlir::Type {
420425
using FIRT = decltype(t);
421426
return FIRT::get(changeElementType(t.getEleTy(), newEleTy));
422427
})

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,17 @@ mlir::Value fir::FirOpBuilder::convertWithSemantics(
577577
return createConvert(loc, toTy, val);
578578
}
579579

580+
mlir::Value fir::FirOpBuilder::createConvertWithVolatileCast(mlir::Location loc,
581+
mlir::Type toTy,
582+
mlir::Value val) {
583+
if (fir::isa_volatile_type(val.getType()) != fir::isa_volatile_type(toTy)) {
584+
mlir::Type volatileAdjustedType = fir::updateTypeWithVolatility(
585+
val.getType(), fir::isa_volatile_type(toTy));
586+
val = create<fir::VolatileCastOp>(loc, volatileAdjustedType, val);
587+
}
588+
return createConvert(loc, toTy, val);
589+
}
590+
580591
mlir::Value fir::factory::createConvert(mlir::OpBuilder &builder,
581592
mlir::Location loc, mlir::Type toTy,
582593
mlir::Value val) {
@@ -739,19 +750,20 @@ mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc,
739750
<< itemAddr.getType();
740751
llvm_unreachable("not a memory reference type");
741752
}
753+
const bool isVolatile = fir::isa_volatile_type(itemAddr.getType());
742754
mlir::Type boxTy;
743755
mlir::Value tdesc;
744756
// Avoid to wrap a box/class with box/class.
745757
if (mlir::isa<fir::BaseBoxType>(elementType)) {
746758
boxTy = elementType;
747759
} else {
748-
boxTy = fir::BoxType::get(elementType);
760+
boxTy = fir::BoxType::get(elementType, isVolatile);
749761
if (isPolymorphic) {
750762
elementType = fir::updateTypeForUnlimitedPolymorphic(elementType);
751763
if (isAssumedType)
752-
boxTy = fir::BoxType::get(elementType);
764+
boxTy = fir::BoxType::get(elementType, isVolatile);
753765
else
754-
boxTy = fir::ClassType::get(elementType);
766+
boxTy = fir::ClassType::get(elementType, isVolatile);
755767
}
756768
}
757769

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "mlir/IR/Matchers.h"
3030
#include "mlir/IR/OpDefinition.h"
3131
#include "mlir/IR/PatternMatch.h"
32+
#include "mlir/IR/TypeRange.h"
3233
#include "llvm/ADT/STLExtras.h"
3334
#include "llvm/ADT/SmallVector.h"
3435
#include "llvm/ADT/TypeSwitch.h"
@@ -853,6 +854,15 @@ std::vector<mlir::Value> fir::ArrayLoadOp::getExtents() {
853854
return {};
854855
}
855856

857+
void fir::ArrayLoadOp::getEffects(
858+
llvm::SmallVectorImpl<
859+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
860+
&effects) {
861+
effects.emplace_back(mlir::MemoryEffects::Read::get(), &getMemrefMutable(),
862+
mlir::SideEffects::DefaultResource::get());
863+
addVolatileMemoryEffects({getMemref().getType()}, effects);
864+
}
865+
856866
llvm::LogicalResult fir::ArrayLoadOp::verify() {
857867
auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
858868
auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);
@@ -935,6 +945,15 @@ llvm::LogicalResult fir::ArrayMergeStoreOp::verify() {
935945
return mlir::success();
936946
}
937947

948+
void fir::ArrayMergeStoreOp::getEffects(
949+
llvm::SmallVectorImpl<
950+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
951+
&effects) {
952+
effects.emplace_back(mlir::MemoryEffects::Write::get(), &getMemrefMutable(),
953+
mlir::SideEffects::DefaultResource::get());
954+
addVolatileMemoryEffects({getMemref().getType()}, effects);
955+
}
956+
938957
//===----------------------------------------------------------------------===//
939958
// ArrayFetchOp
940959
//===----------------------------------------------------------------------===//
@@ -1322,6 +1341,36 @@ mlir::ParseResult fir::CmpcOp::parse(mlir::OpAsmParser &parser,
13221341
return parseCmpOp<fir::CmpcOp>(parser, result);
13231342
}
13241343

1344+
//===----------------------------------------------------------------------===//
1345+
// VolatileCastOp
1346+
//===----------------------------------------------------------------------===//
1347+
1348+
llvm::LogicalResult fir::VolatileCastOp::verify() {
1349+
mlir::Type fromType = getValue().getType();
1350+
mlir::Type toType = getType();
1351+
// Other than volatility, are the types identical?
1352+
const bool sameBaseType =
1353+
llvm::TypeSwitch<mlir::Type, bool>(fromType)
1354+
.Case<fir::BoxType, fir::ReferenceType, fir::ClassType>(
1355+
[&](auto type) {
1356+
using TYPE = decltype(type);
1357+
return mlir::isa<TYPE>(toType);
1358+
})
1359+
.Default([=](mlir::Type) { return fromType == toType; });
1360+
const bool sameElementType = fir::dyn_cast_ptrOrBoxEleTy(fromType) ==
1361+
fir::dyn_cast_ptrOrBoxEleTy(toType);
1362+
if (!sameBaseType || !sameElementType)
1363+
return emitOpError("types must be identical except for volatility ")
1364+
<< fromType << " / " << toType;
1365+
return mlir::success();
1366+
}
1367+
1368+
mlir::OpFoldResult fir::VolatileCastOp::fold(FoldAdaptor adaptor) {
1369+
if (getValue().getType() == getType())
1370+
return getValue();
1371+
return {};
1372+
}
1373+
13251374
//===----------------------------------------------------------------------===//
13261375
// ConvertOp
13271376
//===----------------------------------------------------------------------===//
@@ -1461,7 +1510,13 @@ bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
14611510
}
14621511

14631512
llvm::LogicalResult fir::ConvertOp::verify() {
1464-
if (canBeConverted(getValue().getType(), getType()))
1513+
mlir::Type inType = getValue().getType();
1514+
mlir::Type outType = getType();
1515+
if (fir::isa_volatile_type(inType) != fir::isa_volatile_type(outType))
1516+
return emitOpError("cannot convert between volatile and non-volatile "
1517+
"types, use fir.volatile_cast instead ")
1518+
<< inType << " / " << outType;
1519+
if (canBeConverted(inType, outType))
14651520
return mlir::success();
14661521
return emitOpError("invalid type conversion")
14671522
<< getValue().getType() << " / " << getType();
@@ -1787,6 +1842,10 @@ llvm::LogicalResult fir::EmboxOp::verify() {
17871842
return emitOpError("slice must not be provided for a scalar");
17881843
if (getSourceBox() && !mlir::isa<fir::ClassType>(getResult().getType()))
17891844
return emitOpError("source_box must be used with fir.class result type");
1845+
if (fir::isa_volatile_type(getMemref().getType()) !=
1846+
fir::isa_volatile_type(getResult().getType()))
1847+
return emitOpError("cannot convert between volatile and non-volatile "
1848+
"types, use fir.volatile_cast instead");
17901849
return mlir::success();
17911850
}
17921851

@@ -2599,6 +2658,15 @@ void fir::LoadOp::print(mlir::OpAsmPrinter &p) {
25992658
p << " : " << getMemref().getType();
26002659
}
26012660

2661+
void fir::LoadOp::getEffects(
2662+
llvm::SmallVectorImpl<
2663+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
2664+
&effects) {
2665+
effects.emplace_back(mlir::MemoryEffects::Read::get(), &getMemrefMutable(),
2666+
mlir::SideEffects::DefaultResource::get());
2667+
addVolatileMemoryEffects({getMemref().getType()}, effects);
2668+
}
2669+
26022670
//===----------------------------------------------------------------------===//
26032671
// DoLoopOp
26042672
//===----------------------------------------------------------------------===//
@@ -3951,6 +4019,15 @@ void fir::StoreOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
39514019
build(builder, result, value, memref, {});
39524020
}
39534021

4022+
void fir::StoreOp::getEffects(
4023+
llvm::SmallVectorImpl<
4024+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
4025+
&effects) {
4026+
effects.emplace_back(mlir::MemoryEffects::Write::get(), &getMemrefMutable(),
4027+
mlir::SideEffects::DefaultResource::get());
4028+
addVolatileMemoryEffects({getMemref().getType()}, effects);
4029+
}
4030+
39544031
//===----------------------------------------------------------------------===//
39554032
// CopyOp
39564033
//===----------------------------------------------------------------------===//
@@ -3971,6 +4048,19 @@ llvm::LogicalResult fir::CopyOp::verify() {
39714048
return mlir::success();
39724049
}
39734050

4051+
void fir::CopyOp::getEffects(
4052+
llvm::SmallVectorImpl<
4053+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
4054+
&effects) {
4055+
effects.emplace_back(mlir::MemoryEffects::Read::get(), &getSourceMutable(),
4056+
mlir::SideEffects::DefaultResource::get());
4057+
effects.emplace_back(mlir::MemoryEffects::Write::get(),
4058+
&getDestinationMutable(),
4059+
mlir::SideEffects::DefaultResource::get());
4060+
addVolatileMemoryEffects({getDestination().getType(), getSource().getType()},
4061+
effects);
4062+
}
4063+
39744064
//===----------------------------------------------------------------------===//
39754065
// StringLitOp
39764066
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)