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