[Mlir-commits] [flang] [mlir] [mlir][acc] Add pass to convert acc declare ctors and dtors to LLVM (PR #217415)

Razvan Lupusoru llvmlistbot at llvm.org
Wed Aug 19 10:59:37 PDT 2026


https://github.com/razvanlupusoru created https://github.com/llvm/llvm-project/pull/217415

Adds the `acc-declare-ctor-dtor-conversion` pass which converts `acc.global_ctor` and `acc.global_dtor` operations into LLVM functions and registers them in `llvm.mlir.global_ctors` and `llvm.mlir.global_dtors`.

The pass exposes a `priority` option to control when the generated functions run relative to other module initializers.

>From e58be25ddd9d3d12134084f43e76be5fee16b5c6 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 19 Aug 2026 10:53:45 -0700
Subject: [PATCH] [mlir][acc] Add pass to convert acc declare ctors and dtors
 to LLVM

Adds the `acc-declare-ctor-dtor-conversion` pass which converts
`acc.global_ctor` and `acc.global_dtor` operations into LLVM
functions and registers them in `llvm.mlir.global_ctors` and
`llvm.mlir.global_dtors`.

The pass exposes a `priority` option to control when the generated
functions run relative to other module initializers.
---
 .../acc-declare-ctor-dtor-conversion.fir      |  78 ++++++++
 .../mlir/Dialect/OpenACC/Transforms/Passes.td |  25 +++
 .../ACCDeclareCtorDtorConversion.cpp          | 183 ++++++++++++++++++
 .../Dialect/OpenACC/Transforms/CMakeLists.txt |   2 +
 .../acc-declare-ctor-dtor-conversion.mlir     |  76 ++++++++
 5 files changed, 364 insertions(+)
 create mode 100644 flang/test/Fir/OpenACC/acc-declare-ctor-dtor-conversion.fir
 create mode 100644 mlir/lib/Dialect/OpenACC/Transforms/ACCDeclareCtorDtorConversion.cpp
 create mode 100644 mlir/test/Dialect/OpenACC/acc-declare-ctor-dtor-conversion.mlir

diff --git a/flang/test/Fir/OpenACC/acc-declare-ctor-dtor-conversion.fir b/flang/test/Fir/OpenACC/acc-declare-ctor-dtor-conversion.fir
new file mode 100644
index 0000000000000..9bfde2f0a1825
--- /dev/null
+++ b/flang/test/Fir/OpenACC/acc-declare-ctor-dtor-conversion.fir
@@ -0,0 +1,78 @@
+// RUN: fir-opt %s -acc-declare-ctor-dtor-conversion -o - | FileCheck %s
+// RUN: fir-opt %s --pass-pipeline="builtin.module(acc-declare-ctor-dtor-conversion{generate-dtors=false})" -o - | FileCheck %s --check-prefix=NODTOR
+
+// Derived from:
+// module mm
+// integer, parameter :: N = 7
+// real :: arr(N)
+// !$acc declare create(arr)
+// end module
+
+// CHECK-LABEL: module
+// CHECK-NOT: acc.global_dtor
+// CHECK-NOT: acc.global_ctor
+
+// LLVM functions are created from acc constructors and destructors, then
+// registered once in llvm.mlir.global_ctors / global_dtors (merged with any
+// pre-existing entries such as the CUDA Fortran constructor).
+// CHECK: llvm.func internal @_QMmmEarr_acc_ctor()
+// CHECK: llvm.func internal @_QMmmEotherEarr_acc_ctor()
+// CHECK: llvm.func internal @_QMmmEarr_acc_dtor()
+// CHECK: llvm.func internal @_QMmmEotherEarr_acc_dtor()
+// CHECK: llvm.mlir.global_ctors ctors = [{{.*}}@_QMmmEarr_acc_ctor{{.*}}@_QMmmEotherEarr_acc_ctor], priorities = [{{.*}}102 : i32{{.*}}102 : i32], data = [{{.*}}#llvm.zero{{.*}}#llvm.zero]
+// CHECK: llvm.mlir.global_dtors dtors = [@_QMmmEarr_acc_dtor, @_QMmmEotherEarr_acc_dtor], priorities = [102 : i32, 102 : i32], data = [#llvm.zero, #llvm.zero]
+
+// NODTOR-LABEL: module
+// NODTOR-NOT: @_QMmmEarr_acc_dtor
+// NODTOR-NOT: @_QMmmEotherEarr_acc_dtor
+// NODTOR: llvm.func internal @_QMmmEarr_acc_ctor()
+// NODTOR: llvm.func internal @_QMmmEotherEarr_acc_ctor()
+// NODTOR: llvm.mlir.global_ctors ctors = [{{.*}}@_QMmmEarr_acc_ctor{{.*}}@_QMmmEotherEarr_acc_ctor], priorities = [{{.*}}102 : i32{{.*}}102 : i32], data = [{{.*}}#llvm.zero{{.*}}#llvm.zero]
+// NODTOR-NOT: @_QMmmEarr_acc_dtor
+// NODTOR-NOT: @_QMmmEotherEarr_acc_dtor
+// NODTOR-NOT: llvm.mlir.global_dtors
+
+module attributes {gpu.container_module} {
+  fir.global @_QMmmEarr {acc.declare = #acc.declare<dataClause =  acc_create>} : !fir.array<7xf32> {
+    %0 = fir.zero_bits !fir.array<7xf32>
+    fir.has_value %0 : !fir.array<7xf32>
+  }
+  fir.global @_QMmmEotherEarr {acc.declare = #acc.declare<dataClause =  acc_create>} : !fir.array<3xf32> {
+    %0 = fir.zero_bits !fir.array<3xf32>
+    fir.has_value %0 : !fir.array<3xf32>
+  }
+  acc.global_ctor @_QMmmEarr_acc_ctor {
+    %0 = fir.address_of(@_QMmmEarr) {acc.declare = #acc.declare<dataClause =  acc_create>} : !fir.ref<!fir.array<7xf32>>
+    %1 = acc.create varPtr(%0 : !fir.ref<!fir.array<7xf32>>) -> !fir.ref<!fir.array<7xf32>> {name = "arr", structured = false}
+    %2 = acc.declare_enter dataOperands(%1 : !fir.ref<!fir.array<7xf32>>)
+    acc.terminator
+  }
+  acc.global_ctor @_QMmmEotherEarr_acc_ctor {
+    %0 = fir.address_of(@_QMmmEotherEarr) {acc.declare = #acc.declare<dataClause =  acc_create>} : !fir.ref<!fir.array<3xf32>>
+    %1 = acc.create varPtr(%0 : !fir.ref<!fir.array<3xf32>>) -> !fir.ref<!fir.array<3xf32>> {name = "other_arr", structured = false}
+    %2 = acc.declare_enter dataOperands(%1 : !fir.ref<!fir.array<3xf32>>)
+    acc.terminator
+  }
+  acc.global_dtor @_QMmmEarr_acc_dtor {
+    %0 = fir.address_of(@_QMmmEarr) {acc.declare = #acc.declare<dataClause =  acc_create>} : !fir.ref<!fir.array<7xf32>>
+    %1 = acc.getdeviceptr varPtr(%0 : !fir.ref<!fir.array<7xf32>>) -> !fir.ref<!fir.array<7xf32>> {dataClause = #acc<data_clause acc_create>, name = "arr", structured = false}
+    acc.declare_exit dataOperands(%1 : !fir.ref<!fir.array<7xf32>>)
+    acc.delete accPtr(%1 : !fir.ref<!fir.array<7xf32>>) {dataClause = #acc<data_clause acc_create>, name = "arr", structured = false}
+    acc.terminator
+  }
+  acc.global_dtor @_QMmmEotherEarr_acc_dtor {
+    %0 = fir.address_of(@_QMmmEotherEarr) {acc.declare = #acc.declare<dataClause =  acc_create>} : !fir.ref<!fir.array<3xf32>>
+    %1 = acc.getdeviceptr varPtr(%0 : !fir.ref<!fir.array<3xf32>>) -> !fir.ref<!fir.array<3xf32>> {dataClause = #acc<data_clause acc_create>, name = "other_arr", structured = false}
+    acc.declare_exit dataOperands(%1 : !fir.ref<!fir.array<3xf32>>)
+    acc.delete accPtr(%1 : !fir.ref<!fir.array<3xf32>>) {dataClause = #acc<data_clause acc_create>, name = "other_arr", structured = false}
+    acc.terminator
+  }
+  func.func private @_FortranAProgramEndStatement()
+  llvm.func @_FortranACUFRegisterAllocator() attributes {sym_visibility = "private"}
+  llvm.func internal @__cudaFortranConstructor() {
+    llvm.call @_FortranACUFRegisterAllocator() : () -> ()
+    %0 = cuf.register_module @cuda_device_mod -> !llvm.ptr
+    llvm.return
+  }
+  llvm.mlir.global_ctors ctors = [@__cudaFortranConstructor], priorities = [0 : i32], data = [#llvm.zero]
+}
diff --git a/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td b/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td
index 441de84d08f1e..58e68f55c5010 100644
--- a/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td
@@ -160,6 +160,31 @@ def ACCDeclareGPUModuleInsertion : Pass<"acc-declare-gpu-module-insertion", "mli
   ];
 }
 
+def ACCDeclareCtorDtorConversion
+    : Pass<"acc-declare-ctor-dtor-conversion", "mlir::ModuleOp"> {
+  let summary = "Convert OpenACC declare global constructors and destructors "
+                "to LLVM functions";
+  let description = [{
+    Converts `acc.global_ctor` into `llvm.func` entry points and registers them
+    in `llvm.mlir.global_ctors`. When enabled, similarly converts
+    `acc.global_dtor` and registers the functions in `llvm.mlir.global_dtors`;
+    otherwise, removes the destructor operations.
+
+    The ctor/dtor priority defaults to 102 so declare constructors run after
+    libacctarget init (priority 101).
+
+    Nested OpenACC operations inside the ctor/dtor regions are left unchanged
+    for later lowering.
+  }];
+  let options = [
+    Option<"priority", "priority", "int32_t", /*default=*/"102",
+           "Priority for ACC declare global constructors and destructors">,
+    Option<"generateDtors", "generate-dtors", "bool", /*default=*/"true",
+           "Generate LLVM destructor functions and register them globally">
+  ];
+  let dependentDialects = ["mlir::LLVM::LLVMDialect"];
+}
+
 def ACCLegalizeSerial : Pass<"acc-legalize-serial", "mlir::func::FuncOp"> {
   let summary = "Legalize OpenACC serial constructs";
   let description = [{
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCDeclareCtorDtorConversion.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCDeclareCtorDtorConversion.cpp
new file mode 100644
index 0000000000000..acec4cff084fa
--- /dev/null
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCDeclareCtorDtorConversion.cpp
@@ -0,0 +1,183 @@
+//===- ACCDeclareCtorDtorConversion.cpp - Declare ctor/dtor to LLVM -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Convert ACC declare global constructors and destructors to LLVM functions
+// registered in llvm.mlir.global_ctors / llvm.mlir.global_dtors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/Transforms/Passes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/IRMapping.h"
+#include "mlir/Pass/Pass.h"
+
+namespace mlir {
+namespace acc {
+#define GEN_PASS_DEF_ACCDECLARECTORDTORCONVERSION
+#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
+} // namespace acc
+} // namespace mlir
+
+using namespace mlir;
+
+namespace {
+
+static void collectExistingGlobalCtors(
+    ModuleOp mod, SmallVectorImpl<Attribute> &ctors,
+    SmallVectorImpl<int32_t> &priorities, SmallVectorImpl<Attribute> &data,
+    SmallVectorImpl<LLVM::GlobalCtorsOp> &globalCtorsOps) {
+  for (auto globalCtors : mod.getOps<LLVM::GlobalCtorsOp>()) {
+    ctors.append(globalCtors.getCtors().begin(), globalCtors.getCtors().end());
+    for (Attribute attr : globalCtors.getPriorities())
+      priorities.push_back(cast<IntegerAttr>(attr).getInt());
+    data.append(globalCtors.getData().begin(), globalCtors.getData().end());
+    globalCtorsOps.push_back(globalCtors);
+  }
+}
+
+static void collectExistingGlobalDtors(
+    ModuleOp mod, SmallVectorImpl<Attribute> &dtors,
+    SmallVectorImpl<int32_t> &priorities, SmallVectorImpl<Attribute> &data,
+    SmallVectorImpl<LLVM::GlobalDtorsOp> &globalDtorsOps) {
+  for (auto globalDtors : mod.getOps<LLVM::GlobalDtorsOp>()) {
+    dtors.append(globalDtors.getDtors().begin(), globalDtors.getDtors().end());
+    for (Attribute attr : globalDtors.getPriorities())
+      priorities.push_back(cast<IntegerAttr>(attr).getInt());
+    data.append(globalDtors.getData().begin(), globalDtors.getData().end());
+    globalDtorsOps.push_back(globalDtors);
+  }
+}
+
+static void replaceGlobalCtors(ModuleOp mod, OpBuilder &builder,
+                               ArrayRef<Attribute> ctors,
+                               ArrayRef<int32_t> priorities,
+                               ArrayRef<Attribute> data,
+                               MutableArrayRef<LLVM::GlobalCtorsOp> oldOps) {
+  for (auto globalCtors : oldOps)
+    globalCtors.erase();
+  if (ctors.empty())
+    return;
+
+  builder.setInsertionPointToEnd(mod.getBody());
+  LLVM::GlobalCtorsOp::create(builder, mod.getLoc(), builder.getArrayAttr(ctors),
+                              builder.getI32ArrayAttr(priorities),
+                              builder.getArrayAttr(data));
+}
+
+static void replaceGlobalDtors(ModuleOp mod, OpBuilder &builder,
+                               ArrayRef<Attribute> dtors,
+                               ArrayRef<int32_t> priorities,
+                               ArrayRef<Attribute> data,
+                               MutableArrayRef<LLVM::GlobalDtorsOp> oldOps) {
+  for (auto globalDtors : oldOps)
+    globalDtors.erase();
+  if (dtors.empty())
+    return;
+
+  builder.setInsertionPointToEnd(mod.getBody());
+  LLVM::GlobalDtorsOp::create(builder, mod.getLoc(), builder.getArrayAttr(dtors),
+                              builder.getI32ArrayAttr(priorities),
+                              builder.getArrayAttr(data));
+}
+
+/// Create an llvm.func from an acc.global_ctor / acc.global_dtor region.
+/// Nested operations are cloned unchanged for later lowering.
+static LLVM::LLVMFuncOp createLLVMFunctionFromRegion(StringRef symName,
+                                                     Region &region,
+                                                     ModuleOp mod,
+                                                     OpBuilder &builder) {
+  auto llvmVoidTy = LLVM::LLVMVoidType::get(mod.getContext());
+  auto funcTy =
+      LLVM::LLVMFunctionType::get(llvmVoidTy, {}, /*isVarArg=*/false);
+  builder.setInsertionPointToEnd(mod.getBody());
+  auto newFunc = LLVM::LLVMFuncOp::create(builder, mod.getLoc(), symName, funcTy,
+                                          LLVM::Linkage::Internal);
+
+  Block *entry = newFunc.addEntryBlock(builder);
+  builder.setInsertionPointToStart(entry);
+
+  IRMapping mapping;
+  mapping.map(region.front().getArguments(), entry->getArguments());
+
+  for (Operation &op : region.front()) {
+    Operation *clonedOp = builder.clone(op, mapping);
+    mapping.map(op.getResults(), clonedOp->getResults());
+  }
+
+  Operation *accTerm = entry->getTerminator();
+  LLVM::ReturnOp::create(builder, mod.getLoc(), ValueRange{});
+  accTerm->erase();
+
+  return newFunc;
+}
+
+struct ACCDeclareCtorDtorConversion
+    : public acc::impl::ACCDeclareCtorDtorConversionBase<
+          ACCDeclareCtorDtorConversion> {
+  using Base::Base;
+
+  void runOnOperation() override {
+    ModuleOp mod = getOperation();
+    OpBuilder builder{mod.getBodyRegion()};
+    SmallVector<Operation *> worklist;
+
+    SmallVector<Attribute, 8> allCtors;
+    SmallVector<int32_t, 8> ctorPriorities;
+    SmallVector<Attribute, 8> ctorData;
+    SmallVector<LLVM::GlobalCtorsOp, 4> globalCtorsOps;
+    collectExistingGlobalCtors(mod, allCtors, ctorPriorities, ctorData,
+                               globalCtorsOps);
+    size_t existingCtorCount = allCtors.size();
+
+    SmallVector<Attribute, 8> allDtors;
+    SmallVector<int32_t, 8> dtorPriorities;
+    SmallVector<Attribute, 8> dtorData;
+    SmallVector<LLVM::GlobalDtorsOp, 4> globalDtorsOps;
+    collectExistingGlobalDtors(mod, allDtors, dtorPriorities, dtorData,
+                               globalDtorsOps);
+    size_t existingDtorCount = allDtors.size();
+
+    mod.walk([&](acc::GlobalConstructorOp op) {
+      LLVM::LLVMFuncOp newCtor = createLLVMFunctionFromRegion(
+          op.getSymName(), op.getRegion(), mod, builder);
+      allCtors.push_back(
+          FlatSymbolRefAttr::get(mod.getContext(), newCtor.getSymName()));
+      ctorPriorities.push_back(priority);
+      // Null associated data: constructor always runs at load time.
+      ctorData.push_back(LLVM::ZeroAttr::get(builder.getContext()));
+      worklist.push_back(op.getOperation());
+    });
+
+    mod.walk([&](acc::GlobalDestructorOp op) {
+      if (generateDtors) {
+        LLVM::LLVMFuncOp newDtor = createLLVMFunctionFromRegion(
+            op.getSymName(), op.getRegion(), mod, builder);
+        allDtors.push_back(
+            FlatSymbolRefAttr::get(mod.getContext(), newDtor.getSymName()));
+        dtorPriorities.push_back(priority);
+        // Null associated data: destructor always runs at unload time.
+        dtorData.push_back(LLVM::ZeroAttr::get(builder.getContext()));
+      }
+      worklist.push_back(op.getOperation());
+    });
+
+    if (allCtors.size() > existingCtorCount)
+      replaceGlobalCtors(mod, builder, allCtors, ctorPriorities, ctorData,
+                         globalCtorsOps);
+    if (allDtors.size() > existingDtorCount)
+      replaceGlobalDtors(mod, builder, allDtors, dtorPriorities, dtorData,
+                         globalDtorsOps);
+
+    for (Operation *op : worklist)
+      op->erase();
+  }
+};
+
+} // namespace
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt b/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt
index efad2b45f66ed..3fd2672e82c50 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt
@@ -4,6 +4,7 @@ add_mlir_dialect_library(MLIROpenACCTransforms
   ACCComputeLowering.cpp
   ACCRoutineLowering.cpp
   ACCRoutineToGPUFunc.cpp
+  ACCDeclareCtorDtorConversion.cpp
   ACCDeclareGPUModuleInsertion.cpp
   ACCEmitRemarksLoop.cpp
   ACCEmitRemarksPrivate.cpp
@@ -45,6 +46,7 @@ add_mlir_dialect_library(MLIROpenACCTransforms
   MLIRGPUDialect
   MLIRGPUUtils
   MLIRIR
+  MLIRLLVMDialect
   MLIRMemRefDialect
   MLIRNVVMDialect
   MLIRPass
diff --git a/mlir/test/Dialect/OpenACC/acc-declare-ctor-dtor-conversion.mlir b/mlir/test/Dialect/OpenACC/acc-declare-ctor-dtor-conversion.mlir
new file mode 100644
index 0000000000000..4768bbc602412
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/acc-declare-ctor-dtor-conversion.mlir
@@ -0,0 +1,76 @@
+// RUN: mlir-opt %s -acc-declare-ctor-dtor-conversion -split-input-file | FileCheck %s
+// RUN: mlir-opt %s --pass-pipeline="builtin.module(acc-declare-ctor-dtor-conversion{generate-dtors=false})" -split-input-file | FileCheck %s --check-prefix=NODTOR
+
+// CHECK-NOT: acc.global_ctor
+// CHECK-NOT: acc.global_dtor
+// CHECK: llvm.func internal @arr_acc_ctor()
+// CHECK: llvm.func internal @other_arr_acc_ctor()
+// CHECK: llvm.func internal @arr_acc_dtor()
+// CHECK: llvm.func internal @other_arr_acc_dtor()
+// CHECK: llvm.mlir.global_ctors ctors = [@arr_acc_ctor, @other_arr_acc_ctor], priorities = [102 : i32, 102 : i32], data = [#llvm.zero, #llvm.zero]
+// CHECK: llvm.mlir.global_dtors dtors = [@arr_acc_dtor, @other_arr_acc_dtor], priorities = [102 : i32, 102 : i32], data = [#llvm.zero, #llvm.zero]
+
+// NODTOR-NOT: @arr_acc_dtor
+// NODTOR-NOT: @other_arr_acc_dtor
+// NODTOR: llvm.func internal @arr_acc_ctor()
+// NODTOR: llvm.func internal @other_arr_acc_ctor()
+// NODTOR: llvm.mlir.global_ctors ctors = [@arr_acc_ctor, @other_arr_acc_ctor], priorities = [102 : i32, 102 : i32], data = [#llvm.zero, #llvm.zero]
+// NODTOR-NOT: llvm.mlir.global_dtors
+
+llvm.mlir.global external @arr() {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.array<7 x f32> {
+  %0 = llvm.mlir.zero : !llvm.array<7 x f32>
+  llvm.return %0 : !llvm.array<7 x f32>
+}
+llvm.mlir.global external @other_arr() {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.array<3 x f32> {
+  %0 = llvm.mlir.zero : !llvm.array<3 x f32>
+  llvm.return %0 : !llvm.array<3 x f32>
+}
+acc.global_ctor @arr_acc_ctor {
+  %0 = llvm.mlir.addressof @arr {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.ptr
+  %1 = acc.create varPtr(%0 : !llvm.ptr) varType(!llvm.array<7 x f32>) -> !llvm.ptr
+  acc.declare_enter dataOperands(%1 : !llvm.ptr)
+  acc.terminator
+}
+acc.global_ctor @other_arr_acc_ctor {
+  %0 = llvm.mlir.addressof @other_arr {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.ptr
+  %1 = acc.create varPtr(%0 : !llvm.ptr) varType(!llvm.array<3 x f32>) -> !llvm.ptr
+  acc.declare_enter dataOperands(%1 : !llvm.ptr)
+  acc.terminator
+}
+acc.global_dtor @arr_acc_dtor {
+  %0 = llvm.mlir.addressof @arr {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.ptr
+  %1 = acc.getdeviceptr varPtr(%0 : !llvm.ptr) varType(!llvm.array<7 x f32>) -> !llvm.ptr {dataClause = #acc<data_clause acc_create>}
+  acc.declare_exit dataOperands(%1 : !llvm.ptr)
+  acc.delete accPtr(%1 : !llvm.ptr)
+  acc.terminator
+}
+acc.global_dtor @other_arr_acc_dtor {
+  %0 = llvm.mlir.addressof @other_arr {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.ptr
+  %1 = acc.getdeviceptr varPtr(%0 : !llvm.ptr) varType(!llvm.array<3 x f32>) -> !llvm.ptr {dataClause = #acc<data_clause acc_create>}
+  acc.declare_exit dataOperands(%1 : !llvm.ptr)
+  acc.delete accPtr(%1 : !llvm.ptr)
+  acc.terminator
+}
+
+// -----
+
+// Merge with an existing llvm.mlir.global_ctors entry.
+
+// CHECK: llvm.func internal @existing_ctor
+// CHECK: llvm.func internal @merged_acc_ctor
+// CHECK: llvm.mlir.global_ctors ctors = [@existing_ctor, @merged_acc_ctor], priorities = [0 : i32, 102 : i32], data = [#llvm.zero, #llvm.zero]
+
+llvm.mlir.global external @merged_var() {acc.declare = #acc.declare<dataClause = acc_create>} : i32 {
+  %0 = llvm.mlir.constant(0 : i32) : i32
+  llvm.return %0 : i32
+}
+llvm.func internal @existing_ctor() {
+  llvm.return
+}
+llvm.mlir.global_ctors ctors = [@existing_ctor], priorities = [0 : i32], data = [#llvm.zero]
+acc.global_ctor @merged_acc_ctor {
+  %0 = llvm.mlir.addressof @merged_var {acc.declare = #acc.declare<dataClause = acc_create>} : !llvm.ptr
+  %1 = acc.create varPtr(%0 : !llvm.ptr) varType(i32) -> !llvm.ptr
+  acc.declare_enter dataOperands(%1 : !llvm.ptr)
+  acc.terminator
+}



More information about the Mlir-commits mailing list