Skip to content

Commit b2711e1

Browse files
[flang][nfc] Support volatile on ref, box, and class types (#134386)
Part one of merging #132486. Add support for representing volatility in the type system for reference, box, and class types. Don't do anything with volatile just yet, only support and test their representation and utility functions. The naming convention is a little goofy - `fir::isa_volatile_type` and `fir::updateTypeWithVolatility` use different capitalization, but I put them near similar functions and tried to match the surrounding conventions and [the docs](https://github.com/llvm/llvm-project/blob/main/flang/docs/C%2B%2Bstyle.md#naming) best I could.
1 parent 0ab2061 commit b2711e1

File tree

7 files changed

+192
-24
lines changed

7 files changed

+192
-24
lines changed

Diff for: flang/include/flang/Optimizer/Builder/FIRBuilder.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
150150
mlir::Block *getAllocaBlock();
151151

152152
/// Safely create a reference type to the type `eleTy`.
153-
mlir::Type getRefType(mlir::Type eleTy);
153+
mlir::Type getRefType(mlir::Type eleTy, bool isVolatile = false);
154154

155155
/// Create a sequence of `eleTy` with `rank` dimensions of unknown size.
156156
mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1);

Diff for: flang/include/flang/Optimizer/Dialect/FIRType.h

+8
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ inline bool isa_char_string(mlir::Type t) {
221221
/// (since they may hold one), and are not considered to be unknown size.
222222
bool isa_unknown_size_box(mlir::Type t);
223223

224+
/// Returns true iff `t` is a type capable of representing volatility and has
225+
/// the volatile attribute set.
226+
bool isa_volatile_type(mlir::Type t);
227+
224228
/// Returns true iff `t` is a fir.char type and has an unknown length.
225229
inline bool characterWithDynamicLen(mlir::Type t) {
226230
if (auto charTy = mlir::dyn_cast<fir::CharacterType>(t))
@@ -474,6 +478,10 @@ inline mlir::Type updateTypeForUnlimitedPolymorphic(mlir::Type ty) {
474478
return ty;
475479
}
476480

481+
/// Re-create the given type with the given volatility, if this is a type
482+
/// that can represent volatility.
483+
mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile);
484+
477485
/// Replace the element type of \p type by \p newElementType, preserving
478486
/// all other layers of the type (fir.ref/ptr/heap/array/box/class).
479487
/// If \p turnBoxIntoClass and the input is a fir.box, it will be turned into

Diff for: flang/include/flang/Optimizer/Dialect/FIRTypes.td

+17-12
Original file line numberDiff line numberDiff line change
@@ -77,24 +77,24 @@ def fir_BoxType : FIR_Type<"Box", "box", [], "BaseBoxType"> {
7777
to) whether the entity is an array, its size, or what type it has.
7878
}];
7979

80-
let parameters = (ins "mlir::Type":$eleTy);
80+
let parameters = (ins "mlir::Type":$eleTy, "bool":$isVolatile);
8181

8282
let skipDefaultBuilders = 1;
8383

8484
let builders = [
8585
TypeBuilderWithInferredContext<(ins
86-
"mlir::Type":$eleTy), [{
87-
return Base::get(eleTy.getContext(), eleTy);
86+
"mlir::Type":$eleTy, CArg<"bool", "false">:$isVolatile), [{
87+
return Base::get(eleTy.getContext(), eleTy, isVolatile);
8888
}]>,
8989
];
9090

9191
let extraClassDeclaration = [{
9292
mlir::Type getElementType() const { return getEleTy(); }
93+
bool isVolatile() const { return getIsVolatile(); }
9394
}];
9495

9596
let genVerifyDecl = 1;
96-
97-
let assemblyFormat = "`<` $eleTy `>`";
97+
let hasCustomAssemblyFormat = 1;
9898
}
9999

100100
def fir_CharacterType : FIR_Type<"Character", "char"> {
@@ -146,16 +146,20 @@ def fir_ClassType : FIR_Type<"Class", "class", [], "BaseBoxType"> {
146146
is equivalent to a fir.box type with a dynamic type.
147147
}];
148148

149-
let parameters = (ins "mlir::Type":$eleTy);
149+
let parameters = (ins "mlir::Type":$eleTy, "bool":$isVolatile);
150150

151151
let builders = [
152-
TypeBuilderWithInferredContext<(ins "mlir::Type":$eleTy), [{
153-
return $_get(eleTy.getContext(), eleTy);
152+
TypeBuilderWithInferredContext<(ins "mlir::Type":$eleTy, CArg<"bool", "false">:$isVolatile), [{
153+
return $_get(eleTy.getContext(), eleTy, isVolatile);
154154
}]>
155155
];
156156

157+
let extraClassDeclaration = [{
158+
bool isVolatile() const { return getIsVolatile(); }
159+
}];
160+
157161
let genVerifyDecl = 1;
158-
let assemblyFormat = "`<` $eleTy `>`";
162+
let hasCustomAssemblyFormat = 1;
159163
}
160164

161165
def fir_FieldType : FIR_Type<"Field", "field"> {
@@ -363,18 +367,19 @@ def fir_ReferenceType : FIR_Type<"Reference", "ref"> {
363367
The type of a reference to an entity in memory.
364368
}];
365369

366-
let parameters = (ins "mlir::Type":$eleTy);
370+
let parameters = (ins "mlir::Type":$eleTy, "bool":$isVolatile);
367371

368372
let skipDefaultBuilders = 1;
369373

370374
let builders = [
371-
TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{
372-
return Base::get(elementType.getContext(), elementType);
375+
TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType, CArg<"bool", "false">:$isVolatile), [{
376+
return Base::get(elementType.getContext(), elementType, isVolatile);
373377
}]>,
374378
];
375379

376380
let extraClassDeclaration = [{
377381
mlir::Type getElementType() const { return getEleTy(); }
382+
bool isVolatile() const { return getIsVolatile(); }
378383
}];
379384

380385
let genVerifyDecl = 1;

Diff for: flang/lib/Optimizer/Builder/FIRBuilder.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp,
105105
return modOp.lookupSymbol<fir::GlobalOp>(name);
106106
}
107107

108-
mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy) {
108+
mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy, bool isVolatile) {
109109
assert(!mlir::isa<fir::ReferenceType>(eleTy) && "cannot be a reference type");
110-
return fir::ReferenceType::get(eleTy);
110+
return fir::ReferenceType::get(eleTy, isVolatile);
111111
}
112112

113113
mlir::Type fir::FirOpBuilder::getVarLenSeqTy(mlir::Type eleTy, unsigned rank) {

Diff for: flang/lib/Optimizer/Dialect/FIRType.cpp

+101-7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,21 @@ using namespace fir;
3232

3333
namespace {
3434

35+
static llvm::StringRef getVolatileKeyword() { return "volatile"; }
36+
37+
static mlir::ParseResult parseOptionalCommaAndKeyword(mlir::AsmParser &parser,
38+
mlir::StringRef keyword,
39+
bool &parsedKeyword) {
40+
if (!parser.parseOptionalComma()) {
41+
if (parser.parseKeyword(keyword))
42+
return mlir::failure();
43+
parsedKeyword = true;
44+
return mlir::success();
45+
}
46+
parsedKeyword = false;
47+
return mlir::success();
48+
}
49+
3550
template <typename TYPE>
3651
TYPE parseIntSingleton(mlir::AsmParser &parser) {
3752
int kind = 0;
@@ -215,6 +230,19 @@ mlir::Type getDerivedType(mlir::Type ty) {
215230
.Default([](mlir::Type t) { return t; });
216231
}
217232

233+
mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile) {
234+
// If we already have the volatility we asked for, return the type unchanged.
235+
if (fir::isa_volatile_type(type) == isVolatile)
236+
return type;
237+
return mlir::TypeSwitch<mlir::Type, mlir::Type>(type)
238+
.Case<fir::BoxType, fir::ClassType, fir::ReferenceType>(
239+
[&](auto ty) -> mlir::Type {
240+
using TYPE = decltype(ty);
241+
return TYPE::get(ty.getEleTy(), isVolatile);
242+
})
243+
.Default([&](mlir::Type t) -> mlir::Type { return t; });
244+
}
245+
218246
mlir::Type dyn_cast_ptrEleTy(mlir::Type t) {
219247
return llvm::TypeSwitch<mlir::Type, mlir::Type>(t)
220248
.Case<fir::ReferenceType, fir::PointerType, fir::HeapType,
@@ -701,6 +729,13 @@ bool fir::isa_unknown_size_box(mlir::Type t) {
701729
return false;
702730
}
703731

732+
bool fir::isa_volatile_type(mlir::Type t) {
733+
return llvm::TypeSwitch<mlir::Type, bool>(t)
734+
.Case<fir::ReferenceType, fir::BoxType, fir::ClassType>(
735+
[](auto t) { return t.isVolatile(); })
736+
.Default([](mlir::Type) { return false; });
737+
}
738+
704739
//===----------------------------------------------------------------------===//
705740
// BoxProcType
706741
//===----------------------------------------------------------------------===//
@@ -738,9 +773,31 @@ static bool cannotBePointerOrHeapElementType(mlir::Type eleTy) {
738773
// BoxType
739774
//===----------------------------------------------------------------------===//
740775

776+
// `box` `<` type (`, volatile` $volatile^)? `>`
777+
mlir::Type fir::BoxType::parse(mlir::AsmParser &parser) {
778+
mlir::Type eleTy;
779+
auto location = parser.getCurrentLocation();
780+
auto *context = parser.getContext();
781+
bool isVolatile = false;
782+
if (parser.parseLess() || parser.parseType(eleTy))
783+
return {};
784+
if (parseOptionalCommaAndKeyword(parser, getVolatileKeyword(), isVolatile))
785+
return {};
786+
if (parser.parseGreater())
787+
return {};
788+
return parser.getChecked<fir::BoxType>(location, context, eleTy, isVolatile);
789+
}
790+
791+
void fir::BoxType::print(mlir::AsmPrinter &printer) const {
792+
printer << "<" << getEleTy();
793+
if (isVolatile())
794+
printer << ", " << getVolatileKeyword();
795+
printer << '>';
796+
}
797+
741798
llvm::LogicalResult
742799
fir::BoxType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
743-
mlir::Type eleTy) {
800+
mlir::Type eleTy, bool isVolatile) {
744801
if (mlir::isa<fir::BaseBoxType>(eleTy))
745802
return emitError() << "invalid element type\n";
746803
// TODO
@@ -807,9 +864,32 @@ void fir::CharacterType::print(mlir::AsmPrinter &printer) const {
807864
// ClassType
808865
//===----------------------------------------------------------------------===//
809866

867+
// `class` `<` type (`, volatile` $volatile^)? `>`
868+
mlir::Type fir::ClassType::parse(mlir::AsmParser &parser) {
869+
mlir::Type eleTy;
870+
auto location = parser.getCurrentLocation();
871+
auto *context = parser.getContext();
872+
bool isVolatile = false;
873+
if (parser.parseLess() || parser.parseType(eleTy))
874+
return {};
875+
if (parseOptionalCommaAndKeyword(parser, getVolatileKeyword(), isVolatile))
876+
return {};
877+
if (parser.parseGreater())
878+
return {};
879+
return parser.getChecked<fir::ClassType>(location, context, eleTy,
880+
isVolatile);
881+
}
882+
883+
void fir::ClassType::print(mlir::AsmPrinter &printer) const {
884+
printer << "<" << getEleTy();
885+
if (isVolatile())
886+
printer << ", " << getVolatileKeyword();
887+
printer << '>';
888+
}
889+
810890
llvm::LogicalResult
811891
fir::ClassType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
812-
mlir::Type eleTy) {
892+
mlir::Type eleTy, bool isVolatile) {
813893
if (mlir::isa<fir::RecordType, fir::SequenceType, fir::HeapType,
814894
fir::PointerType, mlir::NoneType, mlir::IntegerType,
815895
mlir::FloatType, fir::CharacterType, fir::LogicalType,
@@ -1057,18 +1137,32 @@ unsigned fir::RecordType::getFieldIndex(llvm::StringRef ident) {
10571137
// ReferenceType
10581138
//===----------------------------------------------------------------------===//
10591139

1060-
// `ref` `<` type `>`
1140+
// `ref` `<` type (`, volatile` $volatile^)? `>`
10611141
mlir::Type fir::ReferenceType::parse(mlir::AsmParser &parser) {
1062-
return parseTypeSingleton<fir::ReferenceType>(parser);
1142+
auto location = parser.getCurrentLocation();
1143+
auto *context = parser.getContext();
1144+
mlir::Type eleTy;
1145+
bool isVolatile = false;
1146+
if (parser.parseLess() || parser.parseType(eleTy))
1147+
return {};
1148+
if (parseOptionalCommaAndKeyword(parser, getVolatileKeyword(), isVolatile))
1149+
return {};
1150+
if (parser.parseGreater())
1151+
return {};
1152+
return parser.getChecked<fir::ReferenceType>(location, context, eleTy,
1153+
isVolatile);
10631154
}
10641155

10651156
void fir::ReferenceType::print(mlir::AsmPrinter &printer) const {
1066-
printer << "<" << getEleTy() << '>';
1157+
printer << "<" << getEleTy();
1158+
if (isVolatile())
1159+
printer << ", " << getVolatileKeyword();
1160+
printer << '>';
10671161
}
10681162

10691163
llvm::LogicalResult fir::ReferenceType::verify(
1070-
llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
1071-
mlir::Type eleTy) {
1164+
llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type eleTy,
1165+
bool isVolatile) {
10721166
if (mlir::isa<ShapeType, ShapeShiftType, SliceType, FieldType, LenType,
10731167
ReferenceType, TypeDescType>(eleTy))
10741168
return emitError() << "cannot build a reference to type: " << eleTy << '\n';

Diff for: flang/test/Fir/invalid-types.fir

+27-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ func.func private @box3() -> !fir.boxproc<>
66

77
// -----
88

9-
// expected-error@+2 {{expected non-function type}}
10-
// expected-error@+1 {{failed to parse fir_BoxType parameter 'eleTy' which is to be a `mlir::Type`}}
9+
// expected-error@+1 {{expected non-function type}}
1110
func.func private @box1() -> !fir.box<>
1211

1312
// -----
@@ -105,6 +104,11 @@ func.func private @mem3() -> !fir.ref<>
105104

106105
// -----
107106

107+
// expected-error@+1 {{expected non-function type}}
108+
func.func private @mem3() -> !fir.ref<, volatile>
109+
110+
// -----
111+
108112
// expected-error@+1 {{expected ':'}}
109113
func.func private @arr1() -> !fir.array<*>
110114

@@ -162,3 +166,24 @@ func.func private @upe() -> !fir.class<!fir.box<i32>>
162166

163167
// expected-error@+1 {{invalid element type}}
164168
func.func private @upe() -> !fir.box<!fir.class<none>>
169+
170+
// -----
171+
172+
// expected-error@+1 {{invalid element type}}
173+
func.func private @upe() -> !fir.box<!fir.class<none>, volatile>
174+
175+
// -----
176+
177+
// expected-error@+1 {{invalid element type}}
178+
func.func private @upe() -> !fir.class<!fir.box<i32>>
179+
180+
// -----
181+
182+
// expected-error@+1 {{invalid element type}}
183+
func.func private @upe() -> !fir.class<!fir.box<i32>, volatile>
184+
185+
// -----
186+
187+
// expected-error@+1 {{expected non-function type}}
188+
func.func private @upe() -> !fir.class<, volatile>
189+

Diff for: flang/unittests/Optimizer/FIRTypesTest.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,39 @@ TEST_F(FIRTypesTest, getTypeAsString) {
316316
EXPECT_EQ("boxchar_c8xU",
317317
fir::getTypeAsString(fir::BoxCharType::get(&context, 1), *kindMap));
318318
}
319+
320+
TEST_F(FIRTypesTest, isVolatileType) {
321+
mlir::Type i32 = mlir::IntegerType::get(&context, 32);
322+
323+
mlir::Type i32NonVolatileRef = fir::ReferenceType::get(i32);
324+
mlir::Type i32NonVolatileBox = fir::BoxType::get(i32);
325+
mlir::Type i32NonVolatileClass = fir::ClassType::get(i32);
326+
327+
// Ensure the default value is false
328+
EXPECT_EQ(i32NonVolatileRef, fir::ReferenceType::get(i32, false));
329+
EXPECT_EQ(i32NonVolatileBox, fir::BoxType::get(i32, false));
330+
EXPECT_EQ(i32NonVolatileClass, fir::ClassType::get(i32, false));
331+
332+
EXPECT_FALSE(fir::isa_volatile_type(i32));
333+
EXPECT_FALSE(fir::isa_volatile_type(i32NonVolatileRef));
334+
EXPECT_FALSE(fir::isa_volatile_type(i32NonVolatileBox));
335+
EXPECT_FALSE(fir::isa_volatile_type(i32NonVolatileClass));
336+
337+
// Should return the same type if it's not capable of representing volatility.
338+
EXPECT_EQ(i32, fir::updateTypeWithVolatility(i32, true));
339+
340+
mlir::Type i32VolatileRef =
341+
fir::updateTypeWithVolatility(i32NonVolatileRef, true);
342+
mlir::Type i32VolatileBox =
343+
fir::updateTypeWithVolatility(i32NonVolatileBox, true);
344+
mlir::Type i32VolatileClass =
345+
fir::updateTypeWithVolatility(i32NonVolatileClass, true);
346+
347+
EXPECT_TRUE(fir::isa_volatile_type(i32VolatileRef));
348+
EXPECT_TRUE(fir::isa_volatile_type(i32VolatileBox));
349+
EXPECT_TRUE(fir::isa_volatile_type(i32VolatileClass));
350+
351+
EXPECT_EQ(i32VolatileRef, fir::ReferenceType::get(i32, true));
352+
EXPECT_EQ(i32VolatileBox, fir::BoxType::get(i32, true));
353+
EXPECT_EQ(i32VolatileClass, fir::ClassType::get(i32, true));
354+
}

0 commit comments

Comments
 (0)