[flang-commits] [flang] 01a0d21 - [flang][acc] Implement MappableType interfaces for fir.box and fir.array (#122495)

via flang-commits flang-commits at lists.llvm.org
Tue Jan 14 10:43:00 PST 2025


Author: Razvan Lupusoru
Date: 2025-01-14T10:42:57-08:00
New Revision: 01a0d212a64919205734706d929db37e503c35ce

URL: https://github.com/llvm/llvm-project/commit/01a0d212a64919205734706d929db37e503c35ce
DIFF: https://github.com/llvm/llvm-project/commit/01a0d212a64919205734706d929db37e503c35ce.diff

LOG: [flang][acc] Implement MappableType interfaces for fir.box and fir.array (#122495)

The newly introduced MappableType interface in `acc` dialect was
primarily intended to allow variables with non-materialized storage to
be used in acc data clauses (previously everything was required to be
`pointer-like`). One motivator for this was `fir.box` since it is
possible to be passed to functions without a wrapping `fir.ref` and also
it can be generated directly via operations like `fir.embox` - and
unlike other variable representations in FIR, the underlying storage for
it does not get materialized until LLVM codegen.

The new interface is being attached to both `fir.box` and `fir.array`.
Strictly speaking, attaching to the latter is primarily for consistency
since the MappableType interface requires implementation of utilities to
compute byte size - and it made sense that a
`fir.box<fir.array<10xi32>>` and `fir.array<10xi32>` would have a
consistently computable size. This decision may be revisited as
MappableType interface evolves.

The new interface attachments are made in a new library named
`FIROpenACCSupport`. The reason for this is to avoid circular
dependencies since the implementation of this library is reusing code
from lowering of OpenACC. More specifically, the types are defined in
`FIRDialect` and `FortranLower` depends on it. Thus we cannot attach
these interfaces in `FIRDialect`.

Added: 
    flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h
    flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h
    flang/lib/Optimizer/OpenACC/CMakeLists.txt
    flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp
    flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp
    flang/test/Fir/OpenACC/openacc-mappable.fir
    flang/test/lib/OpenACC/CMakeLists.txt
    flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp

Modified: 
    flang/include/flang/Optimizer/Support/InitFIR.h
    flang/lib/Frontend/CMakeLists.txt
    flang/lib/Optimizer/CMakeLists.txt
    flang/lib/Optimizer/Dialect/CMakeLists.txt
    flang/test/lib/CMakeLists.txt
    flang/tools/fir-lsp-server/CMakeLists.txt
    flang/tools/fir-opt/CMakeLists.txt
    flang/tools/fir-opt/fir-opt.cpp
    flang/tools/tco/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h
new file mode 100644
index 00000000000000..c1bea32a22361d
--- /dev/null
+++ b/flang/include/flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h
@@ -0,0 +1,43 @@
+//===- FIROpenACCTypeInterfaces.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains external dialect interfaces for FIR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FLANG_OPTIMIZER_OPENACC_FIROPENACCTYPEINTERFACES_H_
+#define FLANG_OPTIMIZER_OPENACC_FIROPENACCTYPEINTERFACES_H_
+
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+
+namespace fir::acc {
+
+template <typename T>
+struct OpenACCMappableModel
+    : public mlir::acc::MappableType::ExternalModel<OpenACCMappableModel<T>,
+                                                    T> {
+  mlir::TypedValue<mlir::acc::PointerLikeType> getVarPtr(::mlir::Type type,
+                                                         mlir::Value var) const;
+
+  std::optional<llvm::TypeSize>
+  getSizeInBytes(mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
+                 const mlir::DataLayout &dataLayout) const;
+
+  std::optional<int64_t>
+  getOffsetInBytes(mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
+                   const mlir::DataLayout &dataLayout) const;
+
+  llvm::SmallVector<mlir::Value>
+  generateAccBounds(mlir::Type type, mlir::Value var,
+                    mlir::OpBuilder &builder) const;
+};
+
+} // namespace fir::acc
+
+#endif // FLANG_OPTIMIZER_OPENACC_FIROPENACCTYPEINTERFACES_H_

diff  --git a/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h b/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h
new file mode 100644
index 00000000000000..efaddd72ebbf2b
--- /dev/null
+++ b/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h
@@ -0,0 +1,22 @@
+//===- RegisterOpenACCExtensions.h - OpenACC Extension Registration --===--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_
+#define FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_
+
+namespace mlir {
+class DialectRegistry;
+} // namespace mlir
+
+namespace fir::acc {
+
+void registerOpenACCExtensions(mlir::DialectRegistry &registry);
+
+} // namespace fir::acc
+
+#endif // FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_

diff  --git a/flang/include/flang/Optimizer/Support/InitFIR.h b/flang/include/flang/Optimizer/Support/InitFIR.h
index 1c61c367199923..94995ac6136edd 100644
--- a/flang/include/flang/Optimizer/Support/InitFIR.h
+++ b/flang/include/flang/Optimizer/Support/InitFIR.h
@@ -17,6 +17,7 @@
 #include "flang/Optimizer/Dialect/CUF/CUFToLLVMIRTranslation.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/HLFIR/HLFIRDialect.h"
+#include "flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h"
 #include "mlir/Conversion/Passes.h"
 #include "mlir/Dialect/Affine/Passes.h"
 #include "mlir/Dialect/Complex/IR/Complex.h"
@@ -63,6 +64,7 @@ inline void addFIRExtensions(mlir::DialectRegistry &registry,
     addFIRInlinerExtension(registry);
   addFIRToLLVMIRExtension(registry);
   cuf::registerCUFDialectTranslation(registry);
+  fir::acc::registerOpenACCExtensions(registry);
 }
 
 inline void loadNonCodegenDialects(mlir::MLIRContext &context) {

diff  --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index 1b90fe826af6c9..0a0482505b747e 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -39,6 +39,7 @@ add_flang_library(flangFrontend
   HLFIRDialect
   HLFIRTransforms
   flangPasses
+  FIROpenACCSupport
   FlangOpenMPTransforms
   MLIRTransforms
   MLIRBuiltinToLLVMIRTranslation

diff  --git a/flang/lib/Optimizer/CMakeLists.txt b/flang/lib/Optimizer/CMakeLists.txt
index 5354d7181e6516..72aba51b858708 100644
--- a/flang/lib/Optimizer/CMakeLists.txt
+++ b/flang/lib/Optimizer/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(Builder)
 add_subdirectory(CodeGen)
 add_subdirectory(Dialect)
 add_subdirectory(HLFIR)
+add_subdirectory(OpenACC)
 add_subdirectory(OpenMP)
 add_subdirectory(Passes)
 add_subdirectory(Support)

diff  --git a/flang/lib/Optimizer/Dialect/CMakeLists.txt b/flang/lib/Optimizer/Dialect/CMakeLists.txt
index a8235f841b879d..08caa15700d4ca 100644
--- a/flang/lib/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/lib/Optimizer/Dialect/CMakeLists.txt
@@ -6,8 +6,8 @@ add_flang_library(FIRDialect
   FIRDialect.cpp
   FIROps.cpp
   FIRType.cpp
-  FortranVariableInterface.cpp
   FirAliasTagOpInterface.cpp
+  FortranVariableInterface.cpp
   Inliner.cpp
 
   DEPENDS

diff  --git a/flang/lib/Optimizer/OpenACC/CMakeLists.txt b/flang/lib/Optimizer/OpenACC/CMakeLists.txt
new file mode 100644
index 00000000000000..ed673121353c16
--- /dev/null
+++ b/flang/lib/Optimizer/OpenACC/CMakeLists.txt
@@ -0,0 +1,22 @@
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+add_flang_library(FIROpenACCSupport
+  FIROpenACCTypeInterfaces.cpp
+  RegisterOpenACCExtensions.cpp
+
+  DEPENDS
+  FIRBuilder
+  FIRDialect
+  FIRDialectSupport
+  FIRSupport
+  HLFIRDialect
+  MLIROpenACCDialect
+
+  LINK_LIBS
+  FIRBuilder
+  FIRDialect
+  FIRDialectSupport
+  FIRSupport
+  HLFIRDialect
+  MLIROpenACCDialect
+)

diff  --git a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp
new file mode 100644
index 00000000000000..e6a484923c7060
--- /dev/null
+++ b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp
@@ -0,0 +1,227 @@
+//===-- FIROpenACCTypeInterfaces.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of external dialect interfaces for FIR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h"
+#include "flang/Lower/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIROpsSupport.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/Support/LLVM.h"
+
+namespace fir::acc {
+
+static mlir::TypedValue<mlir::acc::PointerLikeType>
+getPtrFromVar(mlir::Value var) {
+  if (auto ptr =
+          mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(var))
+    return ptr;
+
+  if (auto load = mlir::dyn_cast_if_present<fir::LoadOp>(var.getDefiningOp())) {
+    // All FIR reference types implement the PointerLikeType interface.
+    return mlir::cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(
+        load.getMemref());
+  }
+
+  return {};
+}
+
+template <>
+mlir::TypedValue<mlir::acc::PointerLikeType>
+OpenACCMappableModel<fir::SequenceType>::getVarPtr(mlir::Type type,
+                                                   mlir::Value var) const {
+  return getPtrFromVar(var);
+}
+
+template <>
+mlir::TypedValue<mlir::acc::PointerLikeType>
+OpenACCMappableModel<fir::BaseBoxType>::getVarPtr(mlir::Type type,
+                                                  mlir::Value var) const {
+  return getPtrFromVar(var);
+}
+
+template <>
+std::optional<llvm::TypeSize>
+OpenACCMappableModel<fir::SequenceType>::getSizeInBytes(
+    mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
+    const mlir::DataLayout &dataLayout) const {
+  // TODO: Bounds operation affect the total size - add support to take them
+  // into account.
+  if (!accBounds.empty())
+    return {};
+
+  // Dynamic extents or unknown ranks generally do not have compile-time
+  // computable dimensions.
+  auto seqType = mlir::cast<fir::SequenceType>(type);
+  if (seqType.hasDynamicExtents() || seqType.hasUnknownShape())
+    return {};
+
+  // Attempt to find an operation that a lookup for KindMapping can be done
+  // from.
+  mlir::Operation *kindMapSrcOp = var.getDefiningOp();
+  if (!kindMapSrcOp) {
+    kindMapSrcOp = var.getParentRegion()->getParentOp();
+    if (!kindMapSrcOp)
+      return {};
+  }
+  auto kindMap = fir::getKindMapping(kindMapSrcOp);
+
+  auto sizeAndAlignment =
+      fir::getTypeSizeAndAlignment(var.getLoc(), type, dataLayout, kindMap);
+  if (!sizeAndAlignment.has_value())
+    return {};
+
+  return {llvm::TypeSize::getFixed(sizeAndAlignment->first)};
+}
+
+template <>
+std::optional<llvm::TypeSize>
+OpenACCMappableModel<fir::BaseBoxType>::getSizeInBytes(
+    mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
+    const mlir::DataLayout &dataLayout) const {
+  // If we have a box value instead of box reference, the intent is to
+  // get the size of the data not the box itself.
+  if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) {
+    if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(
+            fir::unwrapRefType(boxTy.getEleTy()))) {
+      return mappableTy.getSizeInBytes(var, accBounds, dataLayout);
+    }
+  }
+  // Size for boxes is not computable until it gets materialized.
+  return {};
+}
+
+template <>
+std::optional<int64_t>
+OpenACCMappableModel<fir::SequenceType>::getOffsetInBytes(
+    mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
+    const mlir::DataLayout &dataLayout) const {
+  // TODO: Bounds operation affect the offset- add support to take them
+  // into account.
+  if (!accBounds.empty())
+    return {};
+
+  // Dynamic extents (aka descriptor-based arrays) - may have a offset.
+  // For example, a negative stride may mean a negative offset to compute the
+  // start of array.
+  auto seqType = mlir::cast<fir::SequenceType>(type);
+  if (seqType.hasDynamicExtents() || seqType.hasUnknownShape())
+    return {};
+
+  // We have non-dynamic extents - but if for some reason the size is not
+  // computable - assume offset is not either. Otherwise, it is an offset of
+  // zero.
+  if (getSizeInBytes(type, var, accBounds, dataLayout).has_value()) {
+    return {0};
+  }
+  return {};
+}
+
+template <>
+std::optional<int64_t> OpenACCMappableModel<fir::BaseBoxType>::getOffsetInBytes(
+    mlir::Type type, mlir::Value var, mlir::ValueRange accBounds,
+    const mlir::DataLayout &dataLayout) const {
+  // If we have a box value instead of box reference, the intent is to
+  // get the offset of the data not the offset of the box itself.
+  if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) {
+    if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(
+            fir::unwrapRefType(boxTy.getEleTy()))) {
+      return mappableTy.getOffsetInBytes(var, accBounds, dataLayout);
+    }
+  }
+  // Until boxes get materialized, the offset is not evident because it is
+  // relative to the pointer being held.
+  return {};
+}
+
+template <>
+llvm::SmallVector<mlir::Value>
+OpenACCMappableModel<fir::SequenceType>::generateAccBounds(
+    mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const {
+  assert((mlir::isa<mlir::acc::PointerLikeType>(var.getType()) ||
+          mlir::isa<mlir::acc::MappableType>(var.getType())) &&
+         "must be pointer-like or mappable");
+
+  fir::FirOpBuilder firBuilder(builder, var.getDefiningOp());
+  auto seqType = mlir::cast<fir::SequenceType>(type);
+  mlir::Location loc = var.getLoc();
+
+  mlir::Value varPtr =
+      mlir::isa<mlir::acc::PointerLikeType>(var.getType())
+          ? var
+          : mlir::cast<mlir::acc::MappableType>(var.getType()).getVarPtr(var);
+
+  if (seqType.hasDynamicExtents() || seqType.hasUnknownShape()) {
+    if (auto boxAddr =
+            mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) {
+      mlir::Value box = boxAddr.getVal();
+      auto res =
+          hlfir::translateToExtendedValue(loc, firBuilder, hlfir::Entity(box));
+      fir::ExtendedValue exv = res.first;
+      mlir::Value boxRef = box;
+      if (auto boxPtr = getPtrFromVar(box)) {
+        boxRef = boxPtr;
+      }
+      // TODO: Handle Fortran optional.
+      const mlir::Value isPresent;
+      Fortran::lower::AddrAndBoundsInfo info(box, boxRef, isPresent,
+                                             box.getType());
+      return Fortran::lower::genBoundsOpsFromBox<mlir::acc::DataBoundsOp,
+                                                 mlir::acc::DataBoundsType>(
+          firBuilder, loc, exv, info);
+    }
+    assert(false && "array with unknown dimension expected to have descriptor");
+    return {};
+  }
+
+  // TODO: Detect assumed-size case.
+  const bool isAssumedSize = false;
+  auto valToCheck = varPtr;
+  if (auto boxAddr =
+          mlir::dyn_cast_if_present<fir::BoxAddrOp>(varPtr.getDefiningOp())) {
+    valToCheck = boxAddr.getVal();
+  }
+  auto res = hlfir::translateToExtendedValue(loc, firBuilder,
+                                             hlfir::Entity(valToCheck));
+  fir::ExtendedValue exv = res.first;
+  return Fortran::lower::genBaseBoundsOps<mlir::acc::DataBoundsOp,
+                                          mlir::acc::DataBoundsType>(
+      firBuilder, loc, exv,
+      /*isAssumedSize=*/isAssumedSize);
+}
+
+template <>
+llvm::SmallVector<mlir::Value>
+OpenACCMappableModel<fir::BaseBoxType>::generateAccBounds(
+    mlir::Type type, mlir::Value var, mlir::OpBuilder &builder) const {
+  // If we have a box value instead of box reference, the intent is to
+  // get the bounds of the data not the bounds of the box itself.
+  if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(var.getType())) {
+    if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(
+            fir::unwrapRefType(boxTy.getEleTy()))) {
+      mlir::Value data = builder.create<fir::BoxAddrOp>(var.getLoc(), var);
+      return mappableTy.generateAccBounds(data, builder);
+    }
+  }
+  // Box references are not arrays - thus generating acc.bounds does not make
+  // sense.
+  return {};
+}
+
+} // namespace fir::acc

diff  --git a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp
new file mode 100644
index 00000000000000..34ea122f6b997d
--- /dev/null
+++ b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp
@@ -0,0 +1,28 @@
+//===-- RegisterOpenACCExtensions.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Registration for OpenACC extensions as applied to FIR dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h"
+
+namespace fir::acc {
+void registerOpenACCExtensions(mlir::DialectRegistry &registry) {
+  registry.addExtension(+[](mlir::MLIRContext *ctx,
+                            fir::FIROpsDialect *dialect) {
+    fir::SequenceType::attachInterface<OpenACCMappableModel<fir::SequenceType>>(
+        *ctx);
+    fir::BoxType::attachInterface<OpenACCMappableModel<fir::BaseBoxType>>(*ctx);
+  });
+}
+
+} // namespace fir::acc

diff  --git a/flang/test/Fir/OpenACC/openacc-mappable.fir b/flang/test/Fir/OpenACC/openacc-mappable.fir
new file mode 100644
index 00000000000000..438cb29b991c7d
--- /dev/null
+++ b/flang/test/Fir/OpenACC/openacc-mappable.fir
@@ -0,0 +1,25 @@
+// Use --mlir-disable-threading so that the diagnostic printing is serialized.
+// RUN: fir-opt %s -pass-pipeline='builtin.module(test-fir-openacc-interfaces)' -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<f16 = dense<16> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, !llvm.ptr<270> = dense<32> : vector<4xi64>, f64 = dense<64> : vector<2xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, i64 = dense<64> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, f80 = dense<128> : vector<2xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, "dlti.endianness" = "little", "dlti.stack_alignment" = 128 : i64>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} {
+  func.func @_QPsub() {
+    %c2 = arith.constant 2 : index
+    %c10 = arith.constant 10 : index
+    %0 = fir.alloca !fir.array<10xf32> {bindc_name = "arr", uniq_name = "_QFsubEarr"}
+    %1 = fir.shape_shift %c2, %c10 : (index, index) -> !fir.shapeshift<1>
+    %2 = fir.declare %0(%1) {uniq_name = "_QFsubEarr"} : (!fir.ref<!fir.array<10xf32>>, !fir.shapeshift<1>) -> !fir.ref<!fir.array<10xf32>>
+    %3 = fir.embox %2(%1) : (!fir.ref<!fir.array<10xf32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<10xf32>>
+    %4 = fir.box_addr %3 : (!fir.box<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>>
+    %5 = acc.copyin var(%3 : !fir.box<!fir.array<10xf32>>) -> !fir.box<!fir.array<10xf32>> {name = "arr", structured = false}
+    %6 = acc.copyin varPtr(%4 : !fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "arr", structured = false}
+    acc.enter_data dataOperands(%5, %6 : !fir.box<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
+    return
+  }
+}
+
+// CHECK: Visiting: %{{.*}} = acc.copyin var(%{{.*}} : !fir.box<!fir.array<10xf32>>) -> !fir.box<!fir.array<10xf32>> {name = "arr", structured = false}
+// CHECK: Mappable: !fir.box<!fir.array<10xf32>>
+// CHECK: Size: 40
+// CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "arr", structured = false}
+// CHECK: Mappable: !fir.array<10xf32>
+// CHECK: Size: 40

diff  --git a/flang/test/lib/CMakeLists.txt b/flang/test/lib/CMakeLists.txt
index fc6ef10fab1f5a..96f4c9513b11a5 100644
--- a/flang/test/lib/CMakeLists.txt
+++ b/flang/test/lib/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory(Analysis)
+add_subdirectory(OpenACC)

diff  --git a/flang/test/lib/OpenACC/CMakeLists.txt b/flang/test/lib/OpenACC/CMakeLists.txt
new file mode 100644
index 00000000000000..54a81373d253fa
--- /dev/null
+++ b/flang/test/lib/OpenACC/CMakeLists.txt
@@ -0,0 +1,21 @@
+add_flang_library(FIRTestOpenACCInterfaces
+  TestOpenACCInterfaces.cpp
+
+  DEPENDS
+  FIRDialect
+  FIRBuilder
+  FIROpenACCSupport
+  FIRSupport
+  FIRTransforms
+  MLIROpenACCDialect
+
+  LINK_LIBS
+  FIRDialect
+  FIRBuilder
+  FIROpenACCSupport
+  FIRSupport
+  MLIRIR
+  MLIROpenACCDialect
+  MLIRSupport
+  MLIRFuncDialect
+)

diff  --git a/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp b/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp
new file mode 100644
index 00000000000000..a01396748f4c2c
--- /dev/null
+++ b/flang/test/lib/OpenACC/TestOpenACCInterfaces.cpp
@@ -0,0 +1,85 @@
+//===- TestOpenACCInterfaces.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Support/LLVM.h"
+#include "flang/Optimizer/Support/DataLayout.h"
+
+using namespace mlir;
+
+namespace {
+
+struct TestFIROpenACCInterfaces
+    : public PassWrapper<TestFIROpenACCInterfaces, OperationPass<ModuleOp>> {
+  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFIROpenACCInterfaces)
+
+  StringRef getArgument() const final { return "test-fir-openacc-interfaces"; }
+  StringRef getDescription() const final {
+    return "Test FIR implementation of the OpenACC interfaces.";
+  }
+  void runOnOperation() override {
+    mlir::ModuleOp mod = getOperation();
+    auto datalayout =
+        fir::support::getOrSetDataLayout(mod, /*allowDefaultLayout=*/true);
+    mlir::OpBuilder builder(mod);
+    getOperation().walk([&](Operation *op) {
+      if (isa<ACC_DATA_ENTRY_OPS>(op)) {
+        Type typeOfVar = acc::getVar(op).getType();
+        llvm::errs() << "Visiting: " << *op << "\n";
+        auto mappableTy = dyn_cast_if_present<acc::MappableType>(typeOfVar);
+        if (!mappableTy) {
+          mappableTy =
+              dyn_cast_if_present<acc::MappableType>(acc::getVarType(op));
+        }
+        if (mappableTy) {
+          llvm::errs() << "\tMappable: " << mappableTy << "\n";
+          if (datalayout.has_value()) {
+            auto size = mappableTy.getSizeInBytes(
+                acc::getVar(op), acc::getBounds(op), datalayout.value());
+            if (size) {
+              llvm::errs() << "\t\tSize: " << size.value() << "\n";
+            }
+            auto offset = mappableTy.getOffsetInBytes(
+                acc::getVar(op), acc::getBounds(op), datalayout.value());
+            if (offset) {
+              llvm::errs() << "\t\tOffset: " << offset.value() << "\n";
+            }
+          }
+
+          builder.setInsertionPoint(op);
+          auto bounds = mappableTy.generateAccBounds(acc::getVar(op), builder);
+          if (!bounds.empty()) {
+            for (auto [idx, bound] : llvm::enumerate(bounds)) {
+              llvm::errs() << "\t\tBound[" << idx << "]: " << bound << "\n";
+            }
+          }
+        } else {
+          assert(acc::isPointerLikeType(typeOfVar) &&
+              "expected to be pointer-like");
+          llvm::errs() << "\tPointer-like: " << typeOfVar << "\n";
+        }
+      }
+    });
+  }
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
+// Pass Registration
+//===----------------------------------------------------------------------===//
+
+namespace fir {
+namespace test {
+void registerTestFIROpenACCInterfacesPass() {
+  PassRegistration<TestFIROpenACCInterfaces>();
+}
+} // namespace test
+} // namespace fir

diff  --git a/flang/tools/fir-lsp-server/CMakeLists.txt b/flang/tools/fir-lsp-server/CMakeLists.txt
index ff0ced6693b97f..d5445d8f8e99be 100644
--- a/flang/tools/fir-lsp-server/CMakeLists.txt
+++ b/flang/tools/fir-lsp-server/CMakeLists.txt
@@ -11,6 +11,7 @@ get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS)
 target_link_libraries(fir-lsp-server PRIVATE
   CUFDialect
   FIRDialect
+  FIROpenACCSupport
   HLFIRDialect
   MLIRLspServerLib
   ${dialect_libs}

diff  --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt
index 4c6dbf7d9c8c37..f0741ca2821695 100644
--- a/flang/tools/fir-opt/CMakeLists.txt
+++ b/flang/tools/fir-opt/CMakeLists.txt
@@ -6,6 +6,7 @@ get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS)
 if(FLANG_INCLUDE_TESTS)
   set(test_libs
     FIRTestAnalysis
+    FIRTestOpenACCInterfaces
     MLIRTestIR
     )
 endif()
@@ -19,6 +20,7 @@ target_link_libraries(fir-opt PRIVATE
   FIRCodeGen
   HLFIRDialect
   HLFIRTransforms
+  FIROpenACCSupport
   FlangOpenMPTransforms
   FIRAnalysis
   ${test_libs}

diff  --git a/flang/tools/fir-opt/fir-opt.cpp b/flang/tools/fir-opt/fir-opt.cpp
index 5f6a856116bc04..ef510ff77ad253 100644
--- a/flang/tools/fir-opt/fir-opt.cpp
+++ b/flang/tools/fir-opt/fir-opt.cpp
@@ -22,6 +22,7 @@ using namespace mlir;
 namespace fir {
 namespace test {
 void registerTestFIRAliasAnalysisPass();
+void registerTestFIROpenACCInterfacesPass();
 } // namespace test
 } // namespace fir
 
@@ -38,6 +39,7 @@ int main(int argc, char **argv) {
   flangomp::registerFlangOpenMPPasses();
 #ifdef FLANG_INCLUDE_TESTS
   fir::test::registerTestFIRAliasAnalysisPass();
+  fir::test::registerTestFIROpenACCInterfacesPass();
   mlir::registerSideEffectTestPasses();
 #endif
   DialectRegistry registry;

diff  --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt
index aac80437ee11d9..0ac18734be2ce9 100644
--- a/flang/tools/tco/CMakeLists.txt
+++ b/flang/tools/tco/CMakeLists.txt
@@ -18,6 +18,7 @@ target_link_libraries(tco PRIVATE
   HLFIRDialect
   HLFIRTransforms
   flangPasses
+  FIROpenACCSupport
   FlangOpenMPTransforms
   FortranCommon
   ${dialect_libs}


        


More information about the flang-commits mailing list