diff --git a/mlir/include/mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h b/mlir/include/mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h
new file mode 100644
--- /dev/null
+++ b/mlir/include/mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h
@@ -0,0 +1,49 @@
+//===- ConvertOpenACCToLLVM.h - OpenACC conversion pass entrypoint --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef MLIR_CONVERSION_OPENACCTOLLVM_CONVERTOPENACCTOLLVMPASS_H_
+#define MLIR_CONVERSION_OPENACCTOLLVM_CONVERTOPENACCTOLLVMPASS_H_
+
+#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
+#include <memory>
+
+namespace mlir {
+class LLVMTypeConverter;
+class ModuleOp;
+template <typename T>
+class OperationPass;
+class RewritePatternSet;
+
+static constexpr unsigned kPtrBasePosInDataDescriptor = 0;
+static constexpr unsigned kPtrPosInDataDescriptor = 1;
+static constexpr unsigned kSizePosInDataDescriptor = 2;
+
+class DataDescriptor : public StructBuilder {
+public:
+  /// Construct a helper for the given descriptor value.
+  explicit DataDescriptor(Value descriptor);
+  /// Builds IR creating an `undef` value of the descriptor type.
+  static DataDescriptor undef(OpBuilder &builder, Location loc, Type basePtrTy,
+                              Type ptrTy);
+
+  static bool isValid(Value descriptor);
+
+  void setPointer(OpBuilder &builder, Location loc, Value ptr);
+  void setBasePointer(OpBuilder &builder, Location loc, Value basePtr);
+  void setSize(OpBuilder &builder, Location loc, Value size);
+};
+
+/// Collect the patterns to convert from the OpenACC dialect LLVMIR dialect.
+void populateOpenACCToLLVMConversionPatterns(LLVMTypeConverter &converter,
+                                             RewritePatternSet &patterns);
+
+/// Create a pass to convert the OpenACC dialect into the LLVMIR dialect.
+std::unique_ptr<OperationPass<ModuleOp>> createConvertOpenACCToLLVMPass();
+
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_OPENACCTOLLVM_CONVERTOPENACCTOLLVMPASS_H_
diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h
--- a/mlir/include/mlir/Conversion/Passes.h
+++ b/mlir/include/mlir/Conversion/Passes.h
@@ -22,6 +22,7 @@
 #include "mlir/Conversion/LinalgToSPIRV/LinalgToSPIRVPass.h"
 #include "mlir/Conversion/LinalgToStandard/LinalgToStandard.h"
 #include "mlir/Conversion/MathToLibm/MathToLibm.h"
+#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h"
 #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
 #include "mlir/Conversion/PDLToPDLInterp/PDLToPDLInterp.h"
 #include "mlir/Conversion/SCFToGPU/SCFToGPUPass.h"
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -255,6 +255,16 @@
   let dependentDialects = ["StandardOpsDialect", "vector::VectorDialect"];
 }
 
+//===----------------------------------------------------------------------===//
+// OpenACCToLLVM
+//===----------------------------------------------------------------------===//
+
+def ConvertOpenACCToLLVM : Pass<"convert-openacc-to-llvm", "ModuleOp"> {
+  let summary = "Convert the OpenACC ops to LLVM dialect";
+  let constructor = "mlir::createConvertOpenACCToLLVMPass()";
+  let dependentDialects = ["LLVM::LLVMDialect"];
+}
+
 //===----------------------------------------------------------------------===//
 // OpenMPToLLVM
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -249,6 +249,14 @@
                        Variadic<AnyType>:$createZeroOperands,
                        Variadic<AnyType>:$attachOperands);
 
+  let extraClassDeclaration = [{
+    /// The number of data operands.
+    unsigned getNumDataOperands();
+
+    /// The i-th operand data passed.
+    Value getDataOperand(unsigned i);
+  }];
+
   let assemblyFormat = [{
     ( `if` `(` $ifCond^ `)` )?
     ( `async` `(` $asyncOperand^ `:` type($asyncOperand) `)` )?
@@ -291,6 +299,14 @@
                        Variadic<AnyType>:$detachOperands,
                        UnitAttr:$finalize);
 
+  let extraClassDeclaration = [{
+    /// The number of data operands.
+    unsigned getNumDataOperands();
+
+    /// The i-th operand data passed.
+    Value getDataOperand(unsigned i);
+  }];
+
   let assemblyFormat = [{
     ( `if` `(` $ifCond^ `)` )?
     ( `async` `(` $asyncOperand^ `:` type($asyncOperand) `)` )?
@@ -480,6 +496,14 @@
                        Variadic<AnyType>:$deviceOperands,
                        UnitAttr:$ifPresent);
 
+  let extraClassDeclaration = [{
+    /// The number of data operands.
+    unsigned getNumDataOperands();
+
+    /// The i-th operand data passed.
+    Value getDataOperand(unsigned i);
+  }];
+
   let assemblyFormat = [{
     ( `if` `(` $ifCond^ `)` )?
     ( `async` `(` $asyncOperand^ `:` type($asyncOperand) `)` )?
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -11,6 +11,7 @@
 add_subdirectory(LinalgToSPIRV)
 add_subdirectory(LinalgToStandard)
 add_subdirectory(MathToLibm)
+add_subdirectory(OpenACCToLLVM)
 add_subdirectory(OpenMPToLLVM)
 add_subdirectory(PDLToPDLInterp)
 add_subdirectory(SCFToGPU)
diff --git a/mlir/lib/Conversion/OpenACCToLLVM/CMakeLists.txt b/mlir/lib/Conversion/OpenACCToLLVM/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/mlir/lib/Conversion/OpenACCToLLVM/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_mlir_conversion_library(MLIROpenACCToLLVM
+  OpenACCToLLVM.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/OpenACCToLLVM
+
+  DEPENDS
+  MLIRConversionPassIncGen
+  intrinsics_gen
+
+  LINK_COMPONENTS
+  Core
+
+  LINK_LIBS PUBLIC
+  MLIRIR
+  MLIRLLVMIR
+  MLIROpenACC
+  MLIRStandardToLLVM
+  MLIRTransforms
+  )
diff --git a/mlir/lib/Conversion/OpenACCToLLVM/OpenACCToLLVM.cpp b/mlir/lib/Conversion/OpenACCToLLVM/OpenACCToLLVM.cpp
new file mode 100644
--- /dev/null
+++ b/mlir/lib/Conversion/OpenACCToLLVM/OpenACCToLLVM.cpp
@@ -0,0 +1,189 @@
+//===- OpenACCToLLVM.cpp - Prepare OpenACC data for LLVM translation ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../PassDetail.h"
+#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+// DataDescriptor implementation
+//===----------------------------------------------------------------------===//
+
+constexpr StringRef getStructName() { return "openacc_data"; }
+
+/// Construct a helper for the given descriptor value.
+DataDescriptor::DataDescriptor(Value descriptor) : StructBuilder(descriptor) {
+  assert(value != nullptr && "value cannot be null");
+}
+
+/// Builds IR creating an `undef` value of the data descriptor.
+DataDescriptor DataDescriptor::undef(OpBuilder &builder, Location loc,
+                                     Type basePtrTy, Type ptrTy) {
+  Type descriptorType = LLVM::LLVMStructType::getNewIdentified(
+      builder.getContext(), getStructName(),
+      {basePtrTy, ptrTy, builder.getI64Type()});
+  Value descriptor = builder.create<LLVM::UndefOp>(loc, descriptorType);
+  return DataDescriptor(descriptor);
+}
+
+/// Check whether the type is a valid data descriptor.
+bool DataDescriptor::isValid(Value descriptor) {
+  if (auto type = descriptor.getType().dyn_cast<LLVM::LLVMStructType>()) {
+    if (type.isIdentified() && type.getName().startswith(getStructName()) &&
+        type.getBody().size() == 3 &&
+        type.getBody()[kPtrBasePosInDataDescriptor]
+            .isa<LLVM::LLVMPointerType>() &&
+        type.getBody()[kPtrPosInDataDescriptor].isa<LLVM::LLVMPointerType>() &&
+        type.getBody()[kSizePosInDataDescriptor].isInteger(64))
+      return true;
+  }
+  return false;
+}
+
+/// Builds IR inserting the base pointer value into the descriptor.
+void DataDescriptor::setBasePointer(OpBuilder &builder, Location loc,
+                                    Value basePtr) {
+  setPtr(builder, loc, kPtrBasePosInDataDescriptor, basePtr);
+}
+
+/// Builds IR inserting the pointer value into the descriptor.
+void DataDescriptor::setPointer(OpBuilder &builder, Location loc, Value ptr) {
+  setPtr(builder, loc, kPtrPosInDataDescriptor, ptr);
+}
+
+/// Builds IR inserting the size value into the descriptor.
+void DataDescriptor::setSize(OpBuilder &builder, Location loc, Value size) {
+  setPtr(builder, loc, kSizePosInDataDescriptor, size);
+}
+
+//===----------------------------------------------------------------------===//
+// Conversion patterns
+//===----------------------------------------------------------------------===//
+
+template <typename Op>
+class LegalizeDataOpForLLVMTranslation : public ConvertOpToLLVMPattern<Op> {
+  using ConvertOpToLLVMPattern<Op>::ConvertOpToLLVMPattern;
+
+  LogicalResult
+  matchAndRewrite(Op op, ArrayRef<Value> operands,
+                  ConversionPatternRewriter &builder) const override {
+    Location loc = op.getLoc();
+
+    // Go over the data operand and legalize them for translation.
+    unsigned numDataOperand = op.getNumDataOperands();
+    auto dataOperands = operands.take_back(numDataOperand);
+
+    // Keep the non data operands are kept without modification.
+    auto nonDataOperands =
+        operands.take_front(operands.size() - numDataOperand);
+    SmallVector<Value> convertedOperands;
+    convertedOperands.append(nonDataOperands.begin(), nonDataOperands.end());
+
+    for (auto operand : llvm::enumerate(dataOperands)) {
+      Value data = op.getDataOperand(operand.index());
+
+      // Traverse operands that were converted to MemRefDescriptors.
+      if (auto memRefType = data.getType().dyn_cast<MemRefType>()) {
+        // Calculate the size of the memref and get the pointer to the allocated
+        // buffer.
+        SmallVector<Value, 4> sizes;
+        SmallVector<Value, 4> strides;
+        Value sizeBytes;
+        ConvertToLLVMPattern::getMemRefDescriptorSizes(
+            loc, memRefType, {}, builder, sizes, strides, sizeBytes);
+        MemRefDescriptor descriptor(operand.value());
+        Value dataPtr = descriptor.allocatedPtr(builder, loc);
+        auto ptrType = descriptor.getElementPtrType();
+
+        auto descr = DataDescriptor::undef(builder, loc, ptrType, ptrType);
+        descr.setBasePointer(builder, loc, dataPtr);
+        descr.setPointer(builder, loc, dataPtr);
+        descr.setSize(builder, loc, sizeBytes);
+        convertedOperands.push_back(descr);
+      } else if (data.getType().isa<LLVM::LLVMPointerType>()) {
+        convertedOperands.push_back(data);
+      } else {
+        op.emitError("Unsupported type ") << data.getType();
+      }
+    }
+
+    builder.replaceOpWithNewOp<Op>(op, TypeRange(), convertedOperands,
+                                   op.getOperation()->getAttrs());
+
+    return success();
+  }
+};
+
+void mlir::populateOpenACCToLLVMConversionPatterns(
+    LLVMTypeConverter &converter, OwningRewritePatternList &patterns) {
+  patterns.add<LegalizeDataOpForLLVMTranslation<acc::EnterDataOp>>(converter);
+  patterns.add<LegalizeDataOpForLLVMTranslation<acc::ExitDataOp>>(converter);
+  patterns.add<LegalizeDataOpForLLVMTranslation<acc::UpdateOp>>(converter);
+}
+
+namespace {
+struct ConvertOpenACCToLLVMPass
+    : public ConvertOpenACCToLLVMBase<ConvertOpenACCToLLVMPass> {
+  void runOnOperation() override;
+};
+} // namespace
+
+void ConvertOpenACCToLLVMPass::runOnOperation() {
+  auto op = getOperation();
+  auto *context = op.getContext();
+
+  // Convert to OpenACC operations with LLVM IR dialect
+  RewritePatternSet patterns(context);
+  LLVMTypeConverter converter(context);
+  populateStdToLLVMConversionPatterns(converter, patterns);
+  populateOpenACCToLLVMConversionPatterns(converter, patterns);
+
+  ConversionTarget target(*context);
+  target.addLegalDialect<LLVM::LLVMDialect>();
+
+  auto hasLLVMConvertedDataOperands = [](ValueRange operands) {
+    for (Value operand : operands) {
+      if (!DataDescriptor::isValid(operand) &&
+          !operand.getType().isa<LLVM::LLVMPointerType>())
+        return false;
+    }
+    return true;
+  };
+
+  target.addDynamicallyLegalOp<acc::EnterDataOp>(
+      [hasLLVMConvertedDataOperands](acc::EnterDataOp op) {
+        return hasLLVMConvertedDataOperands(op.copyinOperands()) &&
+               hasLLVMConvertedDataOperands(op.createOperands()) &&
+               hasLLVMConvertedDataOperands(op.createZeroOperands()) &&
+               hasLLVMConvertedDataOperands(op.attachOperands());
+      });
+
+  target.addDynamicallyLegalOp<acc::ExitDataOp>(
+      [hasLLVMConvertedDataOperands](acc::ExitDataOp op) {
+        return hasLLVMConvertedDataOperands(op.copyoutOperands()) &&
+               hasLLVMConvertedDataOperands(op.deleteOperands()) &&
+               hasLLVMConvertedDataOperands(op.detachOperands());
+      });
+
+  target.addDynamicallyLegalOp<acc::UpdateOp>(
+      [hasLLVMConvertedDataOperands](acc::UpdateOp op) {
+        return hasLLVMConvertedDataOperands(op.hostOperands()) &&
+               hasLLVMConvertedDataOperands(op.deviceOperands());
+      });
+
+  if (failed(applyPartialConversion(op, target, std::move(patterns))))
+    signalPassFailure();
+}
+
+std::unique_ptr<OperationPass<ModuleOp>>
+mlir::createConvertOpenACCToLLVMPass() {
+  return std::make_unique<ConvertOpenACCToLLVMPass>();
+}
\ No newline at end of file
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -682,8 +682,20 @@
   return success();
 }
 
+unsigned ExitDataOp::getNumDataOperands() {
+  return copyoutOperands().size() + deleteOperands().size() +
+         detachOperands().size();
+}
+
+Value ExitDataOp::getDataOperand(unsigned i) {
+  unsigned numOptional = ifCond() ? 1 : 0;
+  numOptional += asyncOperand() ? 1 : 0;
+  numOptional += waitDevnum() ? 1 : 0;
+  return getOperand(waitOperands().size() + numOptional + i);
+}
+
 //===----------------------------------------------------------------------===//
-// DataEnterOp
+// EnterDataOp
 //===----------------------------------------------------------------------===//
 
 static LogicalResult verify(acc::EnterDataOp op) {
@@ -712,6 +724,18 @@
   return success();
 }
 
+unsigned EnterDataOp::getNumDataOperands() {
+  return copyinOperands().size() + createOperands().size() +
+         createZeroOperands().size() + attachOperands().size();
+}
+
+Value EnterDataOp::getDataOperand(unsigned i) {
+  unsigned numOptional = ifCond() ? 1 : 0;
+  numOptional += asyncOperand() ? 1 : 0;
+  numOptional += waitDevnum() ? 1 : 0;
+  return getOperand(waitOperands().size() + numOptional + i);
+}
+
 //===----------------------------------------------------------------------===//
 // InitOp
 //===----------------------------------------------------------------------===//
@@ -766,6 +790,18 @@
   return success();
 }
 
+unsigned UpdateOp::getNumDataOperands() {
+  return hostOperands().size() + deviceOperands().size();
+}
+
+Value UpdateOp::getDataOperand(unsigned i) {
+  unsigned numOptional = asyncOperand() ? 1 : 0;
+  numOptional += waitDevnum() ? 1 : 0;
+  numOptional += ifCond() ? 1 : 0;
+  return getOperand(waitOperands().size() + deviceTypeOperands().size() +
+                    numOptional + i);
+}
+
 //===----------------------------------------------------------------------===//
 // WaitOp
 //===----------------------------------------------------------------------===//
diff --git a/mlir/test/Conversion/OpenACCToLLVM/convert-standalone-data-to-llvmir.mlir b/mlir/test/Conversion/OpenACCToLLVM/convert-standalone-data-to-llvmir.mlir
new file mode 100644
--- /dev/null
+++ b/mlir/test/Conversion/OpenACCToLLVM/convert-standalone-data-to-llvmir.mlir
@@ -0,0 +1,110 @@
+// RUN: mlir-opt -convert-openacc-to-llvm -split-input-file %s | FileCheck %s
+
+func @testenterdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
+  acc.enter_data copyin(%b : memref<10xf32>) create(%a : memref<10xf32>)
+  return
+}
+
+// CHECK: acc.enter_data copyin(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) create(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<f32>, ptr<f32>, i64)>)
+
+// -----
+
+func @testenterdataop(%a: !llvm.ptr<f32>, %b: memref<10xf32>) -> () {
+  acc.enter_data copyin(%b : memref<10xf32>) create(%a : !llvm.ptr<f32>)
+  return
+}
+
+// CHECK: acc.enter_data copyin(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) create(%{{.*}} : !llvm.ptr<f32>)
+
+// -----
+
+func @testenterdataop(%a: memref<10xi64>, %b: memref<10xf32>) -> () {
+  acc.enter_data copyin(%b : memref<10xf32>) create_zero(%a : memref<10xi64>) attributes {async}
+  return
+}
+
+// CHECK: acc.enter_data copyin(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) create_zero(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<i64>, ptr<i64>, i64)>) attributes {async}
+
+// -----
+
+func @testenterdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
+  %ifCond = constant true
+  acc.enter_data if(%ifCond) copyin(%b : memref<10xf32>) create(%a : memref<10xf32>)
+  return
+}
+
+// CHECK: acc.enter_data if(%{{.*}}) copyin(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) create(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<f32>, ptr<f32>, i64)>)
+
+// -----
+
+func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
+  acc.exit_data copyout(%b : memref<10xf32>) delete(%a : memref<10xf32>)
+  return
+}
+
+// CHECK: acc.exit_data copyout(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) delete(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<f32>, ptr<f32>, i64)>)
+
+// -----
+
+func @testexitdataop(%a: !llvm.ptr<f32>, %b: memref<10xf32>) -> () {
+  acc.exit_data copyout(%b : memref<10xf32>) delete(%a : !llvm.ptr<f32>)
+  return
+}
+
+// CHECK: acc.exit_data copyout(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) delete(%{{.*}} : !llvm.ptr<f32>)
+
+// -----
+
+func @testexitdataop(%a: memref<10xi64>, %b: memref<10xf32>) -> () {
+  acc.exit_data copyout(%b : memref<10xf32>) delete(%a : memref<10xi64>) attributes {async}
+  return
+}
+
+// CHECK: acc.exit_data copyout(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) delete(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<i64>, ptr<i64>, i64)>) attributes {async}
+
+// -----
+
+func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
+  %ifCond = constant true
+  acc.exit_data if(%ifCond) copyout(%b : memref<10xf32>) delete(%a : memref<10xf32>)
+  return
+}
+
+// CHECK: acc.exit_data if(%{{.*}}) copyout(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) delete(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<f32>, ptr<f32>, i64)>)
+
+// -----
+
+func @testupdateop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
+  acc.update host(%b : memref<10xf32>) device(%a : memref<10xf32>)
+  return
+}
+
+// CHECK: acc.update host(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) device(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<f32>, ptr<f32>, i64)>)
+
+// -----
+
+func @testupdateop(%a: !llvm.ptr<f32>, %b: memref<10xf32>) -> () {
+  acc.update host(%b : memref<10xf32>) device(%a : !llvm.ptr<f32>)
+  return
+}
+
+// CHECK: acc.update host(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) device(%{{.*}} : !llvm.ptr<f32>)
+
+// -----
+
+func @testupdateop(%a: memref<10xi64>, %b: memref<10xf32>) -> () {
+  acc.update host(%b : memref<10xf32>) device(%a : memref<10xi64>) attributes {async}
+  return
+}
+
+// CHECK: acc.update host(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) device(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<i64>, ptr<i64>, i64)>) attributes {async}
+
+// -----
+
+func @testupdateop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
+  %ifCond = constant true
+  acc.update if(%ifCond) host(%b : memref<10xf32>) device(%a : memref<10xf32>)
+  return
+}
+
+// CHECK: acc.update if(%{{.*}}) host(%{{.*}} : !llvm.struct<"openacc_data", (ptr<f32>, ptr<f32>, i64)>) device(%{{.*}} : !llvm.struct<"openacc_data.1", (ptr<f32>, ptr<f32>, i64)>)