@@ -141,6 +141,8 @@ struct ConstructContext {
141
141
142
142
Fortran::lower::pft::Evaluation &eval; // construct eval
143
143
Fortran::lower::StatementContext &stmtCtx; // construct exit code
144
+ std::optional<hlfir::Entity> selector; // construct selector, if any.
145
+ bool pushedScope = false ; // was a scoped pushed for this construct?
144
146
};
145
147
146
148
// / Helper class to generate the runtime type info global data and the
@@ -1468,6 +1470,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
1468
1470
void popActiveConstruct () {
1469
1471
assert (!activeConstructStack.empty () && " invalid active construct stack" );
1470
1472
activeConstructStack.back ().eval .activeConstruct = false ;
1473
+ if (activeConstructStack.back ().pushedScope )
1474
+ localSymbols.popScope ();
1471
1475
activeConstructStack.pop_back ();
1472
1476
}
1473
1477
@@ -2181,7 +2185,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2181
2185
}
2182
2186
}
2183
2187
2184
- void genFIR ( const Fortran::parser::CaseConstruct & ) {
2188
+ void genCaseOrRankConstruct ( ) {
2185
2189
Fortran::lower::pft::Evaluation &eval = getEval ();
2186
2190
Fortran::lower::StatementContext stmtCtx;
2187
2191
pushActiveConstruct (eval, stmtCtx);
@@ -2203,6 +2207,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
2203
2207
}
2204
2208
popActiveConstruct ();
2205
2209
}
2210
+ void genFIR (const Fortran::parser::CaseConstruct &) {
2211
+ genCaseOrRankConstruct ();
2212
+ }
2206
2213
2207
2214
template <typename A>
2208
2215
void genNestedStatement (const Fortran::parser::Statement<A> &stmt) {
@@ -3032,13 +3039,198 @@ class FirConverter : public Fortran::lower::AbstractConverter {
3032
3039
3033
3040
void genFIR (const Fortran::parser::SelectRankConstruct &selectRankConstruct) {
3034
3041
setCurrentPositionAt (selectRankConstruct);
3035
- TODO ( toLocation (), " coarray: SelectRankConstruct " );
3042
+ genCaseOrRankConstruct ( );
3036
3043
}
3037
- void genFIR (const Fortran::parser::SelectRankStmt &) {
3038
- TODO (toLocation (), " coarray: SelectRankStmt" );
3044
+
3045
+ void genFIR (const Fortran::parser::SelectRankStmt &selectRankStmt) {
3046
+ // Generate a fir.select_case with the selector rank. The RANK(*) case,
3047
+ // if any, is handles with a conditional branch before the fir.select_case.
3048
+ mlir::Type rankType = builder->getIntegerType (8 );
3049
+ mlir::MLIRContext *context = builder->getContext ();
3050
+ mlir::Location loc = toLocation ();
3051
+ // Build block list for fir.select_case, and identify RANK(*) block, if any.
3052
+ // Default block must be placed last in the fir.select_case block list.
3053
+ mlir::Block *rankStarBlock = nullptr ;
3054
+ Fortran::lower::pft::Evaluation &eval = getEval ();
3055
+ mlir::Block *defaultBlock = eval.parentConstruct ->constructExit ->block ;
3056
+ llvm::SmallVector<mlir::Attribute> attrList;
3057
+ llvm::SmallVector<mlir::Value> valueList;
3058
+ llvm::SmallVector<mlir::Block *> blockList;
3059
+ for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor ; e;
3060
+ e = e->controlSuccessor ) {
3061
+ if (const auto *rankCaseStmt =
3062
+ e->getIf <Fortran::parser::SelectRankCaseStmt>()) {
3063
+ const auto &rank = std::get<Fortran::parser::SelectRankCaseStmt::Rank>(
3064
+ rankCaseStmt->t );
3065
+ assert (e->block && " missing SelectRankCaseStmt block" );
3066
+ std::visit (
3067
+ Fortran::common::visitors{
3068
+ [&](const Fortran::parser::ScalarIntConstantExpr &rankExpr) {
3069
+ blockList.emplace_back (e->block );
3070
+ attrList.emplace_back (fir::PointIntervalAttr::get (context));
3071
+ std::optional<std::int64_t > rankCst =
3072
+ Fortran::evaluate::ToInt64 (
3073
+ Fortran::semantics::GetExpr (rankExpr));
3074
+ assert (rankCst.has_value () &&
3075
+ " rank expr must be constant integer" );
3076
+ valueList.emplace_back (
3077
+ builder->createIntegerConstant (loc, rankType, *rankCst));
3078
+ },
3079
+ [&](const Fortran::parser::Star &) {
3080
+ rankStarBlock = e->block ;
3081
+ },
3082
+ [&](const Fortran::parser::Default &) {
3083
+ defaultBlock = e->block ;
3084
+ }},
3085
+ rank.u );
3086
+ }
3087
+ }
3088
+ attrList.push_back (mlir::UnitAttr::get (context));
3089
+ blockList.push_back (defaultBlock);
3090
+
3091
+ // Lower selector.
3092
+ assert (!activeConstructStack.empty () && " must be inside construct" );
3093
+ assert (!activeConstructStack.back ().selector &&
3094
+ " selector should not yet be set" );
3095
+ Fortran::lower::StatementContext &stmtCtx =
3096
+ activeConstructStack.back ().stmtCtx ;
3097
+ const Fortran::lower::SomeExpr *selectorExpr =
3098
+ std::visit ([](const auto &x) { return Fortran::semantics::GetExpr (x); },
3099
+ std::get<Fortran::parser::Selector>(selectRankStmt.t ).u );
3100
+ assert (selectorExpr && " failed to retrieve selector expr" );
3101
+ hlfir::Entity selector = Fortran::lower::convertExprToHLFIR (
3102
+ loc, *this , *selectorExpr, localSymbols, stmtCtx);
3103
+ activeConstructStack.back ().selector = selector;
3104
+
3105
+ // Deal with assumed-size first. They must fall into RANK(*) if present, or
3106
+ // the default case (F'2023 11.1.10.2.). The selector cannot be an
3107
+ // assumed-size if it is allocatable or pointer, so the check is skipped.
3108
+ if (!Fortran::evaluate::IsAllocatableOrPointerObject (*selectorExpr)) {
3109
+ mlir::Value isAssumedSize = builder->create <fir::IsAssumedSizeOp>(
3110
+ loc, builder->getI1Type (), selector);
3111
+ // Create new block to hold the fir.select_case for the non assumed-size
3112
+ // cases.
3113
+ mlir::Block *selectCaseBlock = insertBlock (blockList[0 ]);
3114
+ mlir::Block *assumedSizeBlock =
3115
+ rankStarBlock ? rankStarBlock : defaultBlock;
3116
+ builder->create <mlir::cf::CondBranchOp>(loc, isAssumedSize,
3117
+ assumedSizeBlock, std::nullopt,
3118
+ selectCaseBlock, std::nullopt);
3119
+ startBlock (selectCaseBlock);
3120
+ }
3121
+ // Create fir.select_case for the other rank cases.
3122
+ mlir::Value rank = builder->create <fir::BoxRankOp>(loc, rankType, selector);
3123
+ stmtCtx.finalizeAndReset ();
3124
+ builder->create <fir::SelectCaseOp>(loc, rank, attrList, valueList,
3125
+ blockList);
3126
+ }
3127
+
3128
+ // Get associating entity symbol inside case statement scope.
3129
+ static const Fortran::semantics::Symbol &
3130
+ getAssociatingEntitySymbol (const Fortran::semantics::Scope &scope) {
3131
+ const Fortran::semantics::Symbol *assocSym = nullptr ;
3132
+ for (const auto &sym : scope.GetSymbols ()) {
3133
+ if (sym->has <Fortran::semantics::AssocEntityDetails>()) {
3134
+ assert (!assocSym &&
3135
+ " expect only one associating entity symbol in this scope" );
3136
+ assocSym = &*sym;
3137
+ }
3138
+ }
3139
+ assert (assocSym && " should contain associating entity symbol" );
3140
+ return *assocSym;
3039
3141
}
3040
- void genFIR (const Fortran::parser::SelectRankCaseStmt &) {
3041
- TODO (toLocation (), " coarray: SelectRankCaseStmt" );
3142
+
3143
+ void genFIR (const Fortran::parser::SelectRankCaseStmt &stmt) {
3144
+ assert (!activeConstructStack.empty () &&
3145
+ " must be inside select rank construct" );
3146
+ // Pop previous associating entity mapping, if any, and push scope for new
3147
+ // mapping.
3148
+ if (activeConstructStack.back ().pushedScope )
3149
+ localSymbols.popScope ();
3150
+ localSymbols.pushScope ();
3151
+ activeConstructStack.back ().pushedScope = true ;
3152
+ const Fortran::semantics::Symbol &assocEntitySymbol =
3153
+ getAssociatingEntitySymbol (
3154
+ bridge.getSemanticsContext ().FindScope (getEval ().position ));
3155
+ const auto &details =
3156
+ assocEntitySymbol.get <Fortran::semantics::AssocEntityDetails>();
3157
+ assert (!activeConstructStack.empty () &&
3158
+ activeConstructStack.back ().selector .has_value () &&
3159
+ " selector must have been created" );
3160
+ // Get lowered value for the selector.
3161
+ hlfir::Entity selector = *activeConstructStack.back ().selector ;
3162
+ assert (selector.isVariable () && " assumed-rank selector are variables" );
3163
+ // Cook selector mlir::Value according to rank case and map it to
3164
+ // associating entity symbol.
3165
+ Fortran::lower::StatementContext stmtCtx;
3166
+ mlir::Location loc = toLocation ();
3167
+ if (details.IsAssumedRank ()) {
3168
+ fir::ExtendedValue selectorExv = Fortran::lower::translateToExtendedValue (
3169
+ loc, *builder, selector, stmtCtx);
3170
+ addSymbol (assocEntitySymbol, selectorExv);
3171
+ } else if (details.IsAssumedSize ()) {
3172
+ // Create rank-1 assumed-size from descriptor. Assumed-size are contiguous
3173
+ // so a new entity can be built from scratch using the base address, type
3174
+ // parameters and dynamic type. The selector cannot be a
3175
+ // POINTER/ALLOCATBLE as per F'2023 C1160.
3176
+ fir::ExtendedValue newExv;
3177
+ llvm::SmallVector assumeSizeExtents{
3178
+ builder->createMinusOneInteger (loc, builder->getIndexType ())};
3179
+ mlir::Value baseAddr =
3180
+ hlfir::genVariableRawAddress (loc, *builder, selector);
3181
+ mlir::Type eleType =
3182
+ fir::unwrapSequenceType (fir::unwrapRefType (baseAddr.getType ()));
3183
+ mlir::Type rank1Type =
3184
+ fir::ReferenceType::get (builder->getVarLenSeqTy (eleType, 1 ));
3185
+ baseAddr = builder->createConvert (loc, rank1Type, baseAddr);
3186
+ if (selector.isCharacter ()) {
3187
+ mlir::Value len = hlfir::genCharLength (loc, *builder, selector);
3188
+ newExv = fir::CharArrayBoxValue{baseAddr, len, assumeSizeExtents};
3189
+ } else if (selector.isDerivedWithLengthParameters ()) {
3190
+ TODO (loc, " RANK(*) with parameterized derived type selector" );
3191
+ } else if (selector.isPolymorphic ()) {
3192
+ TODO (loc, " RANK(*) with polymorphic selector" );
3193
+ } else {
3194
+ // Simple intrinsic or derived type.
3195
+ newExv = fir::ArrayBoxValue{baseAddr, assumeSizeExtents};
3196
+ }
3197
+ addSymbol (assocEntitySymbol, newExv);
3198
+ } else {
3199
+ int rank = details.rank ().value ();
3200
+ auto boxTy =
3201
+ mlir::cast<fir::BaseBoxType>(fir::unwrapRefType (selector.getType ()));
3202
+ mlir::Type newBoxType = boxTy.getBoxTypeWithNewShape (rank);
3203
+ if (fir::isa_ref_type (selector.getType ()))
3204
+ newBoxType = fir::ReferenceType::get (newBoxType);
3205
+ // Give rank info to value via cast, and get rid of the box if not needed
3206
+ // (simple scalars, contiguous arrays... This is done by
3207
+ // translateVariableToExtendedValue).
3208
+ hlfir::Entity rankedBox{
3209
+ builder->createConvert (loc, newBoxType, selector)};
3210
+ bool isSimplyContiguous = Fortran::evaluate::IsSimplyContiguous (
3211
+ assocEntitySymbol, getFoldingContext ());
3212
+ fir::ExtendedValue newExv = Fortran::lower::translateToExtendedValue (
3213
+ loc, *builder, rankedBox, stmtCtx, isSimplyContiguous);
3214
+
3215
+ // Non deferred length parameters of character allocatable/pointer
3216
+ // MutableBoxValue should be properly set before binding it to a symbol in
3217
+ // order to get correct assignment semantics.
3218
+ if (const fir::MutableBoxValue *mutableBox =
3219
+ newExv.getBoxOf <fir::MutableBoxValue>()) {
3220
+ if (selector.isCharacter ()) {
3221
+ auto dynamicType =
3222
+ Fortran::evaluate::DynamicType::From (assocEntitySymbol);
3223
+ if (!dynamicType.value ().HasDeferredTypeParameter ()) {
3224
+ llvm::SmallVector<mlir::Value> lengthParams;
3225
+ hlfir::genLengthParameters (loc, *builder, selector, lengthParams);
3226
+ newExv = fir::MutableBoxValue{rankedBox, lengthParams,
3227
+ mutableBox->getMutableProperties ()};
3228
+ }
3229
+ }
3230
+ }
3231
+ addSymbol (assocEntitySymbol, newExv);
3232
+ }
3233
+ // Statements inside rank case are lowered by SelectRankConstruct visit.
3042
3234
}
3043
3235
3044
3236
void genFIR (const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) {
0 commit comments