[llvm] fe7ca1a - [mlir][openacc] Initial translation for DataOp to LLVM IR

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 27 19:04:10 PDT 2021


Author: Valentin Clement
Date: 2021-07-27T22:04:04-04:00
New Revision: fe7ca1a9fca0ccea7495224e0e837de705e69699

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

LOG: [mlir][openacc] Initial translation for DataOp to LLVM IR

Add basic translation of acc.data to LLVM IR with runtime calls.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D104301

Added: 
    

Modified: 
    llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
    llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
    llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
    mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp
    mlir/test/Target/LLVMIR/openacc-llvm.mlir

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
index a92c3ba381c67..8144f1527a067 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
@@ -636,6 +636,31 @@ class OpenMPIRBuilder {
   createOffloadMapnames(SmallVectorImpl<llvm::Constant *> &Names,
                         std::string VarName);
 
+  struct MapperAllocas {
+    AllocaInst *ArgsBase = nullptr;
+    AllocaInst *Args = nullptr;
+    AllocaInst *ArgSizes = nullptr;
+  };
+
+  /// Create the allocas instruction used in call to mapper functions.
+  void createMapperAllocas(const LocationDescription &Loc,
+                           InsertPointTy AllocaIP, unsigned NumOperands,
+                           struct MapperAllocas &MapperAllocas);
+
+  /// Create the call for the target mapper function.
+  /// \param Loc The source location description.
+  /// \param MapperFunc Function to be called.
+  /// \param SrcLocInfo Source location information global.
+  /// \param MaptypesArgs
+  /// \param MapnamesArg
+  /// \param MapperAllocas The AllocaInst used for the call.
+  /// \param DeviceID Device ID for the call.
+  /// \param TotalNbOperand Number of operand in the call.
+  void emitMapperCall(const LocationDescription &Loc, Function *MapperFunc,
+                      Value *SrcLocInfo, Value *MaptypesArg, Value *MapnamesArg,
+                      struct MapperAllocas &MapperAllocas, int64_t DeviceID,
+                      unsigned NumOperands);
+
 public:
   /// Generator for __kmpc_copyprivate
   ///

diff  --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index 60d71805c758f..76954f9a37e18 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -2318,6 +2318,51 @@ OpenMPIRBuilder::createOffloadMaptypes(SmallVectorImpl<uint64_t> &Mappings,
   return MaptypesArrayGlobal;
 }
 
+void OpenMPIRBuilder::createMapperAllocas(const LocationDescription &Loc,
+                                          InsertPointTy AllocaIP,
+                                          unsigned NumOperands,
+                                          struct MapperAllocas &MapperAllocas) {
+  if (!updateToLocation(Loc))
+    return;
+
+  auto *ArrI8PtrTy = ArrayType::get(Int8Ptr, NumOperands);
+  auto *ArrI64Ty = ArrayType::get(Int64, NumOperands);
+  Builder.restoreIP(AllocaIP);
+  AllocaInst *ArgsBase = Builder.CreateAlloca(ArrI8PtrTy);
+  AllocaInst *Args = Builder.CreateAlloca(ArrI8PtrTy);
+  AllocaInst *ArgSizes = Builder.CreateAlloca(ArrI64Ty);
+  Builder.restoreIP(Loc.IP);
+  MapperAllocas.ArgsBase = ArgsBase;
+  MapperAllocas.Args = Args;
+  MapperAllocas.ArgSizes = ArgSizes;
+}
+
+void OpenMPIRBuilder::emitMapperCall(const LocationDescription &Loc,
+                                     Function *MapperFunc, Value *SrcLocInfo,
+                                     Value *MaptypesArg, Value *MapnamesArg,
+                                     struct MapperAllocas &MapperAllocas,
+                                     int64_t DeviceID, unsigned NumOperands) {
+  if (!updateToLocation(Loc))
+    return;
+
+  auto *ArrI8PtrTy = ArrayType::get(Int8Ptr, NumOperands);
+  auto *ArrI64Ty = ArrayType::get(Int64, NumOperands);
+  Value *ArgsBaseGEP =
+      Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.ArgsBase,
+                                {Builder.getInt32(0), Builder.getInt32(0)});
+  Value *ArgsGEP =
+      Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.Args,
+                                {Builder.getInt32(0), Builder.getInt32(0)});
+  Value *ArgSizesGEP =
+      Builder.CreateInBoundsGEP(ArrI64Ty, MapperAllocas.ArgSizes,
+                                {Builder.getInt32(0), Builder.getInt32(0)});
+  Value *NullPtr = Constant::getNullValue(Int8Ptr->getPointerTo());
+  Builder.CreateCall(MapperFunc,
+                     {SrcLocInfo, Builder.getInt64(DeviceID),
+                      Builder.getInt32(NumOperands), ArgsBaseGEP, ArgsGEP,
+                      ArgSizesGEP, MaptypesArg, MapnamesArg, NullPtr});
+}
+
 bool OpenMPIRBuilder::checkAndEmitFlushAfterAtomic(
     const LocationDescription &Loc, llvm::AtomicOrdering AO, AtomicKind AK) {
   assert(!(AO == AtomicOrdering::NotAtomic ||

diff  --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
index 0df6fe531e3c1..50887611eaf17 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -2703,4 +2703,110 @@ TEST_F(OpenMPIRBuilderTest, CreateOffloadMapnames) {
   EXPECT_EQ(Initializer->getType()->getArrayNumElements(), Names.size());
 }
 
+TEST_F(OpenMPIRBuilderTest, CreateMapperAllocas) {
+  OpenMPIRBuilder OMPBuilder(*M);
+  OMPBuilder.initialize();
+  F->setName("func");
+  IRBuilder<> Builder(BB);
+
+  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
+
+  unsigned TotalNbOperand = 2;
+
+  OpenMPIRBuilder::MapperAllocas MapperAllocas;
+  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),
+                                    F->getEntryBlock().getFirstInsertionPt());
+  OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas);
+  EXPECT_NE(MapperAllocas.ArgsBase, nullptr);
+  EXPECT_NE(MapperAllocas.Args, nullptr);
+  EXPECT_NE(MapperAllocas.ArgSizes, nullptr);
+  EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()->isArrayTy());
+  ArrayType *ArrType =
+      dyn_cast<ArrayType>(MapperAllocas.ArgsBase->getAllocatedType());
+  EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand);
+  EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()
+                  ->getArrayElementType()
+                  ->isPointerTy());
+  EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()
+                  ->getArrayElementType()
+                  ->getPointerElementType()
+                  ->isIntegerTy(8));
+
+  EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()->isArrayTy());
+  ArrType = dyn_cast<ArrayType>(MapperAllocas.Args->getAllocatedType());
+  EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand);
+  EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()
+                  ->getArrayElementType()
+                  ->isPointerTy());
+  EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()
+                  ->getArrayElementType()
+                  ->getPointerElementType()
+                  ->isIntegerTy(8));
+
+  EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType()->isArrayTy());
+  ArrType = dyn_cast<ArrayType>(MapperAllocas.ArgSizes->getAllocatedType());
+  EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand);
+  EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType()
+                  ->getArrayElementType()
+                  ->isIntegerTy(64));
+}
+
+TEST_F(OpenMPIRBuilderTest, EmitMapperCall) {
+  OpenMPIRBuilder OMPBuilder(*M);
+  OMPBuilder.initialize();
+  F->setName("func");
+  IRBuilder<> Builder(BB);
+  LLVMContext &Ctx = M->getContext();
+
+  OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
+
+  unsigned TotalNbOperand = 2;
+
+  OpenMPIRBuilder::MapperAllocas MapperAllocas;
+  IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(),
+                                    F->getEntryBlock().getFirstInsertionPt());
+  OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas);
+
+  auto *BeginMapperFunc = OMPBuilder.getOrCreateRuntimeFunctionPtr(
+      omp::OMPRTL___tgt_target_data_begin_mapper);
+
+  SmallVector<uint64_t> Flags = {0, 2};
+
+  Constant *SrcLocCst = OMPBuilder.getOrCreateSrcLocStr("", "file1", 2, 5);
+  Value *SrcLocInfo = OMPBuilder.getOrCreateIdent(SrcLocCst);
+
+  Constant *Cst1 = OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5);
+  Constant *Cst2 = OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5);
+  SmallVector<llvm::Constant *> Names = {Cst1, Cst2};
+
+  GlobalVariable *Maptypes =
+      OMPBuilder.createOffloadMaptypes(Flags, ".offload_maptypes");
+  Value *MaptypesArg = Builder.CreateConstInBoundsGEP2_32(
+      ArrayType::get(Type::getInt64Ty(Ctx), TotalNbOperand), Maptypes,
+      /*Idx0=*/0, /*Idx1=*/0);
+
+  GlobalVariable *Mapnames =
+      OMPBuilder.createOffloadMapnames(Names, ".offload_mapnames");
+  Value *MapnamesArg = Builder.CreateConstInBoundsGEP2_32(
+      ArrayType::get(Type::getInt8PtrTy(Ctx), TotalNbOperand), Mapnames,
+      /*Idx0=*/0, /*Idx1=*/0);
+
+  OMPBuilder.emitMapperCall(Builder.saveIP(), BeginMapperFunc, SrcLocInfo,
+                            MaptypesArg, MapnamesArg, MapperAllocas, -1,
+                            TotalNbOperand);
+
+  CallInst *MapperCall = dyn_cast<CallInst>(&BB->back());
+  EXPECT_NE(MapperCall, nullptr);
+  EXPECT_EQ(MapperCall->getNumArgOperands(), 9U);
+  EXPECT_EQ(MapperCall->getCalledFunction()->getName(),
+            "__tgt_target_data_begin_mapper");
+  EXPECT_EQ(MapperCall->getOperand(0), SrcLocInfo);
+  EXPECT_TRUE(MapperCall->getOperand(1)->getType()->isIntegerTy(64));
+  EXPECT_TRUE(MapperCall->getOperand(2)->getType()->isIntegerTy(32));
+
+  EXPECT_EQ(MapperCall->getOperand(6), MaptypesArg);
+  EXPECT_EQ(MapperCall->getOperand(7), MapnamesArg);
+  EXPECT_TRUE(MapperCall->getOperand(8)->getType()->isPointerTy());
+}
+
 } // namespace

diff  --git a/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp
index 4fbd051b65390..2900a095e3dbe 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp
@@ -32,14 +32,14 @@ using OpenACCIRBuilder = llvm::OpenMPIRBuilder;
 // Utility functions
 //===----------------------------------------------------------------------===//
 
-/// 0 = alloc/create
-static constexpr uint64_t kCreateFlag = 0;
-/// 1 = to/device/copyin
-static constexpr uint64_t kDeviceCopyinFlag = 1;
-/// 2 = from/copyout
-static constexpr uint64_t kHostCopyoutFlag = 2;
-/// 8 = delete
-static constexpr uint64_t kDeleteFlag = 8;
+/// Flag values are extracted from openmp/libomptarget/include/omptarget.h and
+/// mapped to corresponding OpenACC flags.
+static constexpr uint64_t kCreateFlag = 0x000;
+static constexpr uint64_t kDeviceCopyinFlag = 0x001;
+static constexpr uint64_t kHostCopyoutFlag = 0x002;
+static constexpr uint64_t kCopyFlag = kDeviceCopyinFlag | kHostCopyoutFlag;
+static constexpr uint64_t kPresentFlag = 0x1000;
+static constexpr uint64_t kDeleteFlag = 0x008;
 
 /// Default value for the device id
 static constexpr int64_t kDefaultDevice = -1;
@@ -123,9 +123,8 @@ processOperands(llvm::IRBuilderBase &builder,
                 LLVM::ModuleTranslation &moduleTranslation, Operation *op,
                 ValueRange operands, unsigned totalNbOperand,
                 uint64_t operandFlag, SmallVector<uint64_t> &flags,
-                SmallVector<llvm::Constant *> &names, unsigned &index,
-                llvm::AllocaInst *argsBase, llvm::AllocaInst *args,
-                llvm::AllocaInst *argSizes) {
+                SmallVectorImpl<llvm::Constant *> &names, unsigned &index,
+                struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
   OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
   llvm::LLVMContext &ctx = builder.getContext();
   auto *i8PtrTy = llvm::Type::getInt8PtrTy(ctx);
@@ -160,21 +159,24 @@ processOperands(llvm::IRBuilderBase &builder,
     // Store base pointer extracted from operand into the i-th position of
     // argBase.
     llvm::Value *ptrBaseGEP = builder.CreateInBoundsGEP(
-        arrI8PtrTy, argsBase, {builder.getInt32(0), builder.getInt32(index)});
+        arrI8PtrTy, mapperAllocas.ArgsBase,
+        {builder.getInt32(0), builder.getInt32(index)});
     llvm::Value *ptrBaseCast = builder.CreateBitCast(
         ptrBaseGEP, dataPtrBase->getType()->getPointerTo());
     builder.CreateStore(dataPtrBase, ptrBaseCast);
 
     // Store pointer extracted from operand into the i-th position of args.
     llvm::Value *ptrGEP = builder.CreateInBoundsGEP(
-        arrI8PtrTy, args, {builder.getInt32(0), builder.getInt32(index)});
+        arrI8PtrTy, mapperAllocas.Args,
+        {builder.getInt32(0), builder.getInt32(index)});
     llvm::Value *ptrCast =
         builder.CreateBitCast(ptrGEP, dataPtr->getType()->getPointerTo());
     builder.CreateStore(dataPtr, ptrCast);
 
     // Store size extracted from operand into the i-th position of argSizes.
     llvm::Value *sizeGEP = builder.CreateInBoundsGEP(
-        arrI64Ty, argSizes, {builder.getInt32(0), builder.getInt32(index)});
+        arrI64Ty, mapperAllocas.ArgSizes,
+        {builder.getInt32(0), builder.getInt32(index)});
     builder.CreateStore(dataSize, sizeGEP);
 
     flags.push_back(operandFlag);
@@ -187,11 +189,12 @@ processOperands(llvm::IRBuilderBase &builder,
 }
 
 /// Process data operands from acc::EnterDataOp
-static LogicalResult processDataOperands(
-    llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation,
-    acc::EnterDataOp op, SmallVector<uint64_t> &flags,
-    SmallVector<llvm::Constant *> &names, llvm::AllocaInst *argsBase,
-    llvm::AllocaInst *args, llvm::AllocaInst *argSizes) {
+static LogicalResult
+processDataOperands(llvm::IRBuilderBase &builder,
+                    LLVM::ModuleTranslation &moduleTranslation,
+                    acc::EnterDataOp op, SmallVector<uint64_t> &flags,
+                    SmallVectorImpl<llvm::Constant *> &names,
+                    struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
   // TODO add `create_zero` and `attach` operands
 
   unsigned index = 0;
@@ -199,26 +202,26 @@ static LogicalResult processDataOperands(
   // Create operands are handled as `alloc` call.
   if (failed(processOperands(builder, moduleTranslation, op,
                              op.createOperands(), op.getNumDataOperands(),
-                             kCreateFlag, flags, names, index, argsBase, args,
-                             argSizes)))
+                             kCreateFlag, flags, names, index, mapperAllocas)))
     return failure();
 
   // Copyin operands are handled as `to` call.
   if (failed(processOperands(builder, moduleTranslation, op,
                              op.copyinOperands(), op.getNumDataOperands(),
-                             kDeviceCopyinFlag, flags, names, index, argsBase,
-                             args, argSizes)))
+                             kDeviceCopyinFlag, flags, names, index,
+                             mapperAllocas)))
     return failure();
 
   return success();
 }
 
 /// Process data operands from acc::ExitDataOp
-static LogicalResult processDataOperands(
-    llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation,
-    acc::ExitDataOp op, SmallVector<uint64_t> &flags,
-    SmallVector<llvm::Constant *> &names, llvm::AllocaInst *argsBase,
-    llvm::AllocaInst *args, llvm::AllocaInst *argSizes) {
+static LogicalResult
+processDataOperands(llvm::IRBuilderBase &builder,
+                    LLVM::ModuleTranslation &moduleTranslation,
+                    acc::ExitDataOp op, SmallVector<uint64_t> &flags,
+                    SmallVectorImpl<llvm::Constant *> &names,
+                    struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
   // TODO add `detach` operands
 
   unsigned index = 0;
@@ -226,39 +229,39 @@ static LogicalResult processDataOperands(
   // Delete operands are handled as `delete` call.
   if (failed(processOperands(builder, moduleTranslation, op,
                              op.deleteOperands(), op.getNumDataOperands(),
-                             kDeleteFlag, flags, names, index, argsBase, args,
-                             argSizes)))
+                             kDeleteFlag, flags, names, index, mapperAllocas)))
     return failure();
 
   // Copyout operands are handled as `from` call.
   if (failed(processOperands(builder, moduleTranslation, op,
                              op.copyoutOperands(), op.getNumDataOperands(),
-                             kHostCopyoutFlag, flags, names, index, argsBase,
-                             args, argSizes)))
+                             kHostCopyoutFlag, flags, names, index,
+                             mapperAllocas)))
     return failure();
 
   return success();
 }
 
 /// Process data operands from acc::UpdateOp
-static LogicalResult processDataOperands(
-    llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation,
-    acc::UpdateOp op, SmallVector<uint64_t> &flags,
-    SmallVector<llvm::Constant *> &names, llvm::AllocaInst *argsBase,
-    llvm::AllocaInst *args, llvm::AllocaInst *argSizes) {
+static LogicalResult
+processDataOperands(llvm::IRBuilderBase &builder,
+                    LLVM::ModuleTranslation &moduleTranslation,
+                    acc::UpdateOp op, SmallVector<uint64_t> &flags,
+                    SmallVectorImpl<llvm::Constant *> &names,
+                    struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
   unsigned index = 0;
 
   // Host operands are handled as `from` call.
   if (failed(processOperands(builder, moduleTranslation, op, op.hostOperands(),
                              op.getNumDataOperands(), kHostCopyoutFlag, flags,
-                             names, index, argsBase, args, argSizes)))
+                             names, index, mapperAllocas)))
     return failure();
 
   // Device operands are handled as `to` call.
   if (failed(processOperands(builder, moduleTranslation, op,
                              op.deviceOperands(), op.getNumDataOperands(),
-                             kDeviceCopyinFlag, flags, names, index, argsBase,
-                             args, argSizes)))
+                             kDeviceCopyinFlag, flags, names, index,
+                             mapperAllocas)))
     return failure();
 
   return success();
@@ -268,6 +271,153 @@ static LogicalResult processDataOperands(
 // Conversion functions
 //===----------------------------------------------------------------------===//
 
+/// Converts an OpenACC data operation into LLVM IR.
+static LogicalResult convertDataOp(acc::DataOp &op,
+                                   llvm::IRBuilderBase &builder,
+                                   LLVM::ModuleTranslation &moduleTranslation) {
+  llvm::LLVMContext &ctx = builder.getContext();
+  auto enclosingFuncOp = op.getOperation()->getParentOfType<LLVM::LLVMFuncOp>();
+  llvm::Function *enclosingFunction =
+      moduleTranslation.lookupFunction(enclosingFuncOp.getName());
+
+  OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
+
+  llvm::Value *srcLocInfo = createSourceLocationInfo(*accBuilder, op);
+
+  llvm::Function *beginMapperFunc = accBuilder->getOrCreateRuntimeFunctionPtr(
+      llvm::omp::OMPRTL___tgt_target_data_begin_mapper);
+
+  llvm::Function *endMapperFunc = accBuilder->getOrCreateRuntimeFunctionPtr(
+      llvm::omp::OMPRTL___tgt_target_data_end_mapper);
+
+  // Number of arguments in the data operation.
+  unsigned totalNbOperand = op.getNumDataOperands();
+
+  struct OpenACCIRBuilder::MapperAllocas mapperAllocas;
+  OpenACCIRBuilder::InsertPointTy allocaIP(
+      &enclosingFunction->getEntryBlock(),
+      enclosingFunction->getEntryBlock().getFirstInsertionPt());
+  accBuilder->createMapperAllocas(builder.saveIP(), allocaIP, totalNbOperand,
+                                  mapperAllocas);
+
+  SmallVector<uint64_t> flags;
+  SmallVector<llvm::Constant *> names;
+  unsigned index = 0;
+
+  // TODO handle no_create, deviceptr and attach operands.
+
+  if (failed(processOperands(builder, moduleTranslation, op, op.copyOperands(),
+                             totalNbOperand, kCopyFlag, flags, names, index,
+                             mapperAllocas)))
+    return failure();
+
+  if (failed(processOperands(
+          builder, moduleTranslation, op, op.copyinOperands(), totalNbOperand,
+          kDeviceCopyinFlag, flags, names, index, mapperAllocas)))
+    return failure();
+
+  // TODO copyin readonly currenlty handled as copyin. Update when extension
+  // available.
+  if (failed(processOperands(builder, moduleTranslation, op,
+                             op.copyinReadonlyOperands(), totalNbOperand,
+                             kDeviceCopyinFlag, flags, names, index,
+                             mapperAllocas)))
+    return failure();
+
+  if (failed(processOperands(
+          builder, moduleTranslation, op, op.copyoutOperands(), totalNbOperand,
+          kHostCopyoutFlag, flags, names, index, mapperAllocas)))
+    return failure();
+
+  // TODO copyout zero currenlty handled as copyout. Update when extension
+  // available.
+  if (failed(processOperands(builder, moduleTranslation, op,
+                             op.copyoutZeroOperands(), totalNbOperand,
+                             kHostCopyoutFlag, flags, names, index,
+                             mapperAllocas)))
+    return failure();
+
+  if (failed(processOperands(builder, moduleTranslation, op,
+                             op.createOperands(), totalNbOperand, kCreateFlag,
+                             flags, names, index, mapperAllocas)))
+    return failure();
+
+  // TODO create zero currenlty handled as create. Update when extension
+  // available.
+  if (failed(processOperands(builder, moduleTranslation, op,
+                             op.createZeroOperands(), totalNbOperand,
+                             kCreateFlag, flags, names, index, mapperAllocas)))
+    return failure();
+
+  if (failed(processOperands(builder, moduleTranslation, op,
+                             op.presentOperands(), totalNbOperand, kPresentFlag,
+                             flags, names, index, mapperAllocas)))
+    return failure();
+
+  llvm::GlobalVariable *maptypes =
+      accBuilder->createOffloadMaptypes(flags, ".offload_maptypes");
+  llvm::Value *maptypesArg = builder.CreateConstInBoundsGEP2_32(
+      llvm::ArrayType::get(llvm::Type::getInt64Ty(ctx), totalNbOperand),
+      maptypes, /*Idx0=*/0, /*Idx1=*/0);
+
+  llvm::GlobalVariable *mapnames =
+      accBuilder->createOffloadMapnames(names, ".offload_mapnames");
+  llvm::Value *mapnamesArg = builder.CreateConstInBoundsGEP2_32(
+      llvm::ArrayType::get(llvm::Type::getInt8PtrTy(ctx), totalNbOperand),
+      mapnames, /*Idx0=*/0, /*Idx1=*/0);
+
+  // Create call to start the data region.
+  accBuilder->emitMapperCall(builder.saveIP(), beginMapperFunc, srcLocInfo,
+                             maptypesArg, mapnamesArg, mapperAllocas,
+                             kDefaultDevice, totalNbOperand);
+
+  // Convert the region.
+  llvm::BasicBlock *entryBlock = nullptr;
+
+  for (Block &bb : op.region()) {
+    llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create(
+        ctx, "acc.data", builder.GetInsertBlock()->getParent());
+    if (entryBlock == nullptr)
+      entryBlock = llvmBB;
+    moduleTranslation.mapBlock(&bb, llvmBB);
+  }
+
+  auto afterDataRegion = builder.saveIP();
+
+  llvm::BranchInst *sourceTerminator = builder.CreateBr(entryBlock);
+
+  builder.restoreIP(afterDataRegion);
+  llvm::BasicBlock *endDataBlock = llvm::BasicBlock::Create(
+      ctx, "acc.end_data", builder.GetInsertBlock()->getParent());
+
+  SetVector<Block *> blocks =
+      LLVM::detail::getTopologicallySortedBlocks(op.region());
+  for (Block *bb : blocks) {
+    llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(bb);
+    if (bb->isEntryBlock()) {
+      assert(sourceTerminator->getNumSuccessors() == 1 &&
+             "provided entry block has multiple successors");
+      sourceTerminator->setSuccessor(0, llvmBB);
+    }
+
+    if (failed(
+            moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) {
+      return failure();
+    }
+
+    if (isa<acc::TerminatorOp, acc::YieldOp>(bb->getTerminator()))
+      builder.CreateBr(endDataBlock);
+  }
+
+  // Create call to end the data region.
+  builder.SetInsertPoint(endDataBlock);
+  accBuilder->emitMapperCall(builder.saveIP(), endMapperFunc, srcLocInfo,
+                             maptypesArg, mapnamesArg, mapperAllocas,
+                             kDefaultDevice, totalNbOperand);
+
+  return success();
+}
+
 /// Converts an OpenACC standalone data operation into LLVM IR.
 template <typename OpTy>
 static LogicalResult
@@ -286,27 +436,20 @@ convertStandaloneDataOp(OpTy &op, llvm::IRBuilderBase &builder,
   // Number of arguments in the enter_data operation.
   unsigned totalNbOperand = op.getNumDataOperands();
 
-  // TODO could be moved to OpenXXIRBuilder?
   llvm::LLVMContext &ctx = builder.getContext();
-  auto *i8PtrTy = llvm::Type::getInt8PtrTy(ctx);
-  auto *arrI8PtrTy = llvm::ArrayType::get(i8PtrTy, totalNbOperand);
-  auto *i64Ty = llvm::Type::getInt64Ty(ctx);
-  auto *arrI64Ty = llvm::ArrayType::get(i64Ty, totalNbOperand);
-  llvm::IRBuilder<>::InsertPoint allocaIP(
+
+  struct OpenACCIRBuilder::MapperAllocas mapperAllocas;
+  OpenACCIRBuilder::InsertPointTy allocaIP(
       &enclosingFunction->getEntryBlock(),
       enclosingFunction->getEntryBlock().getFirstInsertionPt());
-  llvm::IRBuilder<>::InsertPoint currentIP = builder.saveIP();
-  builder.restoreIP(allocaIP);
-  llvm::AllocaInst *argsBase = builder.CreateAlloca(arrI8PtrTy);
-  llvm::AllocaInst *args = builder.CreateAlloca(arrI8PtrTy);
-  llvm::AllocaInst *argSizes = builder.CreateAlloca(arrI64Ty);
-  builder.restoreIP(currentIP);
+  accBuilder->createMapperAllocas(builder.saveIP(), allocaIP, totalNbOperand,
+                                  mapperAllocas);
 
   SmallVector<uint64_t> flags;
   SmallVector<llvm::Constant *> names;
 
   if (failed(processDataOperands(builder, moduleTranslation, op, flags, names,
-                                 argsBase, args, argSizes)))
+                                 mapperAllocas)))
     return failure();
 
   llvm::GlobalVariable *maptypes =
@@ -321,19 +464,9 @@ convertStandaloneDataOp(OpTy &op, llvm::IRBuilderBase &builder,
       llvm::ArrayType::get(llvm::Type::getInt8PtrTy(ctx), totalNbOperand),
       mapnames, /*Idx0=*/0, /*Idx1=*/0);
 
-  llvm::Value *argsBaseGEP = builder.CreateInBoundsGEP(
-      arrI8PtrTy, argsBase, {builder.getInt32(0), builder.getInt32(0)});
-  llvm::Value *argsGEP = builder.CreateInBoundsGEP(
-      arrI8PtrTy, args, {builder.getInt32(0), builder.getInt32(0)});
-  llvm::Value *argSizesGEP = builder.CreateInBoundsGEP(
-      arrI64Ty, argSizes, {builder.getInt32(0), builder.getInt32(0)});
-  llvm::Value *nullPtr = llvm::Constant::getNullValue(
-      llvm::Type::getInt8PtrTy(ctx)->getPointerTo());
-
-  builder.CreateCall(mapperFunc,
-                     {srcLocInfo, builder.getInt64(kDefaultDevice),
-                      builder.getInt32(totalNbOperand), argsBaseGEP, argsGEP,
-                      argSizesGEP, maptypesArg, mapnamesArg, nullPtr});
+  accBuilder->emitMapperCall(builder.saveIP(), mapperFunc, srcLocInfo,
+                             maptypesArg, mapnamesArg, mapperAllocas,
+                             kDefaultDevice, totalNbOperand);
 
   return success();
 }
@@ -363,6 +496,9 @@ LogicalResult OpenACCDialectLLVMIRTranslationInterface::convertOperation(
     LLVM::ModuleTranslation &moduleTranslation) const {
 
   return llvm::TypeSwitch<Operation *, LogicalResult>(op)
+      .Case([&](acc::DataOp dataOp) {
+        return convertDataOp(dataOp, builder, moduleTranslation);
+      })
       .Case([&](acc::EnterDataOp enterDataOp) {
         return convertStandaloneDataOp<acc::EnterDataOp>(enterDataOp, builder,
                                                          moduleTranslation);
@@ -375,6 +511,13 @@ LogicalResult OpenACCDialectLLVMIRTranslationInterface::convertOperation(
         return convertStandaloneDataOp<acc::UpdateOp>(updateOp, builder,
                                                       moduleTranslation);
       })
+      .Case<acc::TerminatorOp, acc::YieldOp>([](auto op) {
+        // `yield` and `terminator` can be just omitted. The block structure was
+        // created in the function that handles their parent operation.
+        assert(op->getNumOperands() == 0 &&
+               "unexpected OpenACC terminator with operands");
+        return success();
+      })
       .Default([&](Operation *op) {
         return op->emitError("unsupported OpenACC operation: ")
                << op->getName();

diff  --git a/mlir/test/Target/LLVMIR/openacc-llvm.mlir b/mlir/test/Target/LLVMIR/openacc-llvm.mlir
index 52656f9705bc2..f0fb7ff82c9bd 100644
--- a/mlir/test/Target/LLVMIR/openacc-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openacc-llvm.mlir
@@ -182,3 +182,76 @@ llvm.func @testupdateop(%arg0: !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x
 // CHECK: call void @__tgt_target_data_update_mapper(%struct.ident_t* [[LOCGLOBAL]], i64 -1, i32 2, i8** [[ARGBASE_ALLOCA_GEP]], i8** [[ARG_ALLOCA_GEP]], i64* [[SIZE_ALLOCA_GEP]], i64* getelementptr inbounds ([{{[0-9]*}} x i64], [{{[0-9]*}} x i64]* [[MAPTYPES]], i32 0, i32 0), i8** getelementptr inbounds ([{{[0-9]*}} x i8*], [{{[0-9]*}} x i8*]* [[MAPNAMES]], i32 0, i32 0), i8** null)
 
 // CHECK: declare void @__tgt_target_data_update_mapper(%struct.ident_t*, i64, i32, i8**, i8**, i64*, i64*, i8**, i8**) #0
+
+// -----
+
+llvm.func @testdataop(%arg0: !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, %arg1: !llvm.ptr<f32>, %arg2: !llvm.ptr<i32>) {
+  %0 = llvm.mlir.constant(10 : index) : i64
+  %1 = llvm.mlir.null : !llvm.ptr<f32>
+  %2 = llvm.getelementptr %1[%0] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
+  %3 = llvm.ptrtoint %2 : !llvm.ptr<f32> to i64
+  %4 = llvm.extractvalue %arg0[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>
+  %5 = llvm.mlir.undef : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
+  %6 = llvm.insertvalue %arg0, %5[0] : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
+  %7 = llvm.insertvalue %4, %6[1] : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
+  %8 = llvm.insertvalue %3, %7[2] : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
+  acc.data copy(%8 : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>) copyout(%arg1 : !llvm.ptr<f32>) {
+    %9 = llvm.mlir.constant(2 : i32) : i32
+    llvm.store %9, %arg2 : !llvm.ptr<i32>
+    acc.terminator
+  }
+  llvm.return
+}
+
+// CHECK: %struct.ident_t = type { i32, i32, i32, i32, i8* }
+// CHECK: [[LOCSTR:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};testdataop;{{[0-9]*}};{{[0-9]*}};;\00", align 1
+// CHECK: [[LOCGLOBAL:@.*]] = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([{{[0-9]*}} x i8], [{{[0-9]*}} x i8]* [[LOCSTR]], i32 0, i32 0) }, align 8
+// CHECK: [[MAPNAME1:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00", align 1
+// CHECK: [[MAPNAME2:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00", align 1
+// CHECK: [[MAPTYPES:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i64] [i64 3, i64 2]
+// CHECK: [[MAPNAMES:@.*]] = private constant [{{[0-9]*}} x i8*] [i8* getelementptr inbounds ([{{[0-9]*}} x i8], [{{[0-9]*}} x i8]* [[MAPNAME1]], i32 0, i32 0), i8* getelementptr inbounds ([{{[0-9]*}} x i8], [{{[0-9]*}} x i8]* [[MAPNAME2]], i32 0, i32 0)]
+
+// CHECK: define void @testdataop({ float*, float*, i64, [1 x i64], [1 x i64] } %{{.*}}, float* [[SIMPLEPTR:%.*]], i32* %{{.*}})
+// CHECK: [[ARGBASE_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i8*], align 8
+// CHECK: [[ARG_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i8*], align 8
+// CHECK: [[SIZE_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i64], align 8
+
+// CHECK: [[ARGBASE:%.*]] = extractvalue %openacc_data %{{.*}}, 0
+// CHECK: [[ARG:%.*]] = extractvalue %openacc_data %{{.*}}, 1
+// CHECK: [[ARGSIZE:%.*]] = extractvalue %openacc_data %{{.*}}, 2
+// CHECK: [[ARGBASEGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 0
+// CHECK: [[ARGBASEGEPCAST:%.*]] = bitcast i8** [[ARGBASEGEP]] to { float*, float*, i64, [1 x i64], [1 x i64] }*
+// CHECK: store { float*, float*, i64, [1 x i64], [1 x i64] } [[ARGBASE]], { float*, float*, i64, [1 x i64], [1 x i64] }* [[ARGBASEGEPCAST]], align 8
+// CHECK: [[ARGGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 0
+// CHECK: [[ARGGEPCAST:%.*]] = bitcast i8** [[ARGGEP]] to float**
+// CHECK: store float* [[ARG]], float** [[ARGGEPCAST]], align 8
+// CHECK: [[SIZEGEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 0
+// CHECK: store i64 [[ARGSIZE]], i64* [[SIZEGEP]], align 4
+
+// CHECK: [[ARGBASEGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 1
+// CHECK: [[ARGBASEGEPCAST:%.*]] = bitcast i8** [[ARGBASEGEP]] to float**
+// CHECK: store float* [[SIMPLEPTR]], float** [[ARGBASEGEPCAST]], align 8
+// CHECK: [[ARGGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 1
+// CHECK: [[ARGGEPCAST:%.*]] = bitcast i8** [[ARGGEP]] to float**
+// CHECK: store float* [[SIMPLEPTR]], float** [[ARGGEPCAST]], align 8
+// CHECK: [[SIZEGEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 1
+// CHECK: store i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64* [[SIZEGEP]], align 4
+
+// CHECK: [[ARGBASE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 0
+// CHECK: [[ARG_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 0
+// CHECK: [[SIZE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 0
+// CHECK: call void @__tgt_target_data_begin_mapper(%struct.ident_t* [[LOCGLOBAL]], i64 -1, i32 2, i8** [[ARGBASE_ALLOCA_GEP]], i8** [[ARG_ALLOCA_GEP]], i64* [[SIZE_ALLOCA_GEP]], i64* getelementptr inbounds ([{{[0-9]*}} x i64], [{{[0-9]*}} x i64]* [[MAPTYPES]], i32 0, i32 0), i8** getelementptr inbounds ([{{[0-9]*}} x i8*], [{{[0-9]*}} x i8*]* [[MAPNAMES]], i32 0, i32 0), i8** null)
+// CHECK: br label %acc.data
+
+// CHECK:      acc.data:
+// CHECK-NEXT:   store i32 2, i32* %{{.*}}
+// CHECK-NEXT:   br label %acc.end_data
+
+// CHECK: acc.end_data:
+// CHECK:   [[ARGBASE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 0
+// CHECK:   [[ARG_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 0
+// CHECK:   [[SIZE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 0
+// CHECK:   call void @__tgt_target_data_end_mapper(%struct.ident_t* [[LOCGLOBAL]], i64 -1, i32 2, i8** [[ARGBASE_ALLOCA_GEP]], i8** [[ARG_ALLOCA_GEP]], i64* [[SIZE_ALLOCA_GEP]], i64* getelementptr inbounds ([{{[0-9]*}} x i64], [{{[0-9]*}} x i64]* [[MAPTYPES]], i32 0, i32 0), i8** getelementptr inbounds ([{{[0-9]*}} x i8*], [{{[0-9]*}} x i8*]* [[MAPNAMES]], i32 0, i32 0), i8** null)
+
+// CHECK: declare void @__tgt_target_data_begin_mapper(%struct.ident_t*, i64, i32, i8**, i8**, i64*, i64*, i8**, i8**)
+// CHECK: declare void @__tgt_target_data_end_mapper(%struct.ident_t*, i64, i32, i8**, i8**, i64*, i64*, i8**, i8**)


        


More information about the llvm-commits mailing list