|
17 | 17 | #include "flang/Lower/Allocatable.h"
|
18 | 18 | #include "flang/Lower/CallInterface.h"
|
19 | 19 | #include "flang/Lower/CharacterExpr.h"
|
| 20 | +#include "flang/Lower/CharacterRuntime.h" |
20 | 21 | #include "flang/Lower/Coarray.h"
|
21 | 22 | #include "flang/Lower/ConvertExpr.h"
|
22 | 23 | #include "flang/Lower/ConvertType.h"
|
@@ -395,6 +396,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
|
395 | 396 | return cat == Fortran::common::TypeCategory::Derived;
|
396 | 397 | }
|
397 | 398 |
|
| 399 | + /// Insert a new block before \p block. Leave the insertion point unchanged. |
| 400 | + mlir::Block *insertBlock(mlir::Block *block) { |
| 401 | + auto insertPt = builder->saveInsertionPoint(); |
| 402 | + auto newBlock = builder->createBlock(block); |
| 403 | + builder->restoreInsertionPoint(insertPt); |
| 404 | + return newBlock; |
| 405 | + } |
| 406 | + |
398 | 407 | mlir::Block *blockOfLabel(Fortran::lower::pft::Evaluation &eval,
|
399 | 408 | Fortran::parser::Label label) {
|
400 | 409 | const auto &labelEvaluationMap =
|
@@ -791,10 +800,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
|
791 | 800 | // exit block of the immediately enclosed dimension.
|
792 | 801 | auto createNextExitBlock = [&]() {
|
793 | 802 | // Create unstructured loop exit blocks, outermost to innermost.
|
794 |
| - auto insertPt = builder->saveInsertionPoint(); |
795 |
| - exitBlock = builder->createBlock(exitBlock); |
796 |
| - builder->restoreInsertionPoint(insertPt); |
797 |
| - return exitBlock; |
| 803 | + return exitBlock = insertBlock(exitBlock); |
798 | 804 | };
|
799 | 805 | auto isInnermost = &info == &incrementLoopNestInfo.back();
|
800 | 806 | auto isOutermost = &info == &incrementLoopNestInfo.front();
|
@@ -1130,36 +1136,53 @@ class FirConverter : public Fortran::lower::AbstractConverter {
|
1130 | 1136 | builder->restoreInsertionPoint(insertPt);
|
1131 | 1137 | }
|
1132 | 1138 |
|
| 1139 | + /// Generate FIR for a SELECT CASE statement. |
| 1140 | + /// The type may be CHARACTER, INTEGER, or LOGICAL. |
1133 | 1141 | void genFIR(const Fortran::parser::SelectCaseStmt &stmt) {
|
1134 | 1142 | auto &eval = getEval();
|
1135 | 1143 | auto *context = builder->getContext();
|
1136 | 1144 | auto loc = toLocation();
|
1137 | 1145 | Fortran::lower::StatementContext stmtCtx;
|
1138 | 1146 | const auto *expr = Fortran::semantics::GetExpr(
|
1139 | 1147 | std::get<Fortran::parser::Scalar<Fortran::parser::Expr>>(stmt.t));
|
1140 |
| - auto exprType = expr->GetType(); |
1141 |
| - mlir::Value selectExpr; |
1142 |
| - if (isCharacterCategory(exprType->category())) { |
1143 |
| - TODO(loc, "Select Case selector of type Character"); |
| 1148 | + bool isCharSelector = isCharacterCategory(expr->GetType()->category()); |
| 1149 | + bool isLogicalSelector = isLogicalCategory(expr->GetType()->category()); |
| 1150 | + auto charValue = [&](const Fortran::lower::SomeExpr *expr) { |
| 1151 | + fir::ExtendedValue exv = genExprAddr(*expr, stmtCtx, &loc); |
| 1152 | + return exv.match( |
| 1153 | + [&](const fir::CharBoxValue &cbv) { |
| 1154 | + return Fortran::lower::CharacterExprHelper{*builder, loc} |
| 1155 | + .createEmboxChar(cbv.getAddr(), cbv.getLen()); |
| 1156 | + }, |
| 1157 | + [&](auto) { |
| 1158 | + fir::emitFatalError(loc, "not a character"); |
| 1159 | + return mlir::Value{}; |
| 1160 | + }); |
| 1161 | + }; |
| 1162 | + mlir::Value selector; |
| 1163 | + if (isCharSelector) { |
| 1164 | + selector = charValue(expr); |
1144 | 1165 | } else {
|
1145 |
| - selectExpr = createFIRExpr(loc, expr, stmtCtx); |
1146 |
| - if (isLogicalCategory(exprType->category())) |
1147 |
| - selectExpr = |
1148 |
| - builder->createConvert(loc, builder->getI1Type(), selectExpr); |
| 1166 | + selector = createFIRExpr(loc, expr, stmtCtx); |
| 1167 | + if (isLogicalSelector) |
| 1168 | + selector = builder->createConvert(loc, builder->getI1Type(), selector); |
1149 | 1169 | }
|
1150 |
| - auto selectType = selectExpr.getType(); |
1151 |
| - llvm::SmallVector<mlir::Attribute, 10> attrList; |
1152 |
| - llvm::SmallVector<mlir::Value, 10> valueList; |
1153 |
| - llvm::SmallVector<mlir::Block *, 10> blockList; |
| 1170 | + auto selectType = selector.getType(); |
| 1171 | + llvm::SmallVector<mlir::Attribute> attrList; |
| 1172 | + llvm::SmallVector<mlir::Value> valueList; |
| 1173 | + llvm::SmallVector<mlir::Block *> blockList; |
1154 | 1174 | auto *defaultBlock = eval.parentConstruct->constructExit->block;
|
1155 | 1175 | using CaseValue = Fortran::parser::Scalar<Fortran::parser::ConstantExpr>;
|
1156 | 1176 | auto addValue = [&](const CaseValue &caseValue) {
|
1157 | 1177 | const auto *expr = Fortran::semantics::GetExpr(caseValue.thing);
|
1158 |
| - const auto v = Fortran::evaluate::ToInt64(*expr); |
1159 |
| - valueList.push_back( |
1160 |
| - v ? builder->createIntegerConstant(loc, selectType, *v) |
1161 |
| - : builder->createConvert( |
1162 |
| - loc, selectType, createFIRExpr(toLocation(), expr, stmtCtx))); |
| 1178 | + if (isCharSelector) |
| 1179 | + valueList.push_back(charValue(expr)); |
| 1180 | + else if (isLogicalSelector) |
| 1181 | + valueList.push_back(builder->createConvert( |
| 1182 | + loc, selectType, createFIRExpr(toLocation(), expr, stmtCtx))); |
| 1183 | + else |
| 1184 | + valueList.push_back(builder->createIntegerConstant( |
| 1185 | + loc, selectType, *Fortran::evaluate::ToInt64(*expr))); |
1163 | 1186 | };
|
1164 | 1187 | for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
|
1165 | 1188 | e = e->controlSuccessor) {
|
@@ -1197,13 +1220,65 @@ class FirConverter : public Fortran::lower::AbstractConverter {
|
1197 | 1220 | }
|
1198 | 1221 | }
|
1199 | 1222 | // Skip a logical default block that can never be referenced.
|
1200 |
| - if (selectType == builder->getI1Type() && attrList.size() == 2) |
| 1223 | + if (isLogicalSelector && attrList.size() == 2) |
1201 | 1224 | defaultBlock = eval.parentConstruct->constructExit->block;
|
1202 | 1225 | attrList.push_back(mlir::UnitAttr::get(context));
|
1203 | 1226 | blockList.push_back(defaultBlock);
|
1204 | 1227 | stmtCtx.finalize();
|
1205 |
| - builder->create<fir::SelectCaseOp>(toLocation(), selectExpr, attrList, |
1206 |
| - valueList, blockList); |
| 1228 | + |
| 1229 | + // Generate a fir::SelectCaseOp. |
| 1230 | + // Explicit branch code is better for the LOGICAL type. The CHARACTER type |
| 1231 | + // does not yet have downstream support, and also uses explicit branch code. |
| 1232 | + // The -no-structured-fir option can be used to force generation of INTEGER |
| 1233 | + // type branch code. |
| 1234 | + if (!isLogicalSelector && !isCharSelector && eval.lowerAsStructured()) { |
| 1235 | + builder->create<fir::SelectCaseOp>(loc, selector, attrList, valueList, |
| 1236 | + blockList); |
| 1237 | + return; |
| 1238 | + } |
| 1239 | + |
| 1240 | + // Generate a sequence of case value comparisons and branches. |
| 1241 | + auto caseValue = valueList.begin(); |
| 1242 | + auto caseBlock = blockList.begin(); |
| 1243 | + for (auto attr : attrList) { |
| 1244 | + if (attr.isa<mlir::UnitAttr>()) { |
| 1245 | + genFIRBranch(*caseBlock++); |
| 1246 | + break; |
| 1247 | + } |
| 1248 | + auto genCond = [&](mlir::Value rhs, |
| 1249 | + mlir::CmpIPredicate pred) -> mlir::Value { |
| 1250 | + if (!isCharSelector) |
| 1251 | + return builder->create<mlir::CmpIOp>(loc, pred, selector, rhs); |
| 1252 | + Fortran::lower::CharacterExprHelper charHelper{*builder, loc}; |
| 1253 | + auto [lhsAddr, lhsLen] = charHelper.createUnboxChar(selector); |
| 1254 | + auto [rhsAddr, rhsLen] = charHelper.createUnboxChar(rhs); |
| 1255 | + return Fortran::lower::genRawCharCompare(*builder, loc, pred, lhsAddr, |
| 1256 | + lhsLen, rhsAddr, rhsLen); |
| 1257 | + }; |
| 1258 | + auto *newBlock = insertBlock(*caseBlock); |
| 1259 | + if (attr.isa<fir::ClosedIntervalAttr>()) { |
| 1260 | + auto *newBlock2 = insertBlock(*caseBlock); |
| 1261 | + auto cond = genCond(*caseValue++, mlir::CmpIPredicate::sge); |
| 1262 | + genFIRConditionalBranch(cond, newBlock, newBlock2); |
| 1263 | + builder->setInsertionPointToEnd(newBlock); |
| 1264 | + auto cond2 = genCond(*caseValue++, mlir::CmpIPredicate::sle); |
| 1265 | + genFIRConditionalBranch(cond2, *caseBlock++, newBlock2); |
| 1266 | + builder->setInsertionPointToEnd(newBlock2); |
| 1267 | + continue; |
| 1268 | + } |
| 1269 | + mlir::CmpIPredicate pred; |
| 1270 | + if (attr.isa<fir::PointIntervalAttr>()) |
| 1271 | + pred = mlir::CmpIPredicate::eq; |
| 1272 | + else if (attr.isa<fir::LowerBoundAttr>()) |
| 1273 | + pred = mlir::CmpIPredicate::sge; |
| 1274 | + else if (attr.isa<fir::UpperBoundAttr>()) |
| 1275 | + pred = mlir::CmpIPredicate::sle; |
| 1276 | + auto cond = genCond(*caseValue++, pred); |
| 1277 | + genFIRConditionalBranch(cond, *caseBlock++, newBlock); |
| 1278 | + builder->setInsertionPointToEnd(newBlock); |
| 1279 | + } |
| 1280 | + assert(caseValue == valueList.end() && caseBlock == blockList.end() && |
| 1281 | + "select case list mismatch"); |
1207 | 1282 | }
|
1208 | 1283 |
|
1209 | 1284 | void genFIR(const Fortran::parser::AssociateConstruct &) {
|
|
0 commit comments