[flang-commits] [flang] [flang][acc] Implement cache directive lowering (PR #174897)

Razvan Lupusoru via flang-commits flang-commits at lists.llvm.org
Thu Jan 8 09:58:14 PST 2026


================
@@ -4837,12 +4837,180 @@ genACC(Fortran::lower::AbstractConverter &converter,
       atomicConstruct.u);
 }
 
+/// Generate acc.bounds for cache directive. Handles:
+/// - Single element: arr(i) or arr(5)
+/// - Full range: arr(lower:upper)
+/// - Missing upper: arr(lower:) - uses array's upper bound
+/// - Missing lower: arr(:upper) - uses array's lower bound
+static void
+genCacheBounds(Fortran::lower::AbstractConverter &converter,
+               Fortran::semantics::SemanticsContext &semanticsContext,
+               Fortran::lower::StatementContext &stmtCtx,
+               const Fortran::parser::AccObject &accObject,
+               std::stringstream &asFortran,
+               llvm::SmallVectorImpl<mlir::Value> &bounds) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  mlir::Location loc = converter.getCurrentLocation();
+  mlir::Type idxTy = builder.getIndexType();
+  mlir::Type boundTy = builder.getType<mlir::acc::DataBoundsType>();
+
+  Fortran::evaluate::ExpressionAnalyzer ea{semanticsContext};
+  Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject);
+
+  std::optional<Fortran::evaluate::DataRef> dataRef;
+  Fortran::semantics::MaybeExpr designator = Fortran::common::visit(
+      [&](auto &&s) { return ea.Analyze(s); }, accObject.u);
+  if (designator)
+    dataRef = Fortran::evaluate::ExtractDataRef(*designator);
+
+  if (!dataRef)
+    return;
+
+  auto *arrayRef = std::get_if<Fortran::evaluate::ArrayRef>(&dataRef->u);
+  if (!arrayRef)
+    return;
+
+  // Helper to generate index value from expression.
+  // Optimize for compile-time constants to generate index type directly.
+  auto genIndex =
+      [&](const Fortran::semantics::MaybeExpr &expr) -> mlir::Value {
+    if (auto constVal = Fortran::evaluate::ToInt64(*expr))
+      return builder.createIntegerConstant(loc, idxTy, *constVal);
+    return builder.createConvert(
+        loc, idxTy, fir::getBase(converter.genExprValue(loc, *expr, stmtCtx)));
+  };
+
+  const auto &subscripts = arrayRef->subscript();
+  int dimension = 0;
+  mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
+  fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(symbol);
+
+  for (const auto &subscript : subscripts) {
+    if (dimension != 0)
+      asFortran << ',';
+
+    mlir::Value lbound, extent;
+    mlir::Value arrayLb =
+        fir::factory::readLowerBound(builder, loc, dataExv, dimension, one);
+    mlir::Value arrayExtent =
+        fir::factory::readExtent(builder, loc, dataExv, dimension);
+
+    const auto *triplet = std::get_if<Fortran::evaluate::Triplet>(&subscript.u);
+
+    if (triplet) {
+      asFortran << ':';
+
+      // OpenACC spec requires at least one of lower or upper bound to be
+      // specified: arr(lower:upper), arr(lower:), or arr(:upper).
+      // arr(:) with both bounds missing is not allowed.
+      Fortran::semantics::MaybeExpr lowerExpr =
+          Fortran::evaluate::AsGenericExpr(triplet->lower());
+      Fortran::semantics::MaybeExpr upperExpr =
+          Fortran::evaluate::AsGenericExpr(triplet->upper());
+
+      if (!lowerExpr && !upperExpr) {
+        llvm::report_fatal_error("OpenACC cache directive requires at least "
+                                 "one bound to be specified for array section");
+      }
+
+      // OpenACC cache only supports unit stride (default or explicit 1).
+      auto strideVal = Fortran::evaluate::ToInt64(triplet->stride());
+      if (!strideVal || *strideVal != 1) {
+        llvm::report_fatal_error("OpenACC cache directive does not support "
+                                 "strided array sections");
+      }
+
+      // Compute lower bound (use array lb if not specified).
+      mlir::Value lb = lowerExpr ? genIndex(lowerExpr) : arrayLb;
+
+      // Compute upper bound (use array ub if not specified).
+      mlir::Value ub;
+      if (upperExpr) {
+        ub = genIndex(upperExpr);
+      } else {
+        // arr(lower:) - upper is array's upper bound
+        ub = mlir::arith::AddIOp::create(
+            builder, loc,
+            mlir::arith::SubIOp::create(builder, loc, arrayLb, one),
+            arrayExtent);
+      }
+
+      // Normalize to zero-based and compute extent.
+      lbound = mlir::arith::SubIOp::create(builder, loc, lb, arrayLb);
+      mlir::Value ubound =
+          mlir::arith::SubIOp::create(builder, loc, ub, arrayLb);
+      extent = mlir::arith::AddIOp::create(
+          builder, loc,
+          mlir::arith::SubIOp::create(builder, loc, ubound, lbound), one);
+    } else {
+      // Single element: arr(elem)
+      Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger> scalarExpr =
+          std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>(subscript.u)
+              .value();
+      Fortran::semantics::MaybeExpr elemExpr =
+          Fortran::evaluate::AsGenericExpr(std::move(scalarExpr));
+      mlir::Value elem = genIndex(elemExpr);
+
+      lbound = mlir::arith::SubIOp::create(builder, loc, elem, arrayLb);
+      extent = one;
+    }
+
+    mlir::Value bound = mlir::acc::DataBoundsOp::create(
+        builder, loc, boundTy, lbound, /*upperbound=*/mlir::Value{}, extent,
+        /*stride=*/one, /*strideInBytes=*/false, arrayLb);
+    bounds.push_back(bound);
+    ++dimension;
+  }
+}
+
 static void
 genACC(Fortran::lower::AbstractConverter &converter,
        Fortran::semantics::SemanticsContext &semanticsContext,
        const Fortran::parser::OpenACCCacheConstruct &cacheConstruct) {
-  mlir::Location loc = converter.genLocation(cacheConstruct.source);
-  TODO(loc, "OpenACC cache directive");
+  const auto &objectListWithModifier =
+      std::get<Fortran::parser::AccObjectListWithModifier>(cacheConstruct.t);
+  const auto &accObjectList =
+      std::get<Fortran::parser::AccObjectList>(objectListWithModifier.t);
+  const auto &modifier =
+      std::get<std::optional<Fortran::parser::AccDataModifier>>(
+          objectListWithModifier.t);
+  mlir::acc::DataClause dataClause =
+      (modifier &&
+       (*modifier).v == Fortran::parser::AccDataModifier::Modifier::ReadOnly)
----------------
razvanlupusoru wrote:

The acc dialect was updated a few months back for OpenACC 3.4 standard - and now data clause operations (eg. acc.copyin) also have a `modifiers` attribute. Let's update that one as well as it will help our transition from encoding the modifiers in the dataClause to the modifiers attribute. I understand that the lowering of the other data operations may lag - but might as well do this for `cache`.

https://github.com/llvm/llvm-project/pull/174897


More information about the flang-commits mailing list