Skip to content

Commit a2e7af7

Browse files
clementvaljeanPerierschweitzpgi
committed
[fir] Add utility function to FIRBuilder and MutableBox
This patch is extracted from D111337 to make is smaller. It introduce utility functions to the FIRBuilder and add the MutableBox files. - genShape - readCharLen - getExtents Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D112207 Co-authored-by: Jean Perier <[email protected]> Co-authored-by: Eric Schweitz <[email protected]>
1 parent 4ff103c commit a2e7af7

File tree

7 files changed

+1119
-2
lines changed

7 files changed

+1119
-2
lines changed

flang/include/flang/Lower/FIRBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
#include "llvm/ADT/Optional.h"
2727

2828
namespace Fortran::lower {
29-
3029
class AbstractConverter;
30+
class BoxValue;
3131

3232
//===----------------------------------------------------------------------===//
3333
// FirOpBuilder

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include "mlir/IR/BuiltinOps.h"
2424

2525
namespace fir {
26+
class AbstractArrayBox;
2627
class ExtendedValue;
28+
class BoxValue;
2729

2830
//===----------------------------------------------------------------------===//
2931
// FirOpBuilder
@@ -241,6 +243,16 @@ class FirOpBuilder : public mlir::OpBuilder {
241243
return createFunction(loc, module, name, ty);
242244
}
243245

246+
/// Construct one of the two forms of shape op from an array box.
247+
mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr);
248+
mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift,
249+
llvm::ArrayRef<mlir::Value> exts);
250+
mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts);
251+
252+
/// Create one of the shape ops given an extended value. For a boxed value,
253+
/// this may create a `fir.shift` op.
254+
mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv);
255+
244256
/// Create constant i1 with value 1. if \p b is true or 0. otherwise
245257
mlir::Value createBool(mlir::Location loc, bool b) {
246258
return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0);
@@ -322,6 +334,28 @@ class FirOpBuilder : public mlir::OpBuilder {
322334

323335
namespace fir::factory {
324336

337+
//===----------------------------------------------------------------------===//
338+
// ExtendedValue inquiry helpers
339+
//===----------------------------------------------------------------------===//
340+
341+
/// Read or get character length from \p box that must contain a character
342+
/// entity. If the length value is contained in the ExtendedValue, this will
343+
/// not generate any code, otherwise this will generate a read of the fir.box
344+
/// describing the entity.
345+
mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc,
346+
const fir::ExtendedValue &box);
347+
348+
/// Read extents from \p box.
349+
llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder,
350+
mlir::Location loc,
351+
const fir::BoxValue &box);
352+
353+
/// Get extents from \p box. For fir::BoxValue and
354+
/// fir::MutableBoxValue, this will generate code to read the extents.
355+
llvm::SmallVector<mlir::Value> getExtents(fir::FirOpBuilder &builder,
356+
mlir::Location loc,
357+
const fir::ExtendedValue &box);
358+
325359
//===----------------------------------------------------------------------===//
326360
// String literal helper helpers
327361
//===----------------------------------------------------------------------===//
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//===-- MutableBox.h -- MutableBox utilities -----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H
14+
#define FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H
15+
16+
#include "llvm/ADT/StringRef.h"
17+
18+
namespace mlir {
19+
class Value;
20+
class ValueRange;
21+
class Type;
22+
class Location;
23+
} // namespace mlir
24+
25+
namespace fir {
26+
class FirOpBuilder;
27+
class MutableBoxValue;
28+
class ExtendedValue;
29+
} // namespace fir
30+
31+
namespace fir::factory {
32+
33+
/// Create a fir.box of type \p boxType that can be used to initialize an
34+
/// allocatable variable. Initialization of such variable has to be done at the
35+
/// beginning of the variable lifetime by storing the created box in the memory
36+
/// for the variable box.
37+
/// \p nonDeferredParams must provide the non deferred length parameters so that
38+
/// they can already be placed in the unallocated box (inquiries about these
39+
/// parameters are legal even in unallocated state).
40+
mlir::Value createUnallocatedBox(fir::FirOpBuilder &builder, mlir::Location loc,
41+
mlir::Type boxType,
42+
mlir::ValueRange nonDeferredParams);
43+
44+
/// Create a MutableBoxValue for a temporary allocatable.
45+
/// The created MutableBoxValue wraps a fir.ref<fir.box<fir.heap<type>>> and is
46+
/// initialized to unallocated/diassociated status. An optional name can be
47+
/// given to the created !fir.ref<fir.box>.
48+
fir::MutableBoxValue createTempMutableBox(fir::FirOpBuilder &builder,
49+
mlir::Location loc, mlir::Type type,
50+
llvm::StringRef name = {});
51+
52+
/// Update a MutableBoxValue to describe entity \p source (that must be in
53+
/// memory). If \lbounds is not empty, it is used to defined the MutableBoxValue
54+
/// lower bounds, otherwise, the lower bounds from \p source are used.
55+
void associateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc,
56+
const fir::MutableBoxValue &box,
57+
const fir::ExtendedValue &source,
58+
mlir::ValueRange lbounds);
59+
60+
/// Update a MutableBoxValue to describe entity \p source (that must be in
61+
/// memory) with a new array layout given by \p lbounds and \p ubounds.
62+
/// \p source must be known to be contiguous at compile time, or it must have
63+
/// rank 1 (constraint from Fortran 2018 standard 10.2.2.3 point 9).
64+
void associateMutableBoxWithRemap(fir::FirOpBuilder &builder,
65+
mlir::Location loc,
66+
const fir::MutableBoxValue &box,
67+
const fir::ExtendedValue &source,
68+
mlir::ValueRange lbounds,
69+
mlir::ValueRange ubounds);
70+
71+
/// Set the association status of a MutableBoxValue to
72+
/// disassociated/unallocated. Nothing is done with the entity that was
73+
/// previously associated/allocated. The function generates code that sets the
74+
/// address field of the MutableBoxValue to zero.
75+
void disassociateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc,
76+
const fir::MutableBoxValue &box);
77+
78+
/// Generate code to conditionally reallocate a MutableBoxValue with a new
79+
/// shape, lower bounds, and length parameters if it is unallocated or if its
80+
/// current shape or deferred length parameters do not match the provided ones.
81+
/// Lower bounds are only used if the entity needs to be allocated, otherwise,
82+
/// the MutableBoxValue will keep its current lower bounds.
83+
/// If the MutableBoxValue is an array, the provided shape can be empty, in
84+
/// which case the MutableBoxValue must already be allocated at runtime and its
85+
/// shape and lower bounds will be kept. If \p shape is empty, only a length
86+
/// parameter mismatch can trigger a reallocation. See Fortran 10.2.1.3 point 3
87+
/// that this function is implementing for more details. The polymorphic
88+
/// requirements are not yet covered by this function.
89+
void genReallocIfNeeded(fir::FirOpBuilder &builder, mlir::Location loc,
90+
const fir::MutableBoxValue &box,
91+
mlir::ValueRange lbounds, mlir::ValueRange shape,
92+
mlir::ValueRange lengthParams);
93+
94+
/// Finalize a mutable box if it is allocated or associated. This includes both
95+
/// calling the finalizer, if any, and deallocating the storage.
96+
void genFinalization(fir::FirOpBuilder &builder, mlir::Location loc,
97+
const fir::MutableBoxValue &box);
98+
99+
void genInlinedAllocation(fir::FirOpBuilder &builder, mlir::Location loc,
100+
const fir::MutableBoxValue &box,
101+
mlir::ValueRange lbounds, mlir::ValueRange extents,
102+
mlir::ValueRange lenParams,
103+
llvm::StringRef allocName);
104+
105+
void genInlinedDeallocate(fir::FirOpBuilder &builder, mlir::Location loc,
106+
const fir::MutableBoxValue &box);
107+
108+
/// When the MutableBoxValue was passed as a fir.ref<fir.box> to a call that may
109+
/// have modified it, update the MutableBoxValue according to the
110+
/// fir.ref<fir.box> value.
111+
void syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, mlir::Location loc,
112+
const fir::MutableBoxValue &box);
113+
114+
/// Read all mutable properties into a normal symbol box.
115+
/// It is OK to call this on unassociated/unallocated boxes but any use of the
116+
/// resulting values will be undefined (only the base address will be guaranteed
117+
/// to be null).
118+
fir::ExtendedValue genMutableBoxRead(fir::FirOpBuilder &builder,
119+
mlir::Location loc,
120+
const fir::MutableBoxValue &box,
121+
bool mayBePolymorphic = true);
122+
123+
/// Returns the fir.ref<fir.box<T>> of a MutableBoxValue filled with the current
124+
/// association / allocation properties. If the fir.ref<fir.box> already exists
125+
/// and is-up to date, this is a no-op, otherwise, code will be generated to
126+
/// fill it.
127+
mlir::Value getMutableIRBox(fir::FirOpBuilder &builder, mlir::Location loc,
128+
const fir::MutableBoxValue &box);
129+
130+
/// Generate allocation or association status test and returns the resulting
131+
/// i1. This is testing this for a valid/non-null base address value.
132+
mlir::Value genIsAllocatedOrAssociatedTest(fir::FirOpBuilder &builder,
133+
mlir::Location loc,
134+
const fir::MutableBoxValue &box);
135+
136+
} // namespace fir::factory
137+
138+
#endif // FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H

flang/lib/Optimizer/Builder/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_flang_library(FIRBuilder
55
Character.cpp
66
DoLoopHelper.cpp
77
FIRBuilder.cpp
8+
MutableBox.cpp
89

910
DEPENDS
1011
FIRDialect

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "flang/Optimizer/Builder/FIRBuilder.h"
1010
#include "flang/Optimizer/Builder/BoxValue.h"
11+
#include "flang/Optimizer/Builder/Character.h"
12+
#include "flang/Optimizer/Builder/MutableBox.h"
1113
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
1214
#include "flang/Optimizer/Support/FatalError.h"
1315
#include "flang/Optimizer/Support/InternalNames.h"
@@ -277,6 +279,54 @@ fir::StringLitOp fir::FirOpBuilder::createStringLitOp(mlir::Location loc,
277279
llvm::None, attrs);
278280
}
279281

282+
mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc,
283+
llvm::ArrayRef<mlir::Value> exts) {
284+
auto shapeType = fir::ShapeType::get(getContext(), exts.size());
285+
return create<fir::ShapeOp>(loc, shapeType, exts);
286+
}
287+
288+
mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc,
289+
llvm::ArrayRef<mlir::Value> shift,
290+
llvm::ArrayRef<mlir::Value> exts) {
291+
auto shapeType = fir::ShapeShiftType::get(getContext(), exts.size());
292+
llvm::SmallVector<mlir::Value> shapeArgs;
293+
auto idxTy = getIndexType();
294+
for (auto [lbnd, ext] : llvm::zip(shift, exts)) {
295+
auto lb = createConvert(loc, idxTy, lbnd);
296+
shapeArgs.push_back(lb);
297+
shapeArgs.push_back(ext);
298+
}
299+
return create<fir::ShapeShiftOp>(loc, shapeType, shapeArgs);
300+
}
301+
302+
mlir::Value fir::FirOpBuilder::genShape(mlir::Location loc,
303+
const fir::AbstractArrayBox &arr) {
304+
if (arr.lboundsAllOne())
305+
return genShape(loc, arr.getExtents());
306+
return genShape(loc, arr.getLBounds(), arr.getExtents());
307+
}
308+
309+
mlir::Value fir::FirOpBuilder::createShape(mlir::Location loc,
310+
const fir::ExtendedValue &exv) {
311+
return exv.match(
312+
[&](const fir::ArrayBoxValue &box) { return genShape(loc, box); },
313+
[&](const fir::CharArrayBoxValue &box) { return genShape(loc, box); },
314+
[&](const fir::BoxValue &box) -> mlir::Value {
315+
if (!box.getLBounds().empty()) {
316+
auto shiftType =
317+
fir::ShiftType::get(getContext(), box.getLBounds().size());
318+
return create<fir::ShiftOp>(loc, shiftType, box.getLBounds());
319+
}
320+
return {};
321+
},
322+
[&](const fir::MutableBoxValue &) -> mlir::Value {
323+
// MutableBoxValue must be read into another category to work with them
324+
// outside of allocation/assignment contexts.
325+
fir::emitFatalError(loc, "createShape on MutableBoxValue");
326+
},
327+
[&](auto) -> mlir::Value { fir::emitFatalError(loc, "not an array"); });
328+
}
329+
280330
static mlir::Value genNullPointerComparison(fir::FirOpBuilder &builder,
281331
mlir::Location loc,
282332
mlir::Value addr,
@@ -296,6 +346,76 @@ mlir::Value fir::FirOpBuilder::genIsNull(mlir::Location loc, mlir::Value addr) {
296346
return genNullPointerComparison(*this, loc, addr, arith::CmpIPredicate::eq);
297347
}
298348

349+
//===--------------------------------------------------------------------===//
350+
// ExtendedValue inquiry helper implementation
351+
//===--------------------------------------------------------------------===//
352+
353+
mlir::Value fir::factory::readCharLen(fir::FirOpBuilder &builder,
354+
mlir::Location loc,
355+
const fir::ExtendedValue &box) {
356+
return box.match(
357+
[&](const fir::CharBoxValue &x) -> mlir::Value { return x.getLen(); },
358+
[&](const fir::CharArrayBoxValue &x) -> mlir::Value {
359+
return x.getLen();
360+
},
361+
[&](const fir::BoxValue &x) -> mlir::Value {
362+
assert(x.isCharacter());
363+
if (!x.getExplicitParameters().empty())
364+
return x.getExplicitParameters()[0];
365+
return fir::factory::CharacterExprHelper{builder, loc}
366+
.readLengthFromBox(x.getAddr());
367+
},
368+
[&](const fir::MutableBoxValue &) -> mlir::Value {
369+
// MutableBoxValue must be read into another category to work with them
370+
// outside of allocation/assignment contexts.
371+
fir::emitFatalError(loc, "readCharLen on MutableBoxValue");
372+
},
373+
[&](const auto &) -> mlir::Value {
374+
fir::emitFatalError(
375+
loc, "Character length inquiry on a non-character entity");
376+
});
377+
}
378+
379+
llvm::SmallVector<mlir::Value>
380+
fir::factory::readExtents(fir::FirOpBuilder &builder, mlir::Location loc,
381+
const fir::BoxValue &box) {
382+
llvm::SmallVector<mlir::Value> result;
383+
auto explicitExtents = box.getExplicitExtents();
384+
if (!explicitExtents.empty()) {
385+
result.append(explicitExtents.begin(), explicitExtents.end());
386+
return result;
387+
}
388+
auto rank = box.rank();
389+
auto idxTy = builder.getIndexType();
390+
for (decltype(rank) dim = 0; dim < rank; ++dim) {
391+
auto dimVal = builder.createIntegerConstant(loc, idxTy, dim);
392+
auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
393+
box.getAddr(), dimVal);
394+
result.emplace_back(dimInfo.getResult(1));
395+
}
396+
return result;
397+
}
398+
399+
llvm::SmallVector<mlir::Value>
400+
fir::factory::getExtents(fir::FirOpBuilder &builder, mlir::Location loc,
401+
const fir::ExtendedValue &box) {
402+
return box.match(
403+
[&](const fir::ArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> {
404+
return {x.getExtents().begin(), x.getExtents().end()};
405+
},
406+
[&](const fir::CharArrayBoxValue &x) -> llvm::SmallVector<mlir::Value> {
407+
return {x.getExtents().begin(), x.getExtents().end()};
408+
},
409+
[&](const fir::BoxValue &x) -> llvm::SmallVector<mlir::Value> {
410+
return fir::factory::readExtents(builder, loc, x);
411+
},
412+
[&](const fir::MutableBoxValue &x) -> llvm::SmallVector<mlir::Value> {
413+
auto load = fir::factory::genMutableBoxRead(builder, loc, x);
414+
return fir::factory::getExtents(builder, loc, load);
415+
},
416+
[&](const auto &) -> llvm::SmallVector<mlir::Value> { return {}; });
417+
}
418+
299419
std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix,
300420
llvm::StringRef name) {
301421
// For "long" identifiers use a hash value

0 commit comments

Comments
 (0)