[flang-commits] [flang] [flang] Enumeration Type: (PR 4/5) Lowering (PR #193571)
via flang-commits
flang-commits at lists.llvm.org
Sat Oct 10 19:49:15 PDT 2026
================
@@ -1727,12 +1728,187 @@ class HlfirBuilder {
gen(const Fortran::evaluate::FunctionRef<T> &expr) {
mlir::Type resType =
Fortran::lower::TypeBuilder<T>::genType(getConverter(), expr);
+
+ if constexpr (std::is_same_v<T, Fortran::evaluate::SomeDerived>) {
+ if (const auto *intrinsic = expr.proc().GetSpecificIntrinsic();
+ intrinsic && intrinsic->name == "huge")
+ return genEnumerationHuge(expr, resType);
+ }
+
+ if constexpr (T::category == Fortran::common::TypeCategory::Integer) {
+ if (const auto *intrinsic = expr.proc().GetSpecificIntrinsic();
+ intrinsic && intrinsic->name == "int" && !expr.arguments().empty() &&
+ expr.arguments()[0])
+ if (const auto *arg = expr.arguments()[0]->UnwrapExpr())
+ if (const auto *spec =
+ Fortran::evaluate::GetDerivedTypeSpec(arg->GetType());
+ spec && Fortran::semantics::IsEnumerationType(spec->typeSymbol()))
+ return genEnumerationInt(*arg, resType);
+ }
+
auto result = Fortran::lower::convertCallToHLFIR(
getLoc(), getConverter(), expr, resType, getSymMap(), getStmtCtx());
assert(result.has_value());
return *result;
}
+ // Number of enumerators of the enumeration type returned by expr.
+ int getEnumerationEnumeratorCount(
+ const Fortran::evaluate::FunctionRef<Fortran::evaluate::SomeDerived>
+ &expr,
+ llvm::StringRef name) {
+ auto resultDynType = expr.proc().GetType();
+ assert(resultDynType && (name + " must have a result type").str().c_str());
+ const auto *derived = Fortran::evaluate::GetDerivedTypeSpec(*resultDynType);
+ assert(derived &&
+ derived->typeSymbol()
+ .detailsIf<Fortran::semantics::DerivedTypeDetails>() &&
+ derived->typeSymbol()
+ .detailsIf<Fortran::semantics::DerivedTypeDetails>()
+ ->isEnumerationType() &&
+ (name + " result must be enumeration type").str().c_str());
+ return derived->typeSymbol()
+ .GetUltimate()
+ .get<Fortran::semantics::DerivedTypeDetails>()
+ .enumeratorCount();
+ }
+
+ // Lower HUGE(enumVar) for non-constant enumeration arguments.
+ // Should always be folded, but handle as a constant just in case.
+ hlfir::EntityWithAttributes genEnumerationHuge(
+ const Fortran::evaluate::FunctionRef<Fortran::evaluate::SomeDerived>
+ &expr,
+ mlir::Type resType) {
+ mlir::Location loc = getLoc();
+ fir::FirOpBuilder &builder = getBuilder();
+ int count = getEnumerationEnumeratorCount(expr, "HUGE");
+ mlir::Value last =
+ builder.createIntegerConstant(loc, builder.getI32Type(), count);
+ return Fortran::lower::genEnumerationTemp(
+ loc, builder, mlir::cast<fir::RecordType>(resType), last, "ctor.temp");
+ }
+
+ // Build an enumeration value in a temporary. A non-constant ordinal is range
+ // checked (F2023 7.6.2 p5) in its original kind, before narrowing.
+ hlfir::EntityWithAttributes
+ genEnumerationConstructor(const Fortran::evaluate::StructureConstructor &ctor,
+ fir::RecordType recTy) {
+ using Int4 =
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, 4>;
+ mlir::Location loc = getLoc();
+ fir::FirOpBuilder &builder = getBuilder();
+ assert(ctor.values().size() == 1 &&
+ "enumeration constructor must have exactly one value");
+ const auto &[ordSym, ordValue] = *ctor.values().begin();
+ const Fortran::lower::SomeExpr &ordExpr = ordValue.value();
+ std::string fieldName = converter.getRecordTypeFieldName(*ordSym);
+ mlir::Type ordTy = recTy.getType(fieldName);
+ assert(ordTy && "enumeration type must have an ordinal component");
+
+ mlir::Value ordinal;
+ if (std::optional<std::int64_t> constOrdinal =
+ Fortran::evaluate::ToInt64(ordExpr)) {
+ ordinal = builder.createIntegerConstant(loc, ordTy, *constOrdinal);
+ } else {
+ const Fortran::evaluate::Convert<Int4> *narrowing = nullptr;
+ if (const auto *intExpr = std::get_if<
+ Fortran::evaluate::Expr<Fortran::evaluate::SomeInteger>>(
+ &ordExpr.u))
+ if (const auto *int4Expr =
+ std::get_if<Fortran::evaluate::Expr<Int4>>(&intExpr->u))
+ narrowing =
+ std::get_if<Fortran::evaluate::Convert<Int4>>(&int4Expr->u);
+ hlfir::Entity original =
+ narrowing ? gen(narrowing->left()) : gen(ordExpr);
+ mlir::Value value = hlfir::loadTrivialScalar(loc, builder, original);
+ // Widen narrow kinds so the enumerator count is representable.
+ if (value.getType().getIntOrFloatBitWidth() <
+ ordTy.getIntOrFloatBitWidth())
+ value = builder.createConvert(loc, ordTy, value);
+ mlir::Type valueTy = value.getType();
+ int count = ctor.derivedTypeSpec()
+ .typeSymbol()
+ .GetUltimate()
+ .get<Fortran::semantics::DerivedTypeDetails>()
+ .enumeratorCount();
+ mlir::Value one = builder.createIntegerConstant(loc, valueTy, 1);
+ mlir::Value maxVal = builder.createIntegerConstant(loc, valueTy, count);
+ mlir::Value tooLow = mlir::arith::CmpIOp::create(
+ builder, loc, mlir::arith::CmpIPredicate::slt, value, one);
+ mlir::Value tooHigh = mlir::arith::CmpIOp::create(
+ builder, loc, mlir::arith::CmpIPredicate::sgt, value, maxVal);
+ mlir::Value outOfRange =
+ mlir::arith::OrIOp::create(builder, loc, tooLow, tooHigh);
+ auto ifOp = fir::IfOp::create(builder, loc, {}, outOfRange,
+ /*withElseRegion=*/false);
+ builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+ fir::runtime::genReportFatalUserError(
+ builder, loc,
+ "enumeration constructor value is out of range (must be "
+ "positive and not greater than the number of enumerators)");
+ builder.setInsertionPointAfter(ifOp);
+ ordinal = builder.createConvert(loc, ordTy, value);
+ }
+ return Fortran::lower::genEnumerationTemp(loc, builder, recTy, ordinal,
+ "ctor.temp");
+ }
+
+ // Load the __ordinal of a scalar enumeration variable or value.
+ static mlir::Value genEnumerationOrdinalValue(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ hlfir::Entity enumVal) {
+ if (enumVal.isVariable())
+ return hlfir::loadTrivialScalar(
+ loc, builder,
+ Fortran::lower::genEnumerationOrdinalDesignator(loc, builder,
+ enumVal));
+ hlfir::AssociateOp associate = hlfir::genAssociateExpr(
----------------
MattPD wrote:
Confirmed: The reported PARAMETER gathers now compile and produce the expected results.
https://github.com/llvm/llvm-project/pull/193571
More information about the flang-commits
mailing list