1//===- OpenACCToLLVMIRTranslation.cpp -------------------------------------===//
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// This file implements a translation between the MLIR OpenACC dialect and LLVM
10// IR.
11//
12//===----------------------------------------------------------------------===//
13
14#include "mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h"
15#include "mlir/Analysis/TopologicalSortUtils.h"
16#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
17#include "mlir/Dialect/OpenACC/OpenACC.h"
18#include "mlir/IR/Operation.h"
19#include "mlir/Support/LLVM.h"
20#include "mlir/Target/LLVMIR/Dialect/OpenMPCommon.h"
21#include "mlir/Target/LLVMIR/ModuleTranslation.h"
22
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Frontend/OpenMP/OMPConstants.h"
25
26using namespace mlir;
27
28using OpenACCIRBuilder = llvm::OpenMPIRBuilder;
29
30//===----------------------------------------------------------------------===//
31// Utility functions
32//===----------------------------------------------------------------------===//
33
34/// Flag values are extracted from openmp/libomptarget/include/omptarget.h and
35/// mapped to corresponding OpenACC flags.
36static constexpr uint64_t kCreateFlag = 0x000;
37static constexpr uint64_t kDeviceCopyinFlag = 0x001;
38static constexpr uint64_t kHostCopyoutFlag = 0x002;
39static constexpr uint64_t kPresentFlag = 0x1000;
40static constexpr uint64_t kDeleteFlag = 0x008;
41// Runtime extension to implement the OpenACC second reference counter.
42static constexpr uint64_t kHoldFlag = 0x2000;
43
44/// Default value for the device id
45static constexpr int64_t kDefaultDevice = -1;
46
47/// Create the location struct from the operation location information.
48static llvm::Value *createSourceLocationInfo(OpenACCIRBuilder &builder,
49 Operation *op) {
50 auto loc = op->getLoc();
51 auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
52 StringRef funcName = funcOp ? funcOp.getName() : "unknown";
53 uint32_t strLen;
54 llvm::Constant *locStr = mlir::LLVM::createSourceLocStrFromLocation(
55 loc, builder, name: funcName, strLen);
56 return builder.getOrCreateIdent(SrcLocStr: locStr, SrcLocStrSize: strLen);
57}
58
59/// Return the runtime function used to lower the given operation.
60static llvm::Function *getAssociatedFunction(OpenACCIRBuilder &builder,
61 Operation *op) {
62 return llvm::TypeSwitch<Operation *, llvm::Function *>(op)
63 .Case(caseFn: [&](acc::EnterDataOp) {
64 return builder.getOrCreateRuntimeFunctionPtr(
65 FnID: llvm::omp::OMPRTL___tgt_target_data_begin_mapper);
66 })
67 .Case(caseFn: [&](acc::ExitDataOp) {
68 return builder.getOrCreateRuntimeFunctionPtr(
69 FnID: llvm::omp::OMPRTL___tgt_target_data_end_mapper);
70 })
71 .Case(caseFn: [&](acc::UpdateOp) {
72 return builder.getOrCreateRuntimeFunctionPtr(
73 FnID: llvm::omp::OMPRTL___tgt_target_data_update_mapper);
74 });
75 llvm_unreachable("Unknown OpenACC operation");
76}
77
78/// Extract pointer, size and mapping information from operands
79/// to populate the future functions arguments.
80static LogicalResult
81processOperands(llvm::IRBuilderBase &builder,
82 LLVM::ModuleTranslation &moduleTranslation, Operation *op,
83 ValueRange operands, unsigned totalNbOperand,
84 uint64_t operandFlag, SmallVector<uint64_t> &flags,
85 SmallVectorImpl<llvm::Constant *> &names, unsigned &index,
86 struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
87 OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
88 llvm::LLVMContext &ctx = builder.getContext();
89 auto *i8PtrTy = llvm::PointerType::getUnqual(C&: ctx);
90 auto *arrI8PtrTy = llvm::ArrayType::get(ElementType: i8PtrTy, NumElements: totalNbOperand);
91 auto *i64Ty = llvm::Type::getInt64Ty(C&: ctx);
92 auto *arrI64Ty = llvm::ArrayType::get(ElementType: i64Ty, NumElements: totalNbOperand);
93
94 for (Value data : operands) {
95 llvm::Value *dataValue = moduleTranslation.lookupValue(value: data);
96
97 llvm::Value *dataPtrBase;
98 llvm::Value *dataPtr;
99 llvm::Value *dataSize;
100
101 if (isa<LLVM::LLVMPointerType>(Val: data.getType())) {
102 dataPtrBase = dataValue;
103 dataPtr = dataValue;
104 dataSize = accBuilder->getSizeInBytes(BasePtr: dataValue);
105 } else {
106 return op->emitOpError()
107 << "Data operand must be legalized before translation."
108 << "Unsupported type: " << data.getType();
109 }
110
111 // Store base pointer extracted from operand into the i-th position of
112 // argBase.
113 llvm::Value *ptrBaseGEP = builder.CreateInBoundsGEP(
114 Ty: arrI8PtrTy, Ptr: mapperAllocas.ArgsBase,
115 IdxList: {builder.getInt32(C: 0), builder.getInt32(C: index)});
116 builder.CreateStore(Val: dataPtrBase, Ptr: ptrBaseGEP);
117
118 // Store pointer extracted from operand into the i-th position of args.
119 llvm::Value *ptrGEP = builder.CreateInBoundsGEP(
120 Ty: arrI8PtrTy, Ptr: mapperAllocas.Args,
121 IdxList: {builder.getInt32(C: 0), builder.getInt32(C: index)});
122 builder.CreateStore(Val: dataPtr, Ptr: ptrGEP);
123
124 // Store size extracted from operand into the i-th position of argSizes.
125 llvm::Value *sizeGEP = builder.CreateInBoundsGEP(
126 Ty: arrI64Ty, Ptr: mapperAllocas.ArgSizes,
127 IdxList: {builder.getInt32(C: 0), builder.getInt32(C: index)});
128 builder.CreateStore(Val: dataSize, Ptr: sizeGEP);
129
130 flags.push_back(Elt: operandFlag);
131 llvm::Constant *mapName =
132 mlir::LLVM::createMappingInformation(loc: data.getLoc(), builder&: *accBuilder);
133 names.push_back(Elt: mapName);
134 ++index;
135 }
136 return success();
137}
138
139/// Process data operands from acc::EnterDataOp
140static LogicalResult
141processDataOperands(llvm::IRBuilderBase &builder,
142 LLVM::ModuleTranslation &moduleTranslation,
143 acc::EnterDataOp op, SmallVector<uint64_t> &flags,
144 SmallVectorImpl<llvm::Constant *> &names,
145 struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
146 // TODO add `create_zero` and `attach` operands
147
148 unsigned index = 0;
149
150 // Create operands are handled as `alloc` call.
151 // Copyin operands are handled as `to` call.
152 llvm::SmallVector<mlir::Value> create, copyin;
153 for (mlir::Value dataOp : op.getDataClauseOperands()) {
154 if (auto createOp =
155 mlir::dyn_cast_or_null<acc::CreateOp>(Val: dataOp.getDefiningOp())) {
156 create.push_back(Elt: createOp.getVarPtr());
157 } else if (auto copyinOp = mlir::dyn_cast_or_null<acc::CopyinOp>(
158 Val: dataOp.getDefiningOp())) {
159 copyin.push_back(Elt: copyinOp.getVarPtr());
160 }
161 }
162
163 auto nbTotalOperands = create.size() + copyin.size();
164
165 // Create operands are handled as `alloc` call.
166 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: create,
167 totalNbOperand: nbTotalOperands, operandFlag: kCreateFlag, flags, names, index,
168 mapperAllocas)))
169 return failure();
170
171 // Copyin operands are handled as `to` call.
172 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: copyin,
173 totalNbOperand: nbTotalOperands, operandFlag: kDeviceCopyinFlag, flags, names,
174 index, mapperAllocas)))
175 return failure();
176
177 return success();
178}
179
180/// Process data operands from acc::ExitDataOp
181static LogicalResult
182processDataOperands(llvm::IRBuilderBase &builder,
183 LLVM::ModuleTranslation &moduleTranslation,
184 acc::ExitDataOp op, SmallVector<uint64_t> &flags,
185 SmallVectorImpl<llvm::Constant *> &names,
186 struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
187 // TODO add `detach` operands
188
189 unsigned index = 0;
190
191 llvm::SmallVector<mlir::Value> deleteOperands, copyoutOperands;
192 for (mlir::Value dataOp : op.getDataClauseOperands()) {
193 if (auto devicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
194 Val: dataOp.getDefiningOp())) {
195 for (auto &u : devicePtrOp.getAccPtr().getUses()) {
196 if (mlir::dyn_cast_or_null<acc::DeleteOp>(Val: u.getOwner()))
197 deleteOperands.push_back(Elt: devicePtrOp.getVarPtr());
198 else if (mlir::dyn_cast_or_null<acc::CopyoutOp>(Val: u.getOwner()))
199 copyoutOperands.push_back(Elt: devicePtrOp.getVarPtr());
200 }
201 }
202 }
203
204 auto nbTotalOperands = deleteOperands.size() + copyoutOperands.size();
205
206 // Delete operands are handled as `delete` call.
207 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: deleteOperands,
208 totalNbOperand: nbTotalOperands, operandFlag: kDeleteFlag, flags, names, index,
209 mapperAllocas)))
210 return failure();
211
212 // Copyout operands are handled as `from` call.
213 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: copyoutOperands,
214 totalNbOperand: nbTotalOperands, operandFlag: kHostCopyoutFlag, flags, names,
215 index, mapperAllocas)))
216 return failure();
217
218 return success();
219}
220
221/// Process data operands from acc::UpdateOp
222static LogicalResult
223processDataOperands(llvm::IRBuilderBase &builder,
224 LLVM::ModuleTranslation &moduleTranslation,
225 acc::UpdateOp op, SmallVector<uint64_t> &flags,
226 SmallVectorImpl<llvm::Constant *> &names,
227 struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
228 unsigned index = 0;
229
230 // Host operands are handled as `from` call.
231 // Device operands are handled as `to` call.
232 llvm::SmallVector<mlir::Value> from, to;
233 for (mlir::Value dataOp : op.getDataClauseOperands()) {
234 if (auto getDevicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
235 Val: dataOp.getDefiningOp())) {
236 from.push_back(Elt: getDevicePtrOp.getVarPtr());
237 } else if (auto updateDeviceOp =
238 mlir::dyn_cast_or_null<acc::UpdateDeviceOp>(
239 Val: dataOp.getDefiningOp())) {
240 to.push_back(Elt: updateDeviceOp.getVarPtr());
241 }
242 }
243
244 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: from, totalNbOperand: from.size(),
245 operandFlag: kHostCopyoutFlag, flags, names, index,
246 mapperAllocas)))
247 return failure();
248
249 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: to, totalNbOperand: to.size(),
250 operandFlag: kDeviceCopyinFlag, flags, names, index,
251 mapperAllocas)))
252 return failure();
253 return success();
254}
255
256//===----------------------------------------------------------------------===//
257// Conversion functions
258//===----------------------------------------------------------------------===//
259
260/// Converts an OpenACC data operation into LLVM IR.
261static LogicalResult convertDataOp(acc::DataOp &op,
262 llvm::IRBuilderBase &builder,
263 LLVM::ModuleTranslation &moduleTranslation) {
264 llvm::LLVMContext &ctx = builder.getContext();
265 auto enclosingFuncOp = op.getOperation()->getParentOfType<LLVM::LLVMFuncOp>();
266 llvm::Function *enclosingFunction =
267 moduleTranslation.lookupFunction(name: enclosingFuncOp.getName());
268
269 OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
270
271 llvm::Value *srcLocInfo = createSourceLocationInfo(builder&: *accBuilder, op);
272
273 llvm::Function *beginMapperFunc = accBuilder->getOrCreateRuntimeFunctionPtr(
274 FnID: llvm::omp::OMPRTL___tgt_target_data_begin_mapper);
275
276 llvm::Function *endMapperFunc = accBuilder->getOrCreateRuntimeFunctionPtr(
277 FnID: llvm::omp::OMPRTL___tgt_target_data_end_mapper);
278
279 // Number of arguments in the data operation.
280 unsigned totalNbOperand = op.getNumDataOperands();
281
282 struct OpenACCIRBuilder::MapperAllocas mapperAllocas;
283 OpenACCIRBuilder::InsertPointTy allocaIP(
284 &enclosingFunction->getEntryBlock(),
285 enclosingFunction->getEntryBlock().getFirstInsertionPt());
286 accBuilder->createMapperAllocas(Loc: builder.saveIP(), AllocaIP: allocaIP, NumOperands: totalNbOperand,
287 MapperAllocas&: mapperAllocas);
288
289 SmallVector<uint64_t> flags;
290 SmallVector<llvm::Constant *> names;
291 unsigned index = 0;
292
293 // TODO handle no_create, deviceptr and attach operands.
294
295 llvm::SmallVector<mlir::Value> copyin, copyout, create, present,
296 deleteOperands;
297 for (mlir::Value dataOp : op.getDataClauseOperands()) {
298 if (auto devicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
299 Val: dataOp.getDefiningOp())) {
300 for (auto &u : devicePtrOp.getAccPtr().getUses()) {
301 if (mlir::dyn_cast_or_null<acc::DeleteOp>(Val: u.getOwner())) {
302 deleteOperands.push_back(Elt: devicePtrOp.getVarPtr());
303 } else if (mlir::dyn_cast_or_null<acc::CopyoutOp>(Val: u.getOwner())) {
304 // TODO copyout zero currenlty handled as copyout. Update when
305 // extension available.
306 copyout.push_back(Elt: devicePtrOp.getVarPtr());
307 }
308 }
309 } else if (auto copyinOp = mlir::dyn_cast_or_null<acc::CopyinOp>(
310 Val: dataOp.getDefiningOp())) {
311 // TODO copyin readonly currenlty handled as copyin. Update when extension
312 // available.
313 copyin.push_back(Elt: copyinOp.getVarPtr());
314 } else if (auto createOp = mlir::dyn_cast_or_null<acc::CreateOp>(
315 Val: dataOp.getDefiningOp())) {
316 // TODO create zero currenlty handled as create. Update when extension
317 // available.
318 create.push_back(Elt: createOp.getVarPtr());
319 } else if (auto presentOp = mlir::dyn_cast_or_null<acc::PresentOp>(
320 Val: dataOp.getDefiningOp())) {
321 present.push_back(Elt: createOp.getVarPtr());
322 }
323 }
324
325 auto nbTotalOperands = copyin.size() + copyout.size() + create.size() +
326 present.size() + deleteOperands.size();
327
328 // Copyin operands are handled as `to` call.
329 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: copyin,
330 totalNbOperand: nbTotalOperands, operandFlag: kDeviceCopyinFlag | kHoldFlag,
331 flags, names, index, mapperAllocas)))
332 return failure();
333
334 // Delete operands are handled as `delete` call.
335 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: deleteOperands,
336 totalNbOperand: nbTotalOperands, operandFlag: kDeleteFlag, flags, names, index,
337 mapperAllocas)))
338 return failure();
339
340 // Copyout operands are handled as `from` call.
341 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: copyout,
342 totalNbOperand: nbTotalOperands, operandFlag: kHostCopyoutFlag | kHoldFlag,
343 flags, names, index, mapperAllocas)))
344 return failure();
345
346 // Create operands are handled as `alloc` call.
347 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: create,
348 totalNbOperand: nbTotalOperands, operandFlag: kCreateFlag | kHoldFlag, flags,
349 names, index, mapperAllocas)))
350 return failure();
351
352 if (failed(Result: processOperands(builder, moduleTranslation, op, operands: present,
353 totalNbOperand: nbTotalOperands, operandFlag: kPresentFlag | kHoldFlag, flags,
354 names, index, mapperAllocas)))
355 return failure();
356
357 llvm::GlobalVariable *maptypes =
358 accBuilder->createOffloadMaptypes(Mappings&: flags, VarName: ".offload_maptypes");
359 llvm::Value *maptypesArg = builder.CreateConstInBoundsGEP2_32(
360 Ty: llvm::ArrayType::get(ElementType: llvm::Type::getInt64Ty(C&: ctx), NumElements: totalNbOperand),
361 Ptr: maptypes, /*Idx0=*/0, /*Idx1=*/0);
362
363 llvm::GlobalVariable *mapnames =
364 accBuilder->createOffloadMapnames(Names&: names, VarName: ".offload_mapnames");
365 llvm::Value *mapnamesArg = builder.CreateConstInBoundsGEP2_32(
366 Ty: llvm::ArrayType::get(ElementType: llvm::PointerType::getUnqual(C&: ctx), NumElements: totalNbOperand),
367 Ptr: mapnames, /*Idx0=*/0, /*Idx1=*/0);
368
369 // Create call to start the data region.
370 accBuilder->emitMapperCall(Loc: builder.saveIP(), MapperFunc: beginMapperFunc, SrcLocInfo: srcLocInfo,
371 MaptypesArg: maptypesArg, MapnamesArg: mapnamesArg, MapperAllocas&: mapperAllocas,
372 DeviceID: kDefaultDevice, NumOperands: totalNbOperand);
373
374 // Convert the region.
375 llvm::BasicBlock *entryBlock = nullptr;
376
377 for (Block &bb : op.getRegion()) {
378 llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create(
379 Context&: ctx, Name: "acc.data", Parent: builder.GetInsertBlock()->getParent());
380 if (entryBlock == nullptr)
381 entryBlock = llvmBB;
382 moduleTranslation.mapBlock(mlir: &bb, llvm: llvmBB);
383 }
384
385 auto afterDataRegion = builder.saveIP();
386
387 llvm::BranchInst *sourceTerminator = builder.CreateBr(Dest: entryBlock);
388
389 builder.restoreIP(IP: afterDataRegion);
390 llvm::BasicBlock *endDataBlock = llvm::BasicBlock::Create(
391 Context&: ctx, Name: "acc.end_data", Parent: builder.GetInsertBlock()->getParent());
392
393 SetVector<Block *> blocks = getBlocksSortedByDominance(region&: op.getRegion());
394 for (Block *bb : blocks) {
395 llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(block: bb);
396 if (bb->isEntryBlock()) {
397 assert(sourceTerminator->getNumSuccessors() == 1 &&
398 "provided entry block has multiple successors");
399 sourceTerminator->setSuccessor(idx: 0, NewSucc: llvmBB);
400 }
401
402 if (failed(
403 Result: moduleTranslation.convertBlock(bb&: *bb, ignoreArguments: bb->isEntryBlock(), builder))) {
404 return failure();
405 }
406
407 if (isa<acc::TerminatorOp, acc::YieldOp>(Val: bb->getTerminator()))
408 builder.CreateBr(Dest: endDataBlock);
409 }
410
411 // Create call to end the data region.
412 builder.SetInsertPoint(endDataBlock);
413 accBuilder->emitMapperCall(Loc: builder.saveIP(), MapperFunc: endMapperFunc, SrcLocInfo: srcLocInfo,
414 MaptypesArg: maptypesArg, MapnamesArg: mapnamesArg, MapperAllocas&: mapperAllocas,
415 DeviceID: kDefaultDevice, NumOperands: totalNbOperand);
416
417 return success();
418}
419
420/// Converts an OpenACC standalone data operation into LLVM IR.
421template <typename OpTy>
422static LogicalResult
423convertStandaloneDataOp(OpTy &op, llvm::IRBuilderBase &builder,
424 LLVM::ModuleTranslation &moduleTranslation) {
425 auto enclosingFuncOp =
426 op.getOperation()->template getParentOfType<LLVM::LLVMFuncOp>();
427 llvm::Function *enclosingFunction =
428 moduleTranslation.lookupFunction(name: enclosingFuncOp.getName());
429
430 OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
431
432 auto *srcLocInfo = createSourceLocationInfo(*accBuilder, op);
433 auto *mapperFunc = getAssociatedFunction(*accBuilder, op);
434
435 // Number of arguments in the enter_data operation.
436 unsigned totalNbOperand = op.getNumDataOperands();
437
438 llvm::LLVMContext &ctx = builder.getContext();
439
440 struct OpenACCIRBuilder::MapperAllocas mapperAllocas;
441 OpenACCIRBuilder::InsertPointTy allocaIP(
442 &enclosingFunction->getEntryBlock(),
443 enclosingFunction->getEntryBlock().getFirstInsertionPt());
444 accBuilder->createMapperAllocas(Loc: builder.saveIP(), AllocaIP: allocaIP, NumOperands: totalNbOperand,
445 MapperAllocas&: mapperAllocas);
446
447 SmallVector<uint64_t> flags;
448 SmallVector<llvm::Constant *> names;
449
450 if (failed(processDataOperands(builder, moduleTranslation, op, flags, names,
451 mapperAllocas)))
452 return failure();
453
454 llvm::GlobalVariable *maptypes =
455 accBuilder->createOffloadMaptypes(Mappings&: flags, VarName: ".offload_maptypes");
456 llvm::Value *maptypesArg = builder.CreateConstInBoundsGEP2_32(
457 Ty: llvm::ArrayType::get(ElementType: llvm::Type::getInt64Ty(C&: ctx), NumElements: totalNbOperand),
458 Ptr: maptypes, /*Idx0=*/0, /*Idx1=*/0);
459
460 llvm::GlobalVariable *mapnames =
461 accBuilder->createOffloadMapnames(Names&: names, VarName: ".offload_mapnames");
462 llvm::Value *mapnamesArg = builder.CreateConstInBoundsGEP2_32(
463 Ty: llvm::ArrayType::get(ElementType: llvm::PointerType::getUnqual(C&: ctx), NumElements: totalNbOperand),
464 Ptr: mapnames, /*Idx0=*/0, /*Idx1=*/0);
465
466 accBuilder->emitMapperCall(Loc: builder.saveIP(), MapperFunc: mapperFunc, SrcLocInfo: srcLocInfo,
467 MaptypesArg: maptypesArg, MapnamesArg: mapnamesArg, MapperAllocas&: mapperAllocas,
468 DeviceID: kDefaultDevice, NumOperands: totalNbOperand);
469
470 return success();
471}
472
473namespace {
474
475/// Implementation of the dialect interface that converts operations belonging
476/// to the OpenACC dialect to LLVM IR.
477class OpenACCDialectLLVMIRTranslationInterface
478 : public LLVMTranslationDialectInterface {
479public:
480 using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
481
482 /// Translates the given operation to LLVM IR using the provided IR builder
483 /// and saving the state in `moduleTranslation`.
484 LogicalResult
485 convertOperation(Operation *op, llvm::IRBuilderBase &builder,
486 LLVM::ModuleTranslation &moduleTranslation) const final;
487};
488
489} // namespace
490
491/// Given an OpenACC MLIR operation, create the corresponding LLVM IR
492/// (including OpenACC runtime calls).
493LogicalResult OpenACCDialectLLVMIRTranslationInterface::convertOperation(
494 Operation *op, llvm::IRBuilderBase &builder,
495 LLVM::ModuleTranslation &moduleTranslation) const {
496
497 return llvm::TypeSwitch<Operation *, LogicalResult>(op)
498 .Case(caseFn: [&](acc::DataOp dataOp) {
499 return convertDataOp(op&: dataOp, builder, moduleTranslation);
500 })
501 .Case(caseFn: [&](acc::EnterDataOp enterDataOp) {
502 return convertStandaloneDataOp<acc::EnterDataOp>(op&: enterDataOp, builder,
503 moduleTranslation);
504 })
505 .Case(caseFn: [&](acc::ExitDataOp exitDataOp) {
506 return convertStandaloneDataOp<acc::ExitDataOp>(op&: exitDataOp, builder,
507 moduleTranslation);
508 })
509 .Case(caseFn: [&](acc::UpdateOp updateOp) {
510 return convertStandaloneDataOp<acc::UpdateOp>(op&: updateOp, builder,
511 moduleTranslation);
512 })
513 .Case<acc::TerminatorOp, acc::YieldOp>(caseFn: [](auto op) {
514 // `yield` and `terminator` can be just omitted. The block structure was
515 // created in the function that handles their parent operation.
516 assert(op->getNumOperands() == 0 &&
517 "unexpected OpenACC terminator with operands");
518 return success();
519 })
520 .Case<acc::CreateOp, acc::CopyinOp, acc::CopyoutOp, acc::DeleteOp,
521 acc::UpdateDeviceOp, acc::GetDevicePtrOp>(caseFn: [](auto op) {
522 // NOP
523 return success();
524 })
525 .Default(defaultFn: [&](Operation *op) {
526 return op->emitError(message: "unsupported OpenACC operation: ")
527 << op->getName();
528 });
529}
530
531void mlir::registerOpenACCDialectTranslation(DialectRegistry &registry) {
532 registry.insert<acc::OpenACCDialect>();
533 registry.addExtension(extensionFn: +[](MLIRContext *ctx, acc::OpenACCDialect *dialect) {
534 dialect->addInterfaces<OpenACCDialectLLVMIRTranslationInterface>();
535 });
536}
537
538void mlir::registerOpenACCDialectTranslation(MLIRContext &context) {
539 DialectRegistry registry;
540 registerOpenACCDialectTranslation(registry);
541 context.appendDialectRegistry(registry);
542}
543

source code of mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp