Skip to content

Commit c807aa5

Browse files
[flang] Handle lowering of ranked array
This patch adds lowering of ranked array as function return. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: PeteSteinfeld Differential Revision: https://reviews.llvm.org/D119835 Co-authored-by: Jean Perier <jperier@nvidia.com>
1 parent bfc1217 commit c807aa5

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

flang/lib/Lower/CallInterface.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,21 @@ class Fortran::lower::CallInterfaceImpl {
155155
FirPlaceHolder::resultEntityPosition, Property::Value);
156156
}
157157

158+
void buildExplicitInterface(
159+
const Fortran::evaluate::characteristics::Procedure &procedure) {
160+
// Handle result
161+
if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
162+
&result = procedure.functionResult) {
163+
if (result->CanBeReturnedViaImplicitInterface())
164+
handleImplicitResult(*result);
165+
else
166+
handleExplicitResult(*result);
167+
} else if (interface.side().hasAlternateReturns()) {
168+
addFirResult(mlir::IndexType::get(&mlirContext),
169+
FirPlaceHolder::resultEntityPosition, Property::Value);
170+
}
171+
}
172+
158173
private:
159174
void handleImplicitResult(
160175
const Fortran::evaluate::characteristics::FunctionResult &result) {
@@ -182,6 +197,57 @@ class Fortran::lower::CallInterfaceImpl {
182197
}
183198
}
184199

200+
void handleExplicitResult(
201+
const Fortran::evaluate::characteristics::FunctionResult &result) {
202+
using Attr = Fortran::evaluate::characteristics::FunctionResult::Attr;
203+
204+
if (result.IsProcedurePointer())
205+
TODO(interface.converter.getCurrentLocation(),
206+
"procedure pointer results");
207+
const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
208+
result.GetTypeAndShape();
209+
assert(typeAndShape && "expect type for non proc pointer result");
210+
Fortran::evaluate::DynamicType dynamicType = typeAndShape->type();
211+
if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
212+
TODO(interface.converter.getCurrentLocation(),
213+
"implicit result character type");
214+
} else if (dynamicType.category() ==
215+
Fortran::common::TypeCategory::Derived) {
216+
TODO(interface.converter.getCurrentLocation(),
217+
"implicit result derived type");
218+
}
219+
mlir::Type mlirType =
220+
getConverter().genType(dynamicType.category(), dynamicType.kind());
221+
fir::SequenceType::Shape bounds = getBounds(typeAndShape->shape());
222+
if (!bounds.empty())
223+
mlirType = fir::SequenceType::get(bounds, mlirType);
224+
if (result.attrs.test(Attr::Allocatable))
225+
mlirType = fir::BoxType::get(fir::HeapType::get(mlirType));
226+
if (result.attrs.test(Attr::Pointer))
227+
mlirType = fir::BoxType::get(fir::PointerType::get(mlirType));
228+
229+
addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
230+
Property::Value);
231+
}
232+
233+
fir::SequenceType::Shape getBounds(const Fortran::evaluate::Shape &shape) {
234+
fir::SequenceType::Shape bounds;
235+
for (Fortran::evaluate::MaybeExtentExpr extentExpr : shape) {
236+
fir::SequenceType::Extent extent = fir::SequenceType::getUnknownExtent();
237+
if (std::optional<std::int64_t> constantExtent =
238+
toInt64(std::move(extentExpr)))
239+
extent = *constantExtent;
240+
bounds.push_back(extent);
241+
}
242+
return bounds;
243+
}
244+
245+
template <typename A>
246+
std::optional<std::int64_t> toInt64(A &&expr) {
247+
return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
248+
getConverter().getFoldingContext(), std::move(expr)));
249+
}
250+
185251
void addFirResult(mlir::Type type, int entityPosition, Property p) {
186252
interface.outputs.emplace_back(FirPlaceHolder{type, entityPosition, p});
187253
}
@@ -201,7 +267,7 @@ void Fortran::lower::CallInterface<T>::determineInterface(
201267
if (isImplicit)
202268
impl.buildImplicitInterface(procedure);
203269
else
204-
TODO_NOLOC("determineImplicitInterface");
270+
impl.buildExplicitInterface(procedure);
205271
}
206272

207273
template <typename T>

flang/lib/Lower/ConvertType.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ class TypeBuilder {
154154
TypeBuilder(Fortran::lower::AbstractConverter &converter)
155155
: converter{converter}, context{&converter.getMLIRContext()} {}
156156

157+
template <typename A>
158+
void translateShape(A &shape, Fortran::evaluate::Shape &&shapeExpr) {
159+
for (Fortran::evaluate::MaybeExtentExpr extentExpr : shapeExpr) {
160+
fir::SequenceType::Extent extent = fir::SequenceType::getUnknownExtent();
161+
if (std::optional<std::int64_t> constantExtent =
162+
toInt64(std::move(extentExpr)))
163+
extent = *constantExtent;
164+
shape.push_back(extent);
165+
}
166+
}
167+
157168
template <typename A>
158169
std::optional<std::int64_t> toInt64(A &&expr) {
159170
return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
@@ -186,6 +197,15 @@ class TypeBuilder {
186197
} else {
187198
fir::emitFatalError(loc, "symbol must have a type");
188199
}
200+
if (ultimate.IsObjectArray()) {
201+
auto shapeExpr = Fortran::evaluate::GetShapeHelper{
202+
converter.getFoldingContext()}(ultimate);
203+
if (!shapeExpr)
204+
TODO(loc, "assumed rank symbol type lowering");
205+
fir::SequenceType::Shape shape;
206+
translateShape(shape, std::move(*shapeExpr));
207+
ty = fir::SequenceType::get(shape, ty);
208+
}
189209

190210
if (Fortran::semantics::IsPointer(symbol))
191211
return fir::BoxType::get(fir::PointerType::get(ty));

flang/test/Lower/basic-function.f90

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,34 @@ integer function fct_body()
4848
! CHECK: %{{.*}} = fir.call @_FortranAStopStatement
4949
! CHECK: fir.unreachable
5050

51+
function fct_iarr1()
52+
integer, dimension(10) :: fct_iarr1
53+
end
54+
55+
! CHECK-LABEL: func @_QPfct_iarr1() -> !fir.array<10xi32>
56+
! CHECK: return %{{.*}} : !fir.array<10xi32>
57+
58+
function fct_iarr2()
59+
integer, dimension(10, 20) :: fct_iarr2
60+
end
61+
62+
! CHECK-LABEL: func @_QPfct_iarr2() -> !fir.array<10x20xi32>
63+
! CHECK: return %{{.*}} : !fir.array<10x20xi32>
64+
65+
function fct_iarr3()
66+
integer, dimension(:, :), allocatable :: fct_iarr3
67+
end
68+
69+
! CHECK-LABEL: func @_QPfct_iarr3() -> !fir.box<!fir.heap<!fir.array<?x?xi32>>>
70+
! CHECK: return %{{.*}} : !fir.box<!fir.heap<!fir.array<?x?xi32>>>
71+
72+
function fct_iarr4()
73+
integer, dimension(:), pointer :: fct_iarr4
74+
end
75+
76+
! CHECK-LABEL: func @_QPfct_iarr4() -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
77+
! CHECK: return %{{.*}} : !fir.box<!fir.ptr<!fir.array<?xi32>>>
78+
5179
logical(1) function lfct1()
5280
end
5381
! CHECK-LABEL: func @_QPlfct1() -> !fir.logical<1>

0 commit comments

Comments
 (0)