Skip to content

Commit f3c3f63

Browse files
committed
[flang][hlfir] Generate temporary storage in Forall/Where [2/2]
Generate temporary storage inside WHERE and FORALL using the temporary stack runtime. This covers all cases outside of LHS temporary, where the descriptor stack will have to be used. Reviewed By: vzakhari Differential Revision: https://reviews.llvm.org/D151251
1 parent d757811 commit f3c3f63

File tree

9 files changed

+378
-7
lines changed

9 files changed

+378
-7
lines changed

flang/include/flang/Optimizer/Builder/HLFIRTools.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,7 @@ class Entity : public mlir::Value {
112112
}
113113
bool isScalar() const { return !isArray(); }
114114

115-
bool isPolymorphic() const {
116-
if (auto exprType = getType().dyn_cast<hlfir::ExprType>())
117-
return exprType.isPolymorphic();
118-
return fir::isPolymorphicType(getType());
119-
}
115+
bool isPolymorphic() const { return hlfir::isPolymorphicType(getType()); }
120116

121117
mlir::Type getFortranElementType() const {
122118
return hlfir::getFortranElementType(getType());
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===- TemporaryStack.h --- temporary stack runtime API calls ---*- C++ -*-===//
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+
#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_TEMPORARYSTACK_H
10+
#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_TEMPORARYSTACK_H
11+
12+
namespace mlir {
13+
class Value;
14+
class Location;
15+
} // namespace mlir
16+
17+
namespace fir {
18+
class FirOpBuilder;
19+
}
20+
21+
namespace fir::runtime {
22+
23+
mlir::Value genCreateValueStack(mlir::Location loc, fir::FirOpBuilder &builder);
24+
25+
void genPushValue(mlir::Location loc, fir::FirOpBuilder &builder,
26+
mlir::Value opaquePtr, mlir::Value boxValue);
27+
void genValueAt(mlir::Location loc, fir::FirOpBuilder &builder,
28+
mlir::Value opaquePtr, mlir::Value i, mlir::Value retValueBox);
29+
30+
void genDestroyValueStack(mlir::Location loc, fir::FirOpBuilder &builder,
31+
mlir::Value opaquePtr);
32+
33+
} // namespace fir::runtime
34+
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_TEMPORARYSTACK_H

flang/include/flang/Optimizer/Builder/TemporaryStorage.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,35 @@ class SimpleCopy {
115115
hlfir::AssociateOp copy;
116116
};
117117

118+
/// Data structure to stack any kind of values with the same static type and
119+
/// rank. Each value may have different type parameters, bounds, and dynamic
120+
/// type. Fetching value N will return a value with the same dynamic type,
121+
/// bounds, and type parameters as the Nth value that was pushed. It is
122+
/// implemented using runtime.
123+
class AnyValueStack {
124+
public:
125+
AnyValueStack(mlir::Location loc, fir::FirOpBuilder &builder,
126+
mlir::Type valueStaticType);
127+
128+
void pushValue(mlir::Location loc, fir::FirOpBuilder &builder,
129+
mlir::Value value);
130+
void resetFetchPosition(mlir::Location loc, fir::FirOpBuilder &builder);
131+
mlir::Value fetch(mlir::Location loc, fir::FirOpBuilder &builder);
132+
void destroy(mlir::Location loc, fir::FirOpBuilder &builder);
133+
134+
private:
135+
/// Keep the original value type. Values may be stored by the runtime
136+
/// with a different type (i1 cannot be passed by descriptor).
137+
mlir::Type valueStaticType;
138+
/// Runtime cookie created by the runtime. It is a pointer to an opaque
139+
/// runtime data structure that manages the stack.
140+
mlir::Value opaquePtr;
141+
/// Counter to keep track of the fetching position.
142+
Counter counter;
143+
/// Allocatable box passed to the runtime when fetching the values.
144+
mlir::Value retValueBox;
145+
};
146+
118147
/// Generic wrapper over the different sorts of temporary storages.
119148
class TemporaryStorage {
120149
public:
@@ -138,7 +167,7 @@ class TemporaryStorage {
138167
}
139168

140169
private:
141-
std::variant<HomogeneousScalarStack, SimpleCopy> impl;
170+
std::variant<HomogeneousScalarStack, SimpleCopy, AnyValueStack> impl;
142171
};
143172
} // namespace fir::factory
144173
#endif // FORTRAN_OPTIMIZER_BUILDER_TEMPORARYSTORAGE_H

flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ inline bool isBoxAddressOrValueType(mlir::Type type) {
6969
return fir::unwrapRefType(type).isa<fir::BaseBoxType>();
7070
}
7171

72+
inline bool isPolymorphicType(mlir::Type type) {
73+
if (auto exprType = type.dyn_cast<hlfir::ExprType>())
74+
return exprType.isPolymorphic();
75+
return fir::isPolymorphicType(type);
76+
}
77+
7278
bool isFortranScalarNumericalType(mlir::Type);
7379
bool isFortranNumericalArrayObject(mlir::Type);
7480
bool isFortranNumericalOrLogicalArrayObject(mlir::Type);

flang/lib/Optimizer/Builder/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_flang_library(FIRBuilder
2323
Runtime/Ragged.cpp
2424
Runtime/Reduction.cpp
2525
Runtime/Stop.cpp
26+
Runtime/TemporaryStack.cpp
2627
Runtime/Transformational.cpp
2728
TemporaryStorage.cpp
2829

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===- TemporaryStack.cpp ---- temporary stack runtime API calls ----------===//
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+
#include "flang/Optimizer/Builder/Runtime/TemporaryStack.h"
10+
#include "flang/Optimizer/Builder/FIRBuilder.h"
11+
#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
12+
#include "flang/Runtime/temporary-stack.h"
13+
14+
using namespace Fortran::runtime;
15+
16+
mlir::Value fir::runtime::genCreateValueStack(mlir::Location loc,
17+
fir::FirOpBuilder &builder) {
18+
mlir::func::FuncOp func =
19+
fir::runtime::getRuntimeFunc<mkRTKey(CreateValueStack)>(loc, builder);
20+
mlir::FunctionType funcType = func.getFunctionType();
21+
mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
22+
mlir::Value sourceLine =
23+
fir::factory::locationToLineNo(builder, loc, funcType.getInput(1));
24+
auto args = fir::runtime::createArguments(builder, loc, funcType, sourceFile,
25+
sourceLine);
26+
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
27+
}
28+
29+
void fir::runtime::genPushValue(mlir::Location loc, fir::FirOpBuilder &builder,
30+
mlir::Value opaquePtr, mlir::Value boxValue) {
31+
mlir::func::FuncOp func =
32+
fir::runtime::getRuntimeFunc<mkRTKey(PushValue)>(loc, builder);
33+
mlir::FunctionType funcType = func.getFunctionType();
34+
auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr,
35+
boxValue);
36+
builder.create<fir::CallOp>(loc, func, args);
37+
}
38+
39+
void fir::runtime::genValueAt(mlir::Location loc, fir::FirOpBuilder &builder,
40+
mlir::Value opaquePtr, mlir::Value i,
41+
mlir::Value retValueBox) {
42+
mlir::func::FuncOp func =
43+
fir::runtime::getRuntimeFunc<mkRTKey(ValueAt)>(loc, builder);
44+
mlir::FunctionType funcType = func.getFunctionType();
45+
auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr,
46+
i, retValueBox);
47+
builder.create<fir::CallOp>(loc, func, args);
48+
}
49+
50+
void fir::runtime::genDestroyValueStack(mlir::Location loc,
51+
fir::FirOpBuilder &builder,
52+
mlir::Value opaquePtr) {
53+
mlir::func::FuncOp func =
54+
fir::runtime::getRuntimeFunc<mkRTKey(DestroyValueStack)>(loc, builder);
55+
mlir::FunctionType funcType = func.getFunctionType();
56+
auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr);
57+
builder.create<fir::CallOp>(loc, func, args);
58+
}

flang/lib/Optimizer/Builder/TemporaryStorage.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flang/Optimizer/Builder/TemporaryStorage.h"
1313
#include "flang/Optimizer/Builder/FIRBuilder.h"
1414
#include "flang/Optimizer/Builder/HLFIRTools.h"
15+
#include "flang/Optimizer/Builder/Runtime/TemporaryStack.h"
1516
#include "flang/Optimizer/Builder/Todo.h"
1617
#include "flang/Optimizer/HLFIR/HLFIROps.h"
1718

@@ -154,3 +155,69 @@ void fir::factory::SimpleCopy::destroy(mlir::Location loc,
154155
fir::FirOpBuilder &builder) {
155156
builder.create<hlfir::EndAssociateOp>(loc, copy);
156157
}
158+
159+
//===----------------------------------------------------------------------===//
160+
// fir::factory::AnyValueStack implementation.
161+
//===----------------------------------------------------------------------===//
162+
163+
fir::factory::AnyValueStack::AnyValueStack(mlir::Location loc,
164+
fir::FirOpBuilder &builder,
165+
mlir::Type valueStaticType)
166+
: valueStaticType{valueStaticType},
167+
counter{loc, builder,
168+
builder.createIntegerConstant(loc, builder.getI64Type(), 0),
169+
/*stackThroughLoops=*/true} {
170+
opaquePtr = fir::runtime::genCreateValueStack(loc, builder);
171+
// Compute the storage type. I1 are stored as fir.logical<1>. This is required
172+
// to use descriptor.
173+
mlir::Type storageType =
174+
hlfir::getFortranElementOrSequenceType(valueStaticType);
175+
mlir::Type i1Type = builder.getI1Type();
176+
if (storageType == i1Type)
177+
storageType = fir::LogicalType::get(builder.getContext(), 1);
178+
assert(hlfir::getFortranElementType(storageType) != i1Type &&
179+
"array of i1 should not be used");
180+
mlir::Type heapType = fir::HeapType::get(storageType);
181+
mlir::Type boxType;
182+
if (hlfir::isPolymorphicType(valueStaticType))
183+
boxType = fir::ClassType::get(heapType);
184+
else
185+
boxType = fir::BoxType::get(heapType);
186+
retValueBox = builder.createTemporary(loc, boxType);
187+
}
188+
189+
void fir::factory::AnyValueStack::pushValue(mlir::Location loc,
190+
fir::FirOpBuilder &builder,
191+
mlir::Value value) {
192+
hlfir::Entity entity{value};
193+
mlir::Type storageElementType =
194+
hlfir::getFortranElementType(retValueBox.getType());
195+
auto [box, maybeCleanUp] =
196+
hlfir::convertToBox(loc, builder, entity, storageElementType);
197+
fir::runtime::genPushValue(loc, builder, opaquePtr, fir::getBase(box));
198+
if (maybeCleanUp)
199+
(*maybeCleanUp)();
200+
}
201+
202+
void fir::factory::AnyValueStack::resetFetchPosition(
203+
mlir::Location loc, fir::FirOpBuilder &builder) {
204+
counter.reset(loc, builder);
205+
}
206+
207+
mlir::Value fir::factory::AnyValueStack::fetch(mlir::Location loc,
208+
fir::FirOpBuilder &builder) {
209+
mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder);
210+
fir::runtime::genValueAt(loc, builder, opaquePtr, indexValue, retValueBox);
211+
/// Dereference the allocatable "retValueBox", and load if trivial scalar
212+
/// value.
213+
mlir::Value result =
214+
hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{retValueBox});
215+
if (valueStaticType == builder.getI1Type())
216+
return builder.createConvert(loc, valueStaticType, result);
217+
return result;
218+
}
219+
220+
void fir::factory::AnyValueStack::destroy(mlir::Location loc,
221+
fir::FirOpBuilder &builder) {
222+
fir::runtime::genDestroyValueStack(loc, builder, opaquePtr);
223+
}

flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,8 @@ void OrderedAssignmentRewriter::generateSaveEntity(
895895
// iterations are values that may have different shape, type parameters
896896
// or dynamic type, use the runtime to create and manage a stack-like
897897
// temporary.
898-
TODO(loc, "use runtime to create temporary storage in FORALL or WHERE");
898+
temp = insertSavedEntity(
899+
region, fir::factory::AnyValueStack{loc, builder, entityType});
899900
}
900901
});
901902
// Inside the loop nest (and any fir.if if there are active masks), copy

0 commit comments

Comments
 (0)