MLIR 24.0.0git
ACCDeclareCtorDtorConversion.cpp
Go to the documentation of this file.
1//===- ACCDeclareCtorDtorConversion.cpp - Declare ctor/dtor to LLVM -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Convert ACC declare global constructors and destructors to LLVM functions
10// registered in llvm.mlir.global_ctors / llvm.mlir.global_dtors.
11//
12//===----------------------------------------------------------------------===//
13
17#include "mlir/IR/Builders.h"
18#include "mlir/IR/IRMapping.h"
19#include "mlir/Pass/Pass.h"
20
21namespace mlir {
22namespace acc {
23#define GEN_PASS_DEF_ACCDECLARECTORDTORCONVERSION
24#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
25} // namespace acc
26} // namespace mlir
27
28using namespace mlir;
29
30namespace {
31
32static void collectExistingGlobalCtors(
33 ModuleOp mod, SmallVectorImpl<Attribute> &ctors,
36 for (auto globalCtors : mod.getOps<LLVM::GlobalCtorsOp>()) {
37 ctors.append(globalCtors.getCtors().begin(), globalCtors.getCtors().end());
38 for (Attribute attr : globalCtors.getPriorities())
39 priorities.push_back(cast<IntegerAttr>(attr).getInt());
40 data.append(globalCtors.getData().begin(), globalCtors.getData().end());
41 globalCtorsOps.push_back(globalCtors);
42 }
43}
44
45static void collectExistingGlobalDtors(
46 ModuleOp mod, SmallVectorImpl<Attribute> &dtors,
49 for (auto globalDtors : mod.getOps<LLVM::GlobalDtorsOp>()) {
50 dtors.append(globalDtors.getDtors().begin(), globalDtors.getDtors().end());
51 for (Attribute attr : globalDtors.getPriorities())
52 priorities.push_back(cast<IntegerAttr>(attr).getInt());
53 data.append(globalDtors.getData().begin(), globalDtors.getData().end());
54 globalDtorsOps.push_back(globalDtors);
55 }
56}
57
58static void replaceGlobalCtors(ModuleOp mod, OpBuilder &builder,
60 ArrayRef<int32_t> priorities,
63 for (auto globalCtors : oldOps)
64 globalCtors.erase();
65 if (ctors.empty())
66 return;
67
68 builder.setInsertionPointToEnd(mod.getBody());
69 LLVM::GlobalCtorsOp::create(
70 builder, mod.getLoc(), builder.getArrayAttr(ctors),
71 builder.getI32ArrayAttr(priorities), builder.getArrayAttr(data));
72}
73
74static void replaceGlobalDtors(ModuleOp mod, OpBuilder &builder,
76 ArrayRef<int32_t> priorities,
79 for (auto globalDtors : oldOps)
80 globalDtors.erase();
81 if (dtors.empty())
82 return;
83
84 builder.setInsertionPointToEnd(mod.getBody());
85 LLVM::GlobalDtorsOp::create(
86 builder, mod.getLoc(), builder.getArrayAttr(dtors),
87 builder.getI32ArrayAttr(priorities), builder.getArrayAttr(data));
88}
89
90/// Create an llvm.func from an acc.global_ctor / acc.global_dtor region.
91/// Nested operations are cloned unchanged for later lowering.
92static LLVM::LLVMFuncOp createLLVMFunctionFromRegion(StringRef symName,
93 Region &region,
94 ModuleOp mod,
95 OpBuilder &builder) {
96 auto llvmVoidTy = LLVM::LLVMVoidType::get(mod.getContext());
97 auto funcTy = LLVM::LLVMFunctionType::get(llvmVoidTy, {}, /*isVarArg=*/false);
98 builder.setInsertionPointToEnd(mod.getBody());
99 auto newFunc = LLVM::LLVMFuncOp::create(builder, mod.getLoc(), symName,
100 funcTy, LLVM::Linkage::Internal);
101
102 Block *entry = newFunc.addEntryBlock(builder);
103 builder.setInsertionPointToStart(entry);
104
105 IRMapping mapping;
106 mapping.map(region.front().getArguments(), entry->getArguments());
107
108 for (Operation &op : region.front()) {
109 Operation *clonedOp = builder.clone(op, mapping);
110 mapping.map(op.getResults(), clonedOp->getResults());
111 }
112
113 Operation *accTerm = entry->getTerminator();
114 LLVM::ReturnOp::create(builder, mod.getLoc(), ValueRange{});
115 accTerm->erase();
116
117 return newFunc;
118}
119
120struct ACCDeclareCtorDtorConversion
121 : public acc::impl::ACCDeclareCtorDtorConversionBase<
122 ACCDeclareCtorDtorConversion> {
123 using Base::Base;
124
125 void runOnOperation() override {
126 ModuleOp mod = getOperation();
127 OpBuilder builder{mod.getBodyRegion()};
128 SmallVector<Operation *> worklist;
129
130 SmallVector<Attribute, 8> allCtors;
131 SmallVector<int32_t, 8> ctorPriorities;
132 SmallVector<Attribute, 8> ctorData;
133 SmallVector<LLVM::GlobalCtorsOp, 4> globalCtorsOps;
134 collectExistingGlobalCtors(mod, allCtors, ctorPriorities, ctorData,
135 globalCtorsOps);
136 size_t existingCtorCount = allCtors.size();
137
138 SmallVector<Attribute, 8> allDtors;
139 SmallVector<int32_t, 8> dtorPriorities;
140 SmallVector<Attribute, 8> dtorData;
141 SmallVector<LLVM::GlobalDtorsOp, 4> globalDtorsOps;
142 collectExistingGlobalDtors(mod, allDtors, dtorPriorities, dtorData,
143 globalDtorsOps);
144 size_t existingDtorCount = allDtors.size();
145
146 mod.walk([&](acc::GlobalConstructorOp op) {
147 LLVM::LLVMFuncOp newCtor = createLLVMFunctionFromRegion(
148 op.getSymName(), op.getRegion(), mod, builder);
149 allCtors.push_back(
150 FlatSymbolRefAttr::get(mod.getContext(), newCtor.getSymName()));
151 ctorPriorities.push_back(priority);
152 // Null associated data: constructor always runs at load time.
153 ctorData.push_back(LLVM::ZeroAttr::get(builder.getContext()));
154 worklist.push_back(op.getOperation());
155 });
156
157 mod.walk([&](acc::GlobalDestructorOp op) {
158 if (generateDtors) {
159 LLVM::LLVMFuncOp newDtor = createLLVMFunctionFromRegion(
160 op.getSymName(), op.getRegion(), mod, builder);
161 allDtors.push_back(
162 FlatSymbolRefAttr::get(mod.getContext(), newDtor.getSymName()));
163 dtorPriorities.push_back(priority);
164 // Null associated data: destructor always runs at unload time.
165 dtorData.push_back(LLVM::ZeroAttr::get(builder.getContext()));
166 }
167 worklist.push_back(op.getOperation());
168 });
169
170 if (allCtors.size() > existingCtorCount)
171 replaceGlobalCtors(mod, builder, allCtors, ctorPriorities, ctorData,
172 globalCtorsOps);
173 if (allDtors.size() > existingDtorCount)
174 replaceGlobalDtors(mod, builder, allDtors, dtorPriorities, dtorData,
175 globalDtorsOps);
176
177 for (Operation *op : worklist)
178 op->erase();
179 }
180};
181
182} // namespace
Attributes are known-constant values of operations.
Definition Attributes.h:25
Block represents an ordered list of Operations.
Definition Block.h:33
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
BlockArgListType getArguments()
Definition Block.h:111
ArrayAttr getI32ArrayAttr(ArrayRef< int32_t > values)
Definition Builders.cpp:285
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition Builders.cpp:275
MLIRContext * getContext() const
Definition Builders.h:56
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition IRMapping.h:30
This class helps build Operations.
Definition Builders.h:210
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
Definition Builders.cpp:571
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:434
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Definition Builders.h:439
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
result_range getResults()
Definition Operation.h:440
void erase()
Remove this operation from its parent block and delete it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Block & front()
Definition Region.h:65
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
Include the generated interface declarations.