[flang-commits] [flang] [flang] Enumeration Type: (PR 4/5) Lowering (PR #193571)
via flang-commits
flang-commits at lists.llvm.org
Thu Oct 1 19:49:39 PDT 2026
================
@@ -1727,12 +1728,173 @@ 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);
+ 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);
----------------
MattPD wrote:
With 128 enumerators and a variable `integer(1)` argument holding 1, the constructor now initiates error termination. The upper bound becomes `-128 : i8`, so the signed comparison rejects that valid ordinal. The same program completes at [095d1945](https://github.com/llvm/llvm-project/commit/095d1945f7700776c0f8f0ed00640133a8c285f2). Could the comparison use a signed type representing both the original argument and the enumerator count, while preserving the INTEGER(8) check before narrowing?
https://github.com/llvm/llvm-project/pull/193571
More information about the flang-commits
mailing list