[flang-commits] [flang] [mlir] [mlir] Ptr dialect (PR #73057)

Fabian Mora via flang-commits flang-commits at lists.llvm.org
Tue Mar 26 16:44:09 PDT 2024


https://github.com/fabianmcg updated https://github.com/llvm/llvm-project/pull/73057

>From cfd15df8d6cb16d5e3e4016951b1dbdcc027923c Mon Sep 17 00:00:00 2001
From: Fabian Mora <fmora.dev at gmail.com>
Date: Tue, 26 Mar 2024 23:40:36 +0000
Subject: [PATCH] [mlir] Ptr dialect #73057

This patch introduces the Ptr dialect, a dialect to model pointer operations motivated by the goal of modularizing the LLVM dialect.

More specifically, this patch introduces:
- The pointer dialect and type.
- The `MemorySpaceAttrInterface` interface, an interface to conceptualize memory models, giving proper semantical meaning to the Ptr dialect ops.
- The `ptr::LoadOp` operation, an operation to load data from memory, with the semantics defined by `MemorySpaceAttrInterface` and translatable to LLVM IR.
- The `SharedDialectTypeInterface` interface, an interface to delegate printing and parsing to a different dialect.
- The introduction of `LLVM::AddressSpaceAttr`, an attribute to model LLVM memory semantics.
- The replacement of `LLVMPointerType` with `ptr::PtrType`.
---
 flang/lib/Optimizer/CodeGen/CMakeLists.txt    |   1 +
 flang/lib/Optimizer/CodeGen/CodeGen.cpp       |   2 +
 flang/lib/Optimizer/Support/CMakeLists.txt    |   1 +
 flang/lib/Optimizer/Support/InitFIR.cpp       |   3 +
 .../Fir/convert-to-llvm-openmp-and-fir.fir    |  64 +--
 flang/test/Fir/convert-to-llvm.fir            | 184 +++---
 flang/test/Fir/embox-char.fir                 |  48 +-
 flang/test/Fir/embox-substring.fir            |   2 +-
 flang/test/Fir/rebox-susbtring.fir            |   4 +-
 flang/test/Fir/tbaa-codegen.fir               |  12 +-
 flang/test/Fir/tbaa-codegen2.fir              |  12 +-
 flang/test/Fir/tbaa.fir                       | 138 ++---
 flang/test/Lower/OpenMP/FIR/flush.f90         |   6 +-
 flang/test/Transforms/tbaa.fir                |  52 +-
 flang/test/Transforms/tbaa2.fir               |  56 +-
 mlir/include/mlir/Dialect/CMakeLists.txt      |   1 +
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       | 300 ++--------
 mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h  |  26 +-
 .../include/mlir/Dialect/LLVMIR/LLVMDialect.h |   9 +
 .../mlir/Dialect/LLVMIR/LLVMDialect.td        |   3 +
 mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td |  65 ---
 .../mlir/Dialect/LLVMIR/LLVMInterfaces.h      |  14 +-
 .../mlir/Dialect/LLVMIR/LLVMInterfaces.td     | 127 +----
 .../mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td   |   3 +-
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   | 277 +--------
 mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h  |  39 +-
 mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td |  41 +-
 mlir/include/mlir/Dialect/Ptr/CMakeLists.txt  |   1 +
 .../mlir/Dialect/Ptr/IR/CMakeLists.txt        |  24 +
 .../include/mlir/Dialect/Ptr/IR/MemoryModel.h | 161 ++++++
 .../Dialect/Ptr/IR/MemorySpaceInterfaces.td   | 182 ++++++
 mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.h   |  41 ++
 mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.td  | 292 ++++++++++
 mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.h |  20 +
 .../include/mlir/Dialect/Ptr/IR/PtrDialect.td |  89 +++
 mlir/include/mlir/Dialect/Ptr/IR/PtrEnums.td  |  69 +++
 .../mlir/Dialect/Ptr/IR/PtrInterfaces.h       |  34 ++
 .../mlir/Dialect/Ptr/IR/PtrInterfaces.td      | 152 +++++
 mlir/include/mlir/Dialect/Ptr/IR/PtrOps.h     |  28 +
 mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td    | 411 ++++++++++++++
 mlir/include/mlir/Dialect/Ptr/IR/PtrTypes.h   |  39 ++
 mlir/include/mlir/IR/AsmInterfaces.h          |  19 +
 mlir/include/mlir/IR/AsmInterfaces.td         |  60 ++
 mlir/include/mlir/IR/CMakeLists.txt           |   7 +
 mlir/include/mlir/IR/OpImplementation.h       |  28 +-
 mlir/include/mlir/InitAllDialects.h           |   2 +
 .../mlir/Interfaces/MemorySlotInterfaces.td   |  21 +
 mlir/include/mlir/Target/LLVMIR/Dialect/All.h |   5 +
 .../Dialect/Ptr/LLVMIRToPtrTranslation.h      |  31 ++
 .../Dialect/Ptr/PtrToLLVMIRTranslation.h      |  31 ++
 .../mlir/Target/LLVMIR/LLVMImportInterface.h  |  53 ++
 .../include/mlir/Target/LLVMIR/ModuleImport.h |  21 +-
 .../mlir/Target/LLVMIR/ModuleTranslation.h    |   9 +-
 mlir/lib/AsmParser/DialectSymbolParser.cpp    |  12 +
 .../Conversion/AsyncToLLVM/AsyncToLLVM.cpp    |   1 +
 .../ConvertToLLVM/ConvertToLLVMPass.cpp       |   1 +
 .../GPUCommon/GPUToLLVMConversion.cpp         |   1 +
 .../LLVMCommon/ConversionTarget.cpp           |   1 +
 .../Conversion/MemRefToLLVM/MemRefToLLVM.cpp  |  11 +-
 .../Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp    |   1 +
 .../Conversion/SCFToOpenMP/SCFToOpenMP.cpp    |   2 +-
 .../ConvertLaunchFuncToLLVMCalls.cpp          |   1 +
 .../SPIRVToLLVM/SPIRVToLLVMPass.cpp           |   1 +
 mlir/lib/Dialect/CMakeLists.txt               |   1 +
 mlir/lib/Dialect/LLVMIR/CMakeLists.txt        |   1 +
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 161 +++++-
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    | 265 ++-------
 mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp   |  13 +-
 mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp |  52 --
 mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp | 207 +------
 mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp      | 178 +-----
 mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp       |   5 +-
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  |   5 +-
 mlir/lib/Dialect/Ptr/CMakeLists.txt           |   1 +
 mlir/lib/Dialect/Ptr/IR/CMakeLists.txt        |  18 +
 mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp        | 524 ++++++++++++++++++
 mlir/lib/Dialect/Ptr/IR/PtrMemorySlot.cpp     | 233 ++++++++
 mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp          | 198 +++++++
 .../Transforms/SparseTensorPasses.cpp         |   7 +-
 mlir/lib/ExecutionEngine/CMakeLists.txt       |   2 +
 mlir/lib/IR/AsmInterfaces.cpp                 |  19 +
 mlir/lib/IR/AsmPrinter.cpp                    | 123 +++-
 mlir/lib/IR/CMakeLists.txt                    |   2 +
 mlir/lib/Target/LLVMIR/CMakeLists.txt         |   4 +
 mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt |   1 +
 .../LLVMIR/LLVMIRToLLVMTranslation.cpp        |  21 +
 .../LLVMIR/LLVMToLLVMIRTranslation.cpp        |  21 +
 .../Target/LLVMIR/Dialect/Ptr/CMakeLists.txt  |  31 ++
 .../Dialect/Ptr/LLVMIRToPtrTranslation.cpp    | 312 +++++++++++
 .../Dialect/Ptr/PtrToLLVMIRTranslation.cpp    | 379 +++++++++++++
 mlir/lib/Target/LLVMIR/ModuleImport.cpp       |  35 +-
 mlir/lib/Target/LLVMIR/TypeToLLVM.cpp         |   8 +-
 mlir/lib/Transforms/Mem2Reg.cpp               |  14 +-
 .../AMDGPUToROCDL/amdgpu-to-rocdl.mlir        |   4 +-
 .../AsyncToLLVM/convert-runtime-to-llvm.mlir  |   6 +-
 .../AsyncToLLVM/convert-to-llvm.mlir          |   6 +-
 .../FuncToLLVM/calling-convention.mlir        |  12 +-
 .../lower-alloc-to-gpu-runtime-calls.mlir     |   4 +-
 .../lower-memcpy-to-gpu-runtime-calls.mlir    |   6 +-
 .../GPUCommon/lower-memory-space-attrs.mlir   |  14 +-
 .../lower-memset-to-gpu-runtime-calls.mlir    |   2 +-
 .../GPUCommon/memory-attrbution.mlir          |   8 +-
 .../Conversion/GPUCommon/transfer_write.mlir  |   2 +-
 .../Conversion/GPUToNVVM/gpu-to-nvvm.mlir     |   6 +-
 .../Conversion/GPUToVulkan/invoke-vulkan.mlir |   4 +-
 .../convert-dynamic-memref-ops.mlir           |  60 +-
 .../convert-static-memref-ops.mlir            |  38 +-
 .../expand-then-convert-to-llvm.mlir          |   4 +-
 .../MemRefToLLVM/memref-to-llvm.mlir          |  68 ++-
 .../Conversion/NVGPUToNVVM/nvgpu-to-nvvm.mlir |  12 +-
 .../OpenMPToLLVM/convert-to-llvmir.mlir       |  36 +-
 .../Conversion/SCFToOpenMP/reductions.mlir    |  36 +-
 .../SPIRVToLLVM/memory-ops-to-llvm.mlir       |  24 +-
 .../VectorToLLVM/vector-scalable-memcpy.mlir  |   4 +-
 .../VectorToLLVM/vector-to-llvm.mlir          |  14 +-
 mlir/test/Dialect/LLVMIR/canonicalize.mlir    |  20 +-
 .../Dialect/LLVMIR/inlining-alias-scopes.mlir | 212 +++----
 mlir/test/Dialect/LLVMIR/inlining.mlir        |  58 +-
 mlir/test/Dialect/LLVMIR/invalid.mlir         |  78 +--
 mlir/test/Dialect/LLVMIR/loop-metadata.mlir   |  16 +-
 mlir/test/Dialect/LLVMIR/mem2reg-dbginfo.mlir |  16 +-
 .../Dialect/LLVMIR/mem2reg-intrinsics.mlir    |  42 +-
 mlir/test/Dialect/LLVMIR/mem2reg.mlir         | 172 +++---
 mlir/test/Dialect/LLVMIR/opaque-ptr.mlir      |  12 +-
 mlir/test/Dialect/LLVMIR/rocdl.mlir           |   2 +-
 mlir/test/Dialect/LLVMIR/roundtrip.mlir       |  60 +-
 mlir/test/Dialect/LLVMIR/sroa-intrinsics.mlir |  44 +-
 mlir/test/Dialect/LLVMIR/sroa-statistics.mlir |  10 +-
 mlir/test/Dialect/LLVMIR/sroa.mlir            |  82 +--
 mlir/test/Dialect/LLVMIR/tbaa-invalid.mlir    |  32 +-
 mlir/test/Dialect/LLVMIR/tbaa-roundtrip.mlir  |  84 +--
 .../test/Dialect/LLVMIR/type-consistency.mlir | 164 +++---
 mlir/test/Dialect/MemRef/transform-ops.mlir   |   2 +-
 mlir/test/Dialect/OpenACC/invalid.mlir        |  10 +-
 mlir/test/Dialect/OpenACC/ops.mlir            |   4 +-
 mlir/test/Dialect/OpenMP/canonicalize.mlir    |   2 +-
 mlir/test/Dialect/OpenMP/invalid.mlir         |   8 +-
 mlir/test/Dialect/OpenMP/ops.mlir             |  58 +-
 mlir/test/Integration/GPU/CUDA/sm90/asd       |  36 +-
 mlir/test/Target/LLVMIR/Import/basic.ll       |   6 +-
 mlir/test/Target/LLVMIR/Import/constant.ll    |  16 +-
 .../test/Target/LLVMIR/Import/instructions.ll |  74 +--
 .../LLVMIR/Import/metadata-alias-scopes.ll    |  36 +-
 .../Target/LLVMIR/Import/metadata-loop.ll     |  24 +-
 .../Target/LLVMIR/Import/metadata-tbaa.ll     |  48 +-
 .../Target/LLVMIR/Import/target-ext-type.ll   |   2 +-
 mlir/test/Target/LLVMIR/arm-sve.mlir          |   4 +-
 .../Target/LLVMIR/attribute-alias-scopes.mlir |  24 +-
 mlir/test/Target/LLVMIR/attribute-tbaa.mlir   |  44 +-
 mlir/test/Target/LLVMIR/llvmir.mlir           |  96 ++--
 mlir/test/Target/LLVMIR/loop-metadata.mlir    |  12 +-
 .../omptarget-array-sectioning-host.mlir      |   4 +-
 ...target-byref-bycopy-generation-device.mlir |   4 +-
 ...mptarget-byref-bycopy-generation-host.mlir |   4 +-
 .../omptarget-constant-alloca-raise.mlir      |   4 +-
 ...arget-constant-indexing-device-region.mlir |   4 +-
 .../omptarget-declare-target-llvm-device.mlir |   2 +-
 .../omptarget-declare-target-llvm-host.mlir   |   2 +-
 ...target-fortran-allocatable-types-host.mlir |  12 +-
 mlir/test/Target/LLVMIR/omptarget-llvm.mlir   |  44 +-
 .../LLVMIR/omptarget-parallel-llvm.mlir       |   8 +-
 .../LLVMIR/omptarget-parallel-wsloop.mlir     |   2 +-
 .../LLVMIR/omptarget-region-device-llvm.mlir  |  10 +-
 .../Target/LLVMIR/omptarget-region-llvm.mlir  |  10 +-
 .../omptarget-region-parallel-llvm.mlir       |  10 +-
 .../LLVMIR/omptarget-wsloop-collapsed.mlir    |   2 +-
 mlir/test/Target/LLVMIR/omptarget-wsloop.mlir |   2 +-
 mlir/test/Target/LLVMIR/opaque-ptr.mlir       |   6 +-
 mlir/test/Target/LLVMIR/openacc-llvm.mlir     |   2 +-
 .../Target/LLVMIR/openmp-firstprivate.mlir    |  12 +-
 .../Target/LLVMIR/openmp-llvm-invalid.mlir    |   6 +-
 mlir/test/Target/LLVMIR/openmp-llvm.mlir      | 110 ++--
 mlir/test/Target/LLVMIR/openmp-nested.mlir    |   4 +-
 mlir/test/Target/LLVMIR/openmp-private.mlir   |  20 +-
 .../Target/LLVMIR/openmp-reduction-byref.mlir |  10 +-
 .../Target/LLVMIR/openmp-reduction-call.mlir  |   4 +-
 mlir/test/Target/LLVMIR/openmp-reduction.mlir |  68 +--
 mlir/test/Target/LLVMIR/openmp-teams.mlir     |   2 +-
 mlir/test/Target/LLVMIR/target-ext-type.mlir  |   2 +-
 .../Dialect/Test/TestDialectInterfaces.cpp    |  72 +++
 mlir/test/mlir-cpu-runner/simple.mlir         |   4 +-
 mlir/test/mlir-cpu-runner/x86-varargs.mlir    |  12 +-
 mlir/unittests/ExecutionEngine/Invoke.cpp     |   7 +
 183 files changed, 5709 insertions(+), 2929 deletions(-)
 create mode 100644 mlir/include/mlir/Dialect/Ptr/CMakeLists.txt
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/CMakeLists.txt
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/MemoryModel.h
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.h
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.td
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.h
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.td
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrEnums.td
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.h
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.td
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrOps.h
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td
 create mode 100644 mlir/include/mlir/Dialect/Ptr/IR/PtrTypes.h
 create mode 100644 mlir/include/mlir/IR/AsmInterfaces.h
 create mode 100644 mlir/include/mlir/IR/AsmInterfaces.td
 create mode 100644 mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.h
 create mode 100644 mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h
 create mode 100644 mlir/lib/Dialect/Ptr/CMakeLists.txt
 create mode 100644 mlir/lib/Dialect/Ptr/IR/CMakeLists.txt
 create mode 100644 mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp
 create mode 100644 mlir/lib/Dialect/Ptr/IR/PtrMemorySlot.cpp
 create mode 100644 mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp
 create mode 100644 mlir/lib/IR/AsmInterfaces.cpp
 create mode 100644 mlir/lib/Target/LLVMIR/Dialect/Ptr/CMakeLists.txt
 create mode 100644 mlir/lib/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.cpp
 create mode 100644 mlir/lib/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.cpp

diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index 879bc28d017a35..623dd8e88e9a36 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -21,6 +21,7 @@ add_flang_library(FIRCodeGen
   FIRDialect
   FIRDialectSupport
   FIRSupport
+  MLIRPtrDialect
   MLIRComplexToLLVM
   MLIRComplexToStandard
   MLIRMathToFuncs
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 06ce84f1543a3f..fbfe812811c560 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -44,6 +44,7 @@
 #include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/Ptr/IR/PtrDialect.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/Matchers.h"
 #include "mlir/Pass/Pass.h"
@@ -3615,6 +3616,7 @@ class FIRToLLVMLowering
     fir::populateOpenMPFIRToLLVMConversionPatterns(typeConverter, pattern);
 
     mlir::ConversionTarget target{*context};
+    target.addLegalDialect<mlir::ptr::PtrDialect>();
     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
     // The OpenMP dialect is legal for Operations without regions, for those
     // which contains regions it is legal if the region contains only the
diff --git a/flang/lib/Optimizer/Support/CMakeLists.txt b/flang/lib/Optimizer/Support/CMakeLists.txt
index 55f5718a90b854..b98f0988a3d20c 100644
--- a/flang/lib/Optimizer/Support/CMakeLists.txt
+++ b/flang/lib/Optimizer/Support/CMakeLists.txt
@@ -20,6 +20,7 @@ add_flang_library(FIRSupport
   MLIROpenACCToLLVMIRTranslation
   MLIROpenMPToLLVMIRTranslation
   MLIRLLVMToLLVMIRTranslation
+  MLIRPtrToLLVMIRTranslation
   MLIRTargetLLVMIRExport
   MLIRTargetLLVMIRImport
 
diff --git a/flang/lib/Optimizer/Support/InitFIR.cpp b/flang/lib/Optimizer/Support/InitFIR.cpp
index 0753c4511d9c64..c9ef8b35bf0307 100644
--- a/flang/lib/Optimizer/Support/InitFIR.cpp
+++ b/flang/lib/Optimizer/Support/InitFIR.cpp
@@ -11,6 +11,7 @@
 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h"
+#include "mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h"
 
 void fir::support::registerLLVMTranslation(mlir::MLIRContext &context) {
   mlir::DialectRegistry registry;
@@ -22,5 +23,7 @@ void fir::support::registerLLVMTranslation(mlir::MLIRContext &context) {
   registerLLVMDialectTranslation(registry);
   // Register builtin dialect interface.
   registerBuiltinDialectTranslation(registry);
+  // Register ptr dialect interface.
+  registerPtrDialectTranslation(registry);
   context.appendDialectRegistry(registry);
 }
diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
index 92628af37085a5..62292bd2b63c3e 100644
--- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
+++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
@@ -29,15 +29,15 @@ func.func @_QPsb1(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}, %arg1: !fir.ref<!
 // CHECK: omp.parallel   {
 // CHECK:      %[[ONE_3:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:      %[[I_VAR:.*]] = llvm.alloca %[[ONE_3]] x i32 {pinned} : (i64) -> !llvm.ptr
-// CHECK:      %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr -> i32
+// CHECK:      %[[N:.*]] = ptr.load %[[N_REF]] : !llvm.ptr -> i32
 // CHECK: omp.wsloop nowait
 // CHECK-SAME: for (%[[I:.*]]) : i32 = (%[[ONE_2]]) to (%[[N]]) inclusive step (%[[ONE_2]]) {
-// CHECK:   llvm.store %[[I]], %[[I_VAR]] : i32, !llvm.ptr
-// CHECK:   %[[I1:.*]] = llvm.load %[[I_VAR]] : !llvm.ptr -> i32
+// CHECK:   ptr.store %[[I]], %[[I_VAR]] : i32, !llvm.ptr
+// CHECK:   %[[I1:.*]] = ptr.load %[[I_VAR]] : !llvm.ptr -> i32
 // CHECK:   %[[I1_EXT:.*]] = llvm.sext %[[I1]] : i32 to i64
 // CHECK:   %[[I_CSTYLE:.*]] = llvm.sub %[[I1_EXT]], %[[ONE_1]]  : i64
 // CHECK:   %[[ARR_I_REF:.*]] = llvm.getelementptr %[[ARR_REF]][%[[I_CSTYLE]]] : (!llvm.ptr, i64) -> !llvm.ptr
-// CHECK:   llvm.store %[[I1]], %[[ARR_I_REF]] : i32, !llvm.ptr
+// CHECK:   ptr.store %[[I1]], %[[ARR_I_REF]] : i32, !llvm.ptr
 // CHECK: omp.yield
 // CHECK: }
 // CHECK: omp.terminator
@@ -63,8 +63,8 @@ func.func @_QPsb2(%arg0: !fir.ref<i32> {fir.bindc_name = "x"}, %arg1: !fir.ref<i
 // CHECK-SAME: %[[X_REF:.*]]: !llvm.ptr {fir.bindc_name = "x"}, %[[N_REF:.*]]: !llvm.ptr {fir.bindc_name = "n"}) {
 // CHECK: omp.parallel   {
 // CHECK:   omp.master {
-// CHECK:     %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr -> i32
-// CHECK:     llvm.store %[[N]], %[[X_REF]] : i32, !llvm.ptr
+// CHECK:     %[[N:.*]] = ptr.load %[[N_REF]] : !llvm.ptr -> i32
+// CHECK:     ptr.store %[[N]], %[[X_REF]] : i32, !llvm.ptr
 // CHECK:     omp.terminator
 // CHECK:   }
 // CHECK:   omp.terminator
@@ -99,7 +99,7 @@ func.func @_QPsb(%arr: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "arr"}) {
 // CHECK:      %[[C1:.*]] = llvm.mlir.constant(1 : i32) : i32
 // CHECK:      %[[C50:.*]] = llvm.mlir.constant(50 : i32) : i32
 // CHECK:      omp.wsloop   for  (%[[INDX:.*]]) : i32 = (%[[C1]]) to (%[[C50]]) inclusive step (%[[C1]]) {
-// CHECK:        llvm.store %[[INDX]], %{{.*}} : i32, !llvm.ptr
+// CHECK:        ptr.store %[[INDX]], %{{.*}} : i32, !llvm.ptr
 // CHECK:        omp.yield
 // CHECK:      omp.terminator
 // CHECK:    llvm.return
@@ -201,15 +201,15 @@ func.func @_QPsimd1(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}, %arg1: !fir.ref
 // CHECK: omp.parallel   {
 // CHECK:      %[[ONE_3:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:      %[[I_VAR:.*]] = llvm.alloca %[[ONE_3]] x i32 {pinned} : (i64) -> !llvm.ptr
-// CHECK:      %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr -> i32
+// CHECK:      %[[N:.*]] = ptr.load %[[N_REF]] : !llvm.ptr -> i32
 // CHECK: omp.simdloop
 // CHECK-SAME: (%[[I:.*]]) : i32 = (%[[ONE_2]]) to (%[[N]]) step (%[[ONE_2]]) {
-// CHECK:   llvm.store %[[I]], %[[I_VAR]] : i32, !llvm.ptr
-// CHECK:   %[[I1:.*]] = llvm.load %[[I_VAR]] : !llvm.ptr -> i32
+// CHECK:   ptr.store %[[I]], %[[I_VAR]] : i32, !llvm.ptr
+// CHECK:   %[[I1:.*]] = ptr.load %[[I_VAR]] : !llvm.ptr -> i32
 // CHECK:   %[[I1_EXT:.*]] = llvm.sext %[[I1]] : i32 to i64
 // CHECK:   %[[I_CSTYLE:.*]] = llvm.sub %[[I1_EXT]], %[[ONE_1]]  : i64
 // CHECK:   %[[ARR_I_REF:.*]] = llvm.getelementptr %[[ARR_REF]][%[[I_CSTYLE]]] : (!llvm.ptr, i64) -> !llvm.ptr
-// CHECK:   llvm.store %[[I1]], %[[ARR_I_REF]] : i32, !llvm.ptr
+// CHECK:   ptr.store %[[I1]], %[[ARR_I_REF]] : i32, !llvm.ptr
 // CHECK: omp.yield
 // CHECK: }
 // CHECK: omp.terminator
@@ -386,24 +386,24 @@ func.func @_QPopenmp_target_data_region() {
 // CHECK:             %[[VAL_16:.*]] = llvm.icmp "sgt" %[[VAL_14]], %[[VAL_15]] : i64
 // CHECK:             llvm.cond_br %[[VAL_16]], ^bb2, ^bb3
 // CHECK:           ^bb2:
-// CHECK:             llvm.store %[[VAL_13]], %[[VAL_3]] : i32, !llvm.ptr
-// CHECK:             %[[VAL_17:.*]] = llvm.load %[[VAL_3]] : !llvm.ptr -> i32
-// CHECK:             %[[VAL_18:.*]] = llvm.load %[[VAL_3]] : !llvm.ptr -> i32
+// CHECK:             ptr.store %[[VAL_13]], %[[VAL_3]] : i32, !llvm.ptr
+// CHECK:             %[[VAL_17:.*]] = ptr.load %[[VAL_3]] : !llvm.ptr -> i32
+// CHECK:             %[[VAL_18:.*]] = ptr.load %[[VAL_3]] : !llvm.ptr -> i32
 // CHECK:             %[[VAL_19:.*]] = llvm.sext %[[VAL_18]] : i32 to i64
 // CHECK:             %[[VAL_20:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:             %[[VAL_21:.*]] = llvm.sub %[[VAL_19]], %[[VAL_20]]  : i64
 // CHECK:             %[[VAL_22:.*]] = llvm.getelementptr %[[VAL_1]][0, %[[VAL_21]]] : (!llvm.ptr, i64) -> !llvm.ptr
-// CHECK:             llvm.store %[[VAL_17]], %[[VAL_22]] : i32, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_17]], %[[VAL_22]] : i32, !llvm.ptr
 // CHECK:             %[[VAL_23:.*]] = llvm.add %[[VAL_12]], %[[VAL_8]]  : i64
 // CHECK:             %[[VAL_24:.*]] = llvm.trunc %[[VAL_8]] : i64 to i32
-// CHECK:             %[[VAL_25:.*]] = llvm.load %[[VAL_3]] : !llvm.ptr -> i32
+// CHECK:             %[[VAL_25:.*]] = ptr.load %[[VAL_3]] : !llvm.ptr -> i32
 // CHECK:             %[[VAL_26:.*]] = llvm.add %[[VAL_25]], %[[VAL_24]]  : i32
 // CHECK:             %[[VAL_27:.*]] = llvm.add %[[VAL_12]], %[[VAL_8]]  : i64
 // CHECK:             %[[VAL_28:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK:             %[[VAL_29:.*]] = llvm.sub %[[VAL_14]], %[[VAL_28]]  : i64
 // CHECK:             llvm.br ^bb1(%[[VAL_27]], %[[VAL_26]], %[[VAL_29]] : i64, i32, i64)
 // CHECK:           ^bb3:
-// CHECK:             llvm.store %[[VAL_13]], %[[VAL_3]] : i32, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_13]], %[[VAL_3]] : i32, !llvm.ptr
 // CHECK:             omp.terminator
 // CHECK:           }
 // CHECK:           llvm.return
@@ -463,7 +463,7 @@ func.func @_QPomp_target() {
 // CHECK:             %[[VAL_5:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:             %[[VAL_6:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:             %[[VAL_7:.*]] = llvm.getelementptr %[[ARG_0]][0, %[[VAL_6]]] : (!llvm.ptr, i64) -> !llvm.ptr
-// CHECK:             llvm.store %[[VAL_3]], %[[VAL_7]] : i32, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_3]], %[[VAL_7]] : i32, !llvm.ptr
 // CHECK:             omp.terminator
 // CHECK:           }
 // CHECK:           llvm.return
@@ -669,9 +669,9 @@ func.func @_QPsb() {
 // CHECK:        %[[EXIT_COND:.*]] = llvm.icmp "sgt"
 // CHECK:        llvm.cond_br %[[EXIT_COND]], ^[[BB_LOOP_BODY:.*]], ^[[BB_EXIT:.*]]
 // CHECK:      ^[[BB_LOOP_BODY]]:
-// CHECK:        %[[LI_VAL:.*]] = llvm.load %[[LI_REF]] : !llvm.ptr -> i32
+// CHECK:        %[[LI_VAL:.*]] = ptr.load %[[LI_REF]] : !llvm.ptr -> i32
 // CHECK:        %[[LI_INC:.*]] = llvm.add %[[LI_VAL]], %[[ONE]]  : i32
-// CHECK:        llvm.store %[[LI_INC]], %[[LI_REF]] : i32, !llvm.ptr
+// CHECK:        ptr.store %[[LI_INC]], %[[LI_REF]] : i32, !llvm.ptr
 // CHECK:        llvm.br ^[[BB_ENTRY]]({{.*}})
 // CHECK:      ^[[BB_EXIT]]:
 // CHECK:        omp.terminator
@@ -703,15 +703,15 @@ func.func @_QPsb() {
 // CHECK:    omp.parallel   {
 // CHECK:      omp.wsloop   reduction(@[[EQV_REDUCTION]] %[[RED_ACCUMULATOR]] -> %[[PRV:.+]] : !llvm.ptr) for
 // CHECK:        %[[ARRAY_ELEM_REF:.*]] = llvm.getelementptr %[[ARRAY_REF]][0, %{{.*}}] : (!llvm.ptr, i64) -> !llvm.ptr
-// CHECK:        %[[ARRAY_ELEM:.*]] = llvm.load %[[ARRAY_ELEM_REF]] : !llvm.ptr -> i32
-// CHECK:        %[[LPRV:.+]] = llvm.load %[[PRV]] : !llvm.ptr -> i32
+// CHECK:        %[[ARRAY_ELEM:.*]] = ptr.load %[[ARRAY_ELEM_REF]] : !llvm.ptr -> i32
+// CHECK:        %[[LPRV:.+]] = ptr.load %[[PRV]] : !llvm.ptr -> i32
 // CHECK:        %[[ZERO_1:.*]] = llvm.mlir.constant(0 : i64) : i32
 // CHECK:        %[[ARGVAL_1:.*]] = llvm.icmp "ne" %[[LPRV]], %[[ZERO_1]] : i32
 // CHECK:        %[[ZERO_2:.*]] = llvm.mlir.constant(0 : i64) : i32
 // CHECK:        %[[ARGVAL_2:.*]] = llvm.icmp "ne" %[[ARRAY_ELEM]], %[[ZERO_2]] : i32
 // CHECK:        %[[RES:.*]] = llvm.icmp "eq" %[[ARGVAL_2]], %[[ARGVAL_1]] : i1
 // CHECK:        %[[RES_EXT:.*]] = llvm.zext %[[RES]] : i1 to i32
-// CHECK:        llvm.store %[[RES_EXT]], %[[PRV]] : i32, !llvm.ptr
+// CHECK:        ptr.store %[[RES_EXT]], %[[PRV]] : i32, !llvm.ptr
 // CHECK:        omp.yield
 // CHECK:      omp.terminator
 // CHECK:    llvm.return
@@ -781,10 +781,10 @@ func.func @_QPs(%arg0: !fir.ref<!fir.complex<4>> {fir.bindc_name = "x"}) {
 //CHECK:  omp.parallel   {
 //CHECK:    %[[CONST_1:.*]] = llvm.mlir.constant(1 : i32) : i32
 //CHECK:    %[[ALLOCA_1:.*]] = llvm.alloca %[[CONST_1:.*]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
-//CHECK:    %[[LOAD:.*]] = llvm.load %[[ALLOCA]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
-//CHECK:    llvm.store %[[LOAD]], %[[ALLOCA_1]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
+//CHECK:    %[[LOAD:.*]] = ptr.load %[[ALLOCA]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
+//CHECK:    ptr.store %[[LOAD]], %[[ALLOCA_1]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
 //CHECK:    %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA_1]][0, 0] : (!llvm.ptr) -> !llvm.ptr
-//CHECK:    %[[LOAD_2:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> !llvm.ptr
+//CHECK:    %[[LOAD_2:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> !llvm.ptr
 //CHECK:    omp.terminator
 //CHECK:  }
 
@@ -864,13 +864,13 @@ func.func @sub_() {
       omp.flush(%arg0, %arg1, %arg2 : !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>)
 // CHECK:      omp.flush
       omp.flush
-// CHECK:      %[[A_VAL:.*]] = llvm.load %[[ARG_A]] : !llvm.ptr -> i32
+// CHECK:      %[[A_VAL:.*]] = ptr.load %[[ARG_A]] : !llvm.ptr -> i32
       %0 = fir.load %arg0 : !fir.ref<i32>
-// CHECK:      %[[B_VAL:.*]] = llvm.load %[[ARG_B]] : !llvm.ptr -> i32
+// CHECK:      %[[B_VAL:.*]] = ptr.load %[[ARG_B]] : !llvm.ptr -> i32
       %1 = fir.load %arg1 : !fir.ref<i32>
 // CHECK:      %[[C_VAL:.*]] = llvm.add %[[A_VAL]], %[[B_VAL]]  : i32
       %2 = arith.addi %0, %1 : i32
-// CHECK:      llvm.store %[[C_VAL]], %[[ARG_C]] : i32, !llvm.ptr
+// CHECK:      ptr.store %[[C_VAL]], %[[ARG_C]] : i32, !llvm.ptr
       fir.store %2 to %arg2 : !fir.ref<i32>
 // CHECK:      omp.terminator
       omp.terminator
@@ -892,13 +892,13 @@ func.func @omp_critical_() {
   %1 = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFomp_criticalEy"}
 // CHECK: omp.critical(@help)
   omp.critical(@help) {
-// CHECK: %[[X_VAL:.*]] = llvm.load %[[X_REF]] : !llvm.ptr -> i32
+// CHECK: %[[X_VAL:.*]] = ptr.load %[[X_REF]] : !llvm.ptr -> i32
     %2 = fir.load %0 : !fir.ref<i32>
-// CHECK: %[[Y_VAL:.*]] = llvm.load %[[Y_REF]] : !llvm.ptr -> i32
+// CHECK: %[[Y_VAL:.*]] = ptr.load %[[Y_REF]] : !llvm.ptr -> i32
     %3 = fir.load %1 : !fir.ref<i32>
 // CHECK: %[[RESULT:.*]] = llvm.add %[[X_VAL]], %[[Y_VAL]]  : i32
     %4 = arith.addi %2, %3 : i32
-// CHECK: llvm.store %[[RESULT]], %[[X_REF]] : i32, !llvm.ptr
+// CHECK: ptr.store %[[RESULT]], %[[X_REF]] : i32, !llvm.ptr
     fir.store %4 to %0 : !fir.ref<i32>
 // CHECK: omp.terminator
     omp.terminator
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 21323a5e657c94..93fcb7315a437d 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -218,7 +218,7 @@ func.func @test_alloc_and_freemem_one() {
 // CHECK-LABEL:  llvm.func @test_alloc_and_freemem_one() {
 // CHECK-NEXT:    %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK-NEXT:    %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK-NEXT:    %[[N:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK-NEXT:    %[[N:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK-NEXT:    llvm.call @malloc(%[[N]])
 // CHECK:         llvm.call @free(%{{.*}})
 // CHECK-NEXT:    llvm.return
@@ -237,7 +237,7 @@ func.func @test_alloc_and_freemem_several() {
 // CHECK-LABEL:  llvm.func @test_alloc_and_freemem_several() {
 // CHECK: [[NULL:%.*]]  = llvm.mlir.zero : !llvm.ptr
 // CHECK: [[PTR:%.*]]  = llvm.getelementptr [[NULL]][{{.*}}] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<100 x f32>
-// CHECK: [[N:%.*]]  = llvm.ptrtoint [[PTR]] : !llvm.ptr to i64
+// CHECK: [[N:%.*]]  = ptr.ptrtoint [[PTR]] : !llvm.ptr to i64
 // CHECK: [[MALLOC:%.*]] = llvm.call @malloc([[N]])
 // CHECK:              llvm.call @free([[MALLOC]])
 // CHECK:              llvm.return
@@ -253,7 +253,7 @@ func.func @test_with_shape(%ncols: index, %nrows: index) {
 // CHECK-SAME: %[[NCOLS:.*]]: i64, %[[NROWS:.*]]: i64
 // CHECK:   %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:   %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:   %[[FOUR:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:   %[[FOUR:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:   %[[DIM1_SIZE:.*]] = llvm.mul %[[FOUR]], %[[NCOLS]]  : i64
 // CHECK:   %[[TOTAL_SIZE:.*]] = llvm.mul %[[DIM1_SIZE]], %[[NROWS]]  : i64
 // CHECK:   %[[MEM:.*]] = llvm.call @malloc(%[[TOTAL_SIZE]])
@@ -271,7 +271,7 @@ func.func @test_string_with_shape(%len: index, %nelems: index) {
 // CHECK-SAME: %[[LEN:.*]]: i64, %[[NELEMS:.*]]: i64)
 // CHECK:   %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:   %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:   %[[ONE:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:   %[[ONE:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:   %[[LEN_SIZE:.*]] = llvm.mul %[[ONE]], %[[LEN]]  : i64
 // CHECK:   %[[TOTAL_SIZE:.*]] = llvm.mul %[[LEN_SIZE]], %[[NELEMS]]  : i64
 // CHECK:   %[[MEM:.*]] = llvm.call @malloc(%[[TOTAL_SIZE]])
@@ -749,7 +749,7 @@ func.func @convert_from_int(%arg0 : i32) {
 // CHECK:         %{{.*}} = llvm.trunc %[[ARG0]] : i32 to i16
 // CHECK-NOT:     %{{.*}} = llvm.trunc %[[ARG0]] : i32 to i32
 // CHECK:         %{{.*}} = llvm.sext %[[ARG0]] : i32 to i64
-// CHECK:         %{{.*}} = llvm.inttoptr %{{.*}} : i64 to !llvm.ptr
+// CHECK:         %{{.*}} = ptr.inttoptr %{{.*}} : i64 to !llvm.ptr
 
 
 func.func @convert_from_i1(%arg0 : i1) {
@@ -774,7 +774,7 @@ func.func @convert_from_ref(%arg0 : !fir.ref<i32>) {
 // CHECK-LABEL: convert_from_ref(
 // CHECK-SAME:                   %[[ARG0:.*]]: !llvm.ptr
 // CHECK-NOT:         %{{.*}} = llvm.bitcast %[[ARG0]] : !llvm.ptr to !llvm.ptr
-// CHECK:         %{{.*}} = llvm.ptrtoint %[[ARG0]] : !llvm.ptr to i32
+// CHECK:         %{{.*}} = ptr.ptrtoint %[[ARG0]] : !llvm.ptr to i32
 
 // -----
 
@@ -848,7 +848,7 @@ func.func @test_constc8() -> !fir.complex<8> {
 
 // -----
 
-// Test `fir.store` --> `llvm.store` conversion
+// Test `fir.store` --> `ptr.store` conversion
 
 func.func @test_store_index(%val_to_store : index, %addr : !fir.ref<index>) {
   fir.store %val_to_store to %addr : !fir.ref<index>
@@ -857,7 +857,7 @@ func.func @test_store_index(%val_to_store : index, %addr : !fir.ref<index>) {
 
 // CHECK-LABEL:   llvm.func @test_store_index
 // CHECK-SAME:    (%[[arg0:.*]]: i64, %[[arg1:.*]]: !llvm.ptr) {
-// CHECK-NEXT:    llvm.store %[[arg0]], %[[arg1]] : i64, !llvm.ptr
+// CHECK-NEXT:    ptr.store %[[arg0]], %[[arg1]] : i64, !llvm.ptr
 // CHECK-NEXT:    llvm.return
 // CHECK-NEXT:  }
 
@@ -869,8 +869,8 @@ func.func @test_store_box(%array : !fir.ref<!fir.box<!fir.array<?x?xf32>>>, %box
 // CHECK-LABEL:  llvm.func @test_store_box
 // CHECK-SAME:  (%[[arg0:.*]]: !llvm.ptr,
 // CHECK-SAME:  %[[arg1:.*]]: !llvm.ptr) {
-// CHECK-NEXT:  %[[box_to_store:.*]] = llvm.load %arg1 : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>
-// CHECK-NEXT:  llvm.store %[[box_to_store]], %[[arg0]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>, !llvm.ptr
+// CHECK-NEXT:  %[[box_to_store:.*]] = ptr.load %arg1 : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>
+// CHECK-NEXT:  ptr.store %[[box_to_store]], %[[arg0]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>, !llvm.ptr
 // CHECK-NEXT:  llvm.return
 // CHECK-NEXT:  }
 
@@ -883,19 +883,19 @@ func.func @store_unlimited_polymorphic_box(%arg0 : !fir.class<none>, %arg1 : !fi
   return
 }
 // CHECK-LABEL:   llvm.func @store_unlimited_polymorphic_box(
-// CHECK:  %[[VAL_8:.*]] = llvm.load %{{.*}} : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>
-// CHECK:  llvm.store %[[VAL_8]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
-// CHECK:  %[[VAL_9:.*]] = llvm.load %{{.*}} : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>, ptr, array<1 x i{{.*}}>)>
-// CHECK:  llvm.store %[[VAL_9]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
-// CHECK:  %[[VAL_10:.*]] = llvm.load %{{.*}} : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>
-// CHECK:  llvm.store %[[VAL_10]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
-// CHECK:  %[[VAL_11:.*]] = llvm.load %{{.*}}: !llvm.ptr
-// CHECK:  llvm.store %[[VAL_11]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
+// CHECK:  %[[VAL_8:.*]] = ptr.load %{{.*}} : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>
+// CHECK:  ptr.store %[[VAL_8]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
+// CHECK:  %[[VAL_9:.*]] = ptr.load %{{.*}} : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>, ptr, array<1 x i{{.*}}>)>
+// CHECK:  ptr.store %[[VAL_9]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
+// CHECK:  %[[VAL_10:.*]] = ptr.load %{{.*}} : !llvm.ptr -> !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>
+// CHECK:  ptr.store %[[VAL_10]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
+// CHECK:  %[[VAL_11:.*]] = ptr.load %{{.*}}: !llvm.ptr
+// CHECK:  ptr.store %[[VAL_11]], %{{.*}} : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>, ptr, array<1 x i{{.*}}>)>, !llvm.ptr
 
 
 // -----
 
-// Test `fir.load` --> `llvm.load` conversion
+// Test `fir.load` --> `ptr.load` conversion
 
 func.func @test_load_index(%addr : !fir.ref<index>) {
   %0 = fir.load %addr : !fir.ref<index>
@@ -904,7 +904,7 @@ func.func @test_load_index(%addr : !fir.ref<index>) {
 
 // CHECK-LABEL: llvm.func @test_load_index(
 // CHECK-SAME:  %[[arg1:.*]]: !llvm.ptr) {
-// CHECK-NEXT:    %0 = llvm.load %[[arg1]] : !llvm.ptr -> i64
+// CHECK-NEXT:    %0 = ptr.load %[[arg1]] : !llvm.ptr -> i64
 // CHECK-NEXT:    llvm.return
 // CHECK-NEXT:  }
 
@@ -922,9 +922,9 @@ func.func @test_load_box(%addr : !fir.ref<!fir.box<!fir.array<10xf32>>>) {
 // CHECK-NEXT:    %[[c1:.*]] = llvm.mlir.constant(1 : i32) : i32
 // GENERIC-NEXT:  %[[box_copy:.*]] = llvm.alloca %[[c1]] x !llvm.struct<([[DESC_TYPE:.*]])>
 // AMDGPU-NEXT:   %[[alloca_box_copy:.*]] = llvm.alloca %[[c1]] x !llvm.struct<([[DESC_TYPE:.*]])>{{.*}} : (i32) -> !llvm.ptr<5>
-// AMDGPU-NEXT:   %[[box_copy:.*]] = llvm.addrspacecast %[[alloca_box_copy]] : !llvm.ptr<5> to !llvm.ptr
-// CHECK-NEXT:    %[[box_val:.*]] = llvm.load %[[arg0]] : !llvm.ptr -> !llvm.struct<([[DESC_TYPE]])>
-// CHECK-NEXT:    llvm.store %[[box_val]], %[[box_copy]] : !llvm.struct<([[DESC_TYPE]])>, !llvm.ptr
+// AMDGPU-NEXT:   %[[box_copy:.*]] = ptr.addrspacecast %[[alloca_box_copy]] : !llvm.ptr<5> to !llvm.ptr
+// CHECK-NEXT:    %[[box_val:.*]] = ptr.load %[[arg0]] : !llvm.ptr -> !llvm.struct<([[DESC_TYPE]])>
+// CHECK-NEXT:    ptr.store %[[box_val]], %[[box_copy]] : !llvm.struct<([[DESC_TYPE]])>, !llvm.ptr
 // CHECK-NEXT:    llvm.call @takes_box(%[[box_copy]]) : (!llvm.ptr) -> ()
 // CHECK-NEXT:    llvm.return
 // CHECK-NEXT:  }
@@ -941,7 +941,7 @@ func.func @extract_rank(%arg0: !fir.box<!fir.array<*:f64>>) -> i32 {
 // CHECK-LABEL: llvm.func @extract_rank(
 // CHECK-SAME:                          %[[ARG0:.*]]: !llvm.ptr) -> i32
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[RANK:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> i32
+// CHECK:         %[[RANK:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> i32
 // CHECK:         llvm.return %[[RANK]] : i32
 
 // -----
@@ -956,7 +956,7 @@ func.func @extract_addr(%arg0: !fir.box<!fir.array<*:f64>>) -> !fir.ref<f64> {
 // CHECK-LABEL: llvm.func @extract_addr(
 // CHECK-SAME:                          %[[ARG0:.*]]: !llvm.ptr) -> !llvm.ptr
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[ADDR:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> !llvm.ptr
+// CHECK:         %[[ADDR:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> !llvm.ptr
 // CHECK:         llvm.return %[[ADDR]] : !llvm.ptr
 
 // -----
@@ -974,11 +974,11 @@ func.func @extract_dims(%arg0: !fir.box<!fir.array<*:f64>>) -> index {
 // CHECK-SAME:                          %[[ARG0:.*]]: !llvm.ptr) -> i64
 // CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK:         %[[GEP0:.*]] = llvm.getelementptr %[[ARG0]][0, 7, %[[C0]], 0] :  (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[LOAD0:.*]] = llvm.load %[[GEP0]] : !llvm.ptr -> i64
+// CHECK:         %[[LOAD0:.*]] = ptr.load %[[GEP0]] : !llvm.ptr -> i64
 // CHECK:         %[[GEP1:.*]] = llvm.getelementptr %[[ARG0]][0, 7, %[[C0]], 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[LOAD1:.*]] = llvm.load %[[GEP1]] : !llvm.ptr -> i64
+// CHECK:         %[[LOAD1:.*]] = ptr.load %[[GEP1]] : !llvm.ptr -> i64
 // CHECK:         %[[GEP2:.*]] = llvm.getelementptr %[[ARG0]][0, 7, %[[C0]], 2] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[LOAD2:.*]] = llvm.load %[[GEP2]] : !llvm.ptr -> i64
+// CHECK:         %[[LOAD2:.*]] = ptr.load %[[GEP2]] : !llvm.ptr -> i64
 // CHECK:         llvm.return %[[LOAD0]] : i64
 
 // -----
@@ -993,7 +993,7 @@ func.func @extract_elesize(%arg0: !fir.box<f32>) -> i32 {
 // CHECK-LABEL: llvm.func @extract_elesize(
 // CHECK-SAME:                             %[[ARG0:.*]]: !llvm.ptr) -> i32
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[ELE_SIZE:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> i32
+// CHECK:         %[[ELE_SIZE:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> i32
 // CHECK:         llvm.return %[[ELE_SIZE]] : i32
 
 // -----
@@ -1009,7 +1009,7 @@ func.func @box_isarray(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
 // CHECK-LABEL: llvm.func @box_isarray(
 // CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr) -> i1
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[RANK:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> i32
+// CHECK:         %[[RANK:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> i32
 // CHECK:         %[[C0_ISARRAY:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK:         %[[IS_ARRAY:.*]] = llvm.icmp "ne" %[[RANK]], %[[C0_ISARRAY]] : i32
 // CHECK:         llvm.return %[[IS_ARRAY]] : i1
@@ -1028,7 +1028,7 @@ func.func @box_isalloc(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
 // CHECK-LABEL: llvm.func @box_isalloc(
 // CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr) -> i1
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[ATTR:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> i32
+// CHECK:         %[[ATTR:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> i32
 // CHECK:         %[[ATTR_ISALLOC:.*]] = llvm.mlir.constant(2 : i32) : i32
 // CHECK:         %[[AND:.*]] = llvm.and %[[ATTR]], %[[ATTR_ISALLOC]]  : i32
 // CHECK:         %[[CMP_C0:.*]] = llvm.mlir.constant(0 : i32) : i32
@@ -1049,7 +1049,7 @@ func.func @box_isptr(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
 // CHECK-LABEL: llvm.func @box_isptr(
 // CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr) -> i1
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         %[[ATTR:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> i32
+// CHECK:         %[[ATTR:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> i32
 // CHECK:         %[[ATTR_ISALLOC:.*]] = llvm.mlir.constant(1 : i32) : i32
 // CHECK:         %[[AND:.*]] = llvm.and %[[ATTR]], %[[ATTR_ISALLOC]]  : i32
 // CHECK:         %[[CMP_C0:.*]] = llvm.mlir.constant(0 : i32) : i32
@@ -1069,7 +1069,7 @@ func.func @alloca_one() -> !fir.ref<i32> {
 // CHECK: [[N:%.*]] = llvm.mlir.constant(1 : i64) : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[N]] x i32
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[N]] x i32 : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[A]] : !llvm.ptr
 
 
@@ -1089,7 +1089,7 @@ func.func @alloca_several() -> !fir.ref<i32> {
 // CHECK: [[TOTAL:%.*]] = llvm.mul [[ONE]], [[N]] : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[TOTAL]] x i32
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[TOTAL]] x i32 : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[A]] : !llvm.ptr
 
 // -----
@@ -1105,7 +1105,7 @@ func.func @alloca_ptr_to_array() -> !fir.ref<!fir.ptr<!fir.array<?xi32>>> {
 // CHECK: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[ONE]] x !llvm.ptr
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[ONE]] x !llvm.ptr : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[A]] : !llvm.ptr
 
 // -----
@@ -1125,7 +1125,7 @@ func.func @alloca_char_array(%l: i32, %e : index) -> !fir.ref<!fir.array<?x?x!fi
 // CHECK: [[PROD2:%.*]] = llvm.mul [[PROD1]], [[E]] : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[PROD2]] x i8
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[PROD2]] x i8 : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: return [[A]] : !llvm.ptr
 
 // -----
@@ -1144,7 +1144,7 @@ func.func @alloca_fixed_char_array(%e : index) -> !fir.ref<!fir.array<?x?x!fir.c
 // CHECK: [[PROD2:%.*]] = llvm.mul [[PROD1]], [[E]] : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[PROD2]] x !llvm.array<8 x i8>
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[PROD2]] x !llvm.array<8 x i8> : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: return [[A]] : !llvm.ptr
 
 // -----
@@ -1170,7 +1170,7 @@ func.func @alloca_record(%arg0 : i32, %arg1 : i16) -> !fir.ref<!fir.type<_QTt(p1
 // CHECK: [[SIZE:%.*]] = llvm.call @_QTtP.mem.size([[ARG0]], [[ARG1]]) : (i32, i16) -> i64
 // GENERIC: [[ALLOC:%.*]] = llvm.alloca [[SIZE]] x i8
 // AMDGPU: [[A:%.*]] = llvm.alloca [[SIZE]] x i8 : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[ALLOC:%.*]] = llvm.addrspacecast [[A]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[ALLOC:%.*]] = ptr.addrspacecast [[A]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[ALLOC]] : !llvm.ptr
 
 // -----
@@ -1191,7 +1191,7 @@ func.func @alloca_multidim_array(%0 : index) -> !fir.ref<!fir.array<8x16x32xf32>
 // CHECK: [[TOTAL:%.*]] = llvm.mul [[MUL1]], [[OP2]] : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[TOTAL]] x !llvm.array<32 x array<16 x array<8 x f32>>>
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[TOTAL]] x !llvm.array<32 x array<16 x array<8 x f32>>> : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[A]] : !llvm.ptr
 
 // -----
@@ -1212,7 +1212,7 @@ func.func @alloca_const_interior_array(%0 : index) -> !fir.ref<!fir.array<8x9x?x
 // CHECK: [[TOTAL:%.*]] = llvm.mul [[MUL1]], [[OP2]] : i64
 // GENERIC: [[A:%.*]] = llvm.alloca [[TOTAL]] x !llvm.array<9 x array<8 x f32>>
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[TOTAL]] x !llvm.array<9 x array<8 x f32>> : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[A:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[A]] : !llvm.ptr
 
 // -----
@@ -1234,7 +1234,7 @@ func.func @alloca_array_with_holes(%0 : index, %1 : index) -> !fir.ref<!fir.arra
 // CHECK: [[PROD3:%.*]] = llvm.mul [[PROD2]], [[B]] : i64
 // GENERIC: [[RES:%.*]] = llvm.alloca [[PROD3]] x !llvm.array<4 x i32>
 // AMDGPU: [[AA:%.*]] = llvm.alloca [[PROD3]] x !llvm.array<4 x i32> : (i64) -> !llvm.ptr<5>
-// AMDGPU: [[RES:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU: [[RES:%.*]] = ptr.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[RES]] : !llvm.ptr
 
 // -----
@@ -1285,7 +1285,7 @@ func.func @select_case_integer(%arg0: !fir.ref<i32>) -> i32 {
 
 // CHECK-LABEL: llvm.func @select_case_integer(
 // CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr) -> i32 {
-// CHECK:         %[[SELECT_VALUE:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> i32
+// CHECK:         %[[SELECT_VALUE:.*]] = ptr.load %[[ARG0]] : !llvm.ptr -> i32
 // CHECK:         %[[CST1:.*]] = llvm.mlir.constant(1 : i32) : i32
 // CHECK:         %[[CST2:.*]] = llvm.mlir.constant(2 : i32) : i32
 // CHECK:         %[[CST4:.*]] = llvm.mlir.constant(4 : i32) : i32
@@ -1344,7 +1344,7 @@ func.func @select_case_integer(%arg0: !fir.ref<i32>) -> i32 {
 // CHECK:        llvm.br ^bb14
 // Block ^bb6 in original FIR code.
 // CHECK-LABEL: ^bb14:
-// CHECK:        %[[RET:.*]] = llvm.load %[[ARG0:.*]] : !llvm.ptr -> i32
+// CHECK:        %[[RET:.*]] = ptr.load %[[ARG0:.*]] : !llvm.ptr -> i32
 // CHECK:        llvm.return %[[RET]] : i32
 
 // -----
@@ -1371,7 +1371,7 @@ func.func @select_case_logical(%arg0: !fir.ref<!fir.logical<4>>) {
 
 // CHECK-LABEL: llvm.func @select_case_logical(
 // CHECK-SAME:                                 %[[ARG0:.*]]: !llvm.ptr
-// CHECK:         %[[LOAD_ARG0:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> i32
+// CHECK:         %[[LOAD_ARG0:.*]] = ptr.load %[[ARG0]] : !llvm.ptr -> i32
 // CHECK:         %[[CST_ZERO:.*]] = llvm.mlir.constant(0 : i64) : i32
 // CHECK:         %[[SELECT_VALUE:.*]] = llvm.icmp "ne" %[[LOAD_ARG0]], %[[CST_ZERO]] : i32
 // CHECK:         %[[CST_FALSE:.*]] = llvm.mlir.constant(false) : i1
@@ -1402,7 +1402,7 @@ func.func @test_is_present_i64(%arg0: !fir.ref<i64>) -> () {
 // CHECK-LABEL: @test_is_present_i64
 // CHECK-SAME: (%[[arg:.*]]: !llvm.ptr)
 // CHECK-NEXT:  %[[constant:.*]] = llvm.mlir.constant(0 : i64) : i64
-// CHECK-NEXT:  %[[ptr:.*]] = llvm.ptrtoint %[[arg]] : !llvm.ptr to i64
+// CHECK-NEXT:  %[[ptr:.*]] = ptr.ptrtoint %[[arg]] : !llvm.ptr to i64
 // CHECK-NEXT:  %{{.*}} = llvm.icmp "ne" %[[ptr]], %[[constant]] : i64
 // CHECK-NEXT:  llvm.return
 // CHECK-NEXT: }
@@ -1415,7 +1415,7 @@ func.func @test_is_present_box(%arg0: !fir.box<!fir.ref<i64>>) -> () {
 // CHECK-LABEL: @test_is_present_box
 // CHECK-SAME: (%[[arg:.*]]: !llvm.ptr)
 // CHECK-NEXT: %[[constant:.*]] = llvm.mlir.constant(0 : i64) : i64
-// CHECK-NEXT: %[[ptr:.*]] = llvm.ptrtoint %[[arg]] : !llvm.ptr to i64
+// CHECK-NEXT: %[[ptr:.*]] = ptr.ptrtoint %[[arg]] : !llvm.ptr to i64
 // CHECK-NEXT: %{{.*}} = llvm.icmp "ne" %[[ptr]], %[[constant]] : i64
 // CHECK-NEXT: llvm.return
 // CHECK-NEXT: }
@@ -1457,7 +1457,7 @@ func.func @is_present(%arg0: !fir.ref<i64>) -> i1 {
 // CHECK-LABEL: @is_present
 // CHECK-SAME: (%[[arg:.*]]: !llvm.ptr) -> i1
 // CHECK-NEXT:  %[[constant:.*]] = llvm.mlir.constant(0 : i64) : i64
-// CHECK-NEXT:  %[[ptr:.*]] = llvm.ptrtoint %[[arg]] : !llvm.ptr to i64
+// CHECK-NEXT:  %[[ptr:.*]] = ptr.ptrtoint %[[arg]] : !llvm.ptr to i64
 // CHECK-NEXT:  %[[ret_val:.*]] = llvm.icmp "ne" %[[ptr]], %[[constant]] : i64
 // CHECK-NEXT:  llvm.return %[[ret_val]] : i1
 // CHECK-NEXT: }
@@ -1554,7 +1554,7 @@ func.func @box_tdesc(%arg0: !fir.box<!fir.type<dtdesc{a:i32}>>) {
 // CHECK-LABEL: llvm.func @box_tdesc(
 // CHECK-SAME:                       %[[ARG0:.*]]: !llvm.ptr) {
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 7] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>
-// CHECK:         %[[LOAD:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> !llvm.ptr
+// CHECK:         %[[LOAD:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> !llvm.ptr
 
 // -----
 
@@ -1575,11 +1575,11 @@ func.func @embox0(%arg0: !fir.ref<!fir.array<100xi32>>) {
 // CHECK:         %[[C1:.*]] = llvm.mlir.constant(1 : i32) : i32
 // GENERIC:       %[[ALLOCA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 // AMDGPU:        %[[AA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-// AMDGPU:        %[[ALLOCA:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[ALLOCA:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[TYPE_CODE:.*]] = llvm.mlir.constant(9 : i32) : i32
 // CHECK:         %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:         %[[I64_ELEM_SIZE:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:         %[[I64_ELEM_SIZE:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:         %[[DESC:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
 // CHECK:         %[[DESC0:.*]] = llvm.insertvalue %[[I64_ELEM_SIZE]], %[[DESC]][1] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
 // CHECK:         %[[CFI_VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -1596,7 +1596,7 @@ func.func @embox0(%arg0: !fir.ref<!fir.array<100xi32>>) {
 // CHECK:         %[[F18ADDENDUM_I8:.*]] = llvm.trunc %[[F18ADDENDUM]] : i32 to i8
 // CHECK:         %[[DESC5:.*]] = llvm.insertvalue %[[F18ADDENDUM_I8]], %[[DESC4]][6] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
 // CHECK:         %[[DESC6:.*]] = llvm.insertvalue %[[ARG0]], %[[DESC5]][0] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>
-// CHECK:         llvm.store %[[DESC6]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>, !llvm.ptr
+// CHECK:         ptr.store %[[DESC6]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>, !llvm.ptr
 
 // Check `fir.embox` in a `fir.global`. Descriptors created by `fir.embox`
 // conversion are not generating `alloca` instructions. This test make sure of
@@ -1778,9 +1778,9 @@ func.func @no_reassoc(%arg0: !fir.ref<i32>) {
 // CHECK:         %[[C1:.*]] = llvm.mlir.constant(1 : i64) : i64
 // GENERIC:       %[[ALLOC:.*]] = llvm.alloca %[[C1]] x i32 : (i64) -> !llvm.ptr
 // AMDGPU:        %[[AA:.*]] = llvm.alloca %[[C1]] x i32 : (i64) -> !llvm.ptr<5>
-// AMDGPU:        %[[ALLOC:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
-// CHECK:         %[[LOAD:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> i32
-// CHECK:         llvm.store %[[LOAD]], %[[ALLOC]] : i32, !llvm.ptr
+// AMDGPU:        %[[ALLOC:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+// CHECK:         %[[LOAD:.*]] = ptr.load %[[ARG0]] : !llvm.ptr -> i32
+// CHECK:         ptr.store %[[LOAD]], %[[ALLOC]] : i32, !llvm.ptr
 // CHECK:         llvm.return
 
 // -----
@@ -1800,12 +1800,12 @@ func.func @xembox0(%arg0: !fir.ref<!fir.array<?xi32>>) {
 // CHECK:         %[[ALLOCA_SIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
 // GENERIC:       %[[ALLOCA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 // AMDGPU:        %[[AA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-// AMDGPU:        %[[ALLOCA:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[ALLOCA:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:         %[[TYPE:.*]] = llvm.mlir.constant(9 : i32) : i32
 // CHECK:         %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:         %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:         %[[ELEM_LEN_I64:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:         %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
 // CHECK:         %[[BOX1:.*]] = llvm.insertvalue %[[ELEM_LEN_I64]], %[[BOX0]][1] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
 // CHECK:         %[[VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -1839,7 +1839,7 @@ func.func @xembox0(%arg0: !fir.ref<!fir.array<?xi32>>) {
 // CHECK:         %[[PREV_PTROFF:.*]] = llvm.mul %[[ONE]], %[[C0]]  : i64
 // CHECK:         %[[BASE_PTR:.*]] = llvm.getelementptr %[[ARG0]][%[[PTR_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
 // CHECK:         %[[BOX10:.*]] = llvm.insertvalue %[[BASE_PTR]], %[[BOX9]][0] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK:         llvm.store %[[BOX10]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:         ptr.store %[[BOX10]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>, !llvm.ptr
 
 // Check adjustment of element scaling factor.
 
@@ -1853,7 +1853,7 @@ func.func @xembox1(%arg0: !fir.ref<!fir.array<?x!fir.char<1, 10>>>) {
 // CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:         %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:         %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:         %[[ELEM_LEN_I64:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:         %{{.*}} = llvm.insertvalue %[[ELEM_LEN_I64]], %{{.*}}[1] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
 // CHECK:         %[[PREV_PTROFF:.*]] = llvm.mul %[[ELEM_LEN_I64]], %[[C0]]  : i64
 
@@ -1890,7 +1890,7 @@ func.func private @_QPxb(!fir.box<!fir.array<?x?xf64>>)
 // CHECK:         %[[ALLOCA_SIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
 // GENERIC:       %[[ALLOCA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 // AMDGPU:        %[[AA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-// AMDGPU:        %[[ALLOCA:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[ALLOCA:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[C4:.*]] = llvm.mlir.constant(4 : index) : i64
 // CHECK:         %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK:         %[[C2:.*]] = llvm.mlir.constant(2 : index) : i64
@@ -1903,11 +1903,11 @@ func.func private @_QPxb(!fir.box<!fir.array<?x?xf64>>)
 // CHECK:         %[[ARR_SIZE:.*]] = llvm.mul %[[ARR_SIZE_TMP1]], %[[N2]]  : i64
 // GENERIC:       %[[ARR:.*]] = llvm.alloca %[[ARR_SIZE]] x f64 {bindc_name = "arr"} : (i64) -> !llvm.ptr
 // AMDGPU:        %[[AR:.*]] = llvm.alloca %[[ARR_SIZE]] x f64 {bindc_name = "arr"} : (i64) -> !llvm.ptr<5>
-// AMDGPU:        %[[ARR:.*]] = llvm.addrspacecast %[[AR]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[ARR:.*]] = ptr.addrspacecast %[[AR]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[TYPE_CODE:.*]] = llvm.mlir.constant(28 : i32) : i32
 // CHECK:         %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:         %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:         %[[ELEM_LEN_I64:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:         %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
 // CHECK:         %[[BOX1:.*]] = llvm.insertvalue %[[ELEM_LEN_I64]], %[[BOX0]][1] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
 // CHECK:         %[[VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -1953,7 +1953,7 @@ func.func private @_QPxb(!fir.box<!fir.array<?x?xf64>>)
 // CHECK:         %[[BOX12:.*]] = llvm.insertvalue %[[STRIDE_MUL]], %[[BOX11]][7, 1, 2] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
 // CHECK:         %[[BASE_PTR:.*]] = llvm.getelementptr %[[ARR]][%[[PTR_OFFSET0]]] : (!llvm.ptr, i64) -> !llvm.ptr, f64
 // CHECK:         %[[BOX13:.*]] = llvm.insertvalue %[[BASE_PTR]], %[[BOX12]][0] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
-// CHECK:         llvm.store %[[BOX13]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:         ptr.store %[[BOX13]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>, !llvm.ptr
 
 // Conversion with a subcomponent.
 
@@ -1975,7 +1975,7 @@ func.func private @_QPtest_dt_callee(%arg0: !fir.box<!fir.array<?xi32>>)
 // CHECK:         %[[ALLOCA_SIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
 // GENERIC:       %[[ALLOCA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 // AMDGPU:        %[[AA:.*]] = llvm.alloca %[[ALLOCA_SIZE]] x !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-// AMDGPU:        %[[ALLOCA:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[ALLOCA:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[C20:.*]] = llvm.mlir.constant(20 : index) : i64
 // CHECK:         %[[C1:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:         %[[C10:.*]] = llvm.mlir.constant(10 : i64) : i64
@@ -1983,15 +1983,15 @@ func.func private @_QPtest_dt_callee(%arg0: !fir.box<!fir.array<?xi32>>)
 // CHECK:         %[[ALLOCA_SIZE_V:.*]] = llvm.mlir.constant(1 : i64) : i64
 // GENERIC:       %[[V:.*]] = llvm.alloca %[[ALLOCA_SIZE_V]] x i32 {bindc_name = "v"} : (i64) -> !llvm.ptr
 // AMDGPU:        %[[AB:.*]] = llvm.alloca %[[ALLOCA_SIZE_V]] x i32 {bindc_name = "v"} : (i64) -> !llvm.ptr<5>
-// AMDGPU:        %[[V:.*]] = llvm.addrspacecast %[[AB]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[V:.*]] = ptr.addrspacecast %[[AB]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[ALLOCA_SIZE_X:.*]] = llvm.mlir.constant(1 : i64) : i64
 // GENERIC:       %[[X:.*]] = llvm.alloca %[[ALLOCA_SIZE_X]] x !llvm.array<20 x struct<"_QFtest_dt_sliceTt", (i32, i32)>> {bindc_name = "x"} : (i64) -> !llvm.ptr
 // AMDGPU:        %[[AC:.*]] = llvm.alloca %[[ALLOCA_SIZE_X]] x !llvm.array<20 x struct<"_QFtest_dt_sliceTt", (i32, i32)>> {bindc_name = "x"} : (i64) -> !llvm.ptr<5>
-// AMDGPU:        %[[X:.*]] = llvm.addrspacecast %[[AC]] : !llvm.ptr<5> to !llvm.ptr
+// AMDGPU:        %[[X:.*]] = ptr.addrspacecast %[[AC]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK:         %[[TYPE_CODE:.*]] = llvm.mlir.constant(9 : i32) : i32
 // CHECK:         %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-// CHECK:         %[[ELEM_LEN_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+// CHECK:         %[[ELEM_LEN_I64:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 // CHECK:         %[[BOX0:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
 // CHECK:         %[[BOX1:.*]] = llvm.insertvalue %[[ELEM_LEN_I64]], %[[BOX0]][1] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
 // CHECK:         %[[VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -2011,7 +2011,7 @@ func.func private @_QPtest_dt_callee(%arg0: !fir.box<!fir.array<?xi32>>)
 // CHECK:         %[[ONE:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:         %[[ELE_TYPE:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:         %[[GEP_DTYPE_SIZE:.*]] = llvm.getelementptr %[[ELE_TYPE]][1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFtest_dt_sliceTt", (i32, i32)>
-// CHECK:         %[[PTRTOINT_DTYPE_SIZE:.*]] = llvm.ptrtoint %[[GEP_DTYPE_SIZE]] : !llvm.ptr to i64
+// CHECK:         %[[PTRTOINT_DTYPE_SIZE:.*]] = ptr.ptrtoint %[[GEP_DTYPE_SIZE]] : !llvm.ptr to i64
 // CHECK:         %[[ADJUSTED_OFFSET:.*]] = llvm.sub %[[C1]], %[[ONE]]  : i64
 // CHECK:         %[[EXT_SUB:.*]] = llvm.sub %[[C10]], %[[C1]]  : i64
 // CHECK:         %[[EXT_ADD:.*]] = llvm.add %[[EXT_SUB]], %[[C2]]  : i64
@@ -2024,7 +2024,7 @@ func.func private @_QPtest_dt_callee(%arg0: !fir.box<!fir.array<?xi32>>)
 // CHECK:         %[[BOX9:.*]] = llvm.insertvalue %[[STRIDE_MUL]], %[[BOX8]][7, 0, 2] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
 // CHECK:         %[[BASE_PTR:.*]] = llvm.getelementptr %[[X]][%[[ZERO]], %[[ADJUSTED_OFFSET]], 0] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<20 x struct<"_QFtest_dt_sliceTt", (i32, i32)>>
 // CHECK:         %[[BOX10:.*]] = llvm.insertvalue %[[BASE_PTR]], %[[BOX9]][0] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK:         llvm.store %[[BOX10]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:         ptr.store %[[BOX10]], %[[ALLOCA]] : !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>, !llvm.ptr
 // CHECK:         llvm.call @_QPtest_dt_callee(%[[ALLOCA]]) : (!llvm.ptr) -> ()
 
 // Conversion with a subcomponent that indexes a 2d array field in a derived type.
@@ -2127,11 +2127,11 @@ func.func @ext_array_coor3(%arg0: !fir.box<!fir.array<?xi32>>) {
 // CHECK:         %[[IDX:.*]] = llvm.sub %[[C0]], %[[C1]] overflow<nsw> : i64
 // CHECK:         %[[DIFF0:.*]] = llvm.mul %[[IDX]], %[[C1]] overflow<nsw> : i64
 // CHECK:         %[[GEPSTRIDE:.*]] = llvm.getelementptr %[[ARG0]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK:         %[[LOADEDSTRIDE:.*]] = llvm.load %[[GEPSTRIDE]] : !llvm.ptr -> i64
+// CHECK:         %[[LOADEDSTRIDE:.*]] = ptr.load %[[GEPSTRIDE]] : !llvm.ptr -> i64
 // CHECK:         %[[SC:.*]] = llvm.mul %[[DIFF0]], %[[LOADEDSTRIDE]] overflow<nsw> : i64
 // CHECK:         %[[OFFSET:.*]] = llvm.add %[[SC]], %[[C0_1]] overflow<nsw> : i64
 // CHECK:         %[[GEPADDR:.*]] = llvm.getelementptr %[[ARG0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK:         %[[LOADEDADDR:.*]] = llvm.load %[[GEPADDR]] : !llvm.ptr -> !llvm.ptr
+// CHECK:         %[[LOADEDADDR:.*]] = ptr.load %[[GEPADDR]] : !llvm.ptr -> !llvm.ptr
 // CHECK:         %[[GEPADDROFFSET:.*]] = llvm.getelementptr %[[LOADEDADDR]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
 
 // Conversion with non zero shift and slice.
@@ -2285,7 +2285,7 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
 //CHECK:    %[[ONE_1:.*]] = llvm.mlir.constant(1 : i32) : i32
 //GENERIC:  %[[RESULT_BOX_REF:.*]] = llvm.alloca %[[ONE_1]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 //AMDGPU:   %[[AA:.*]] = llvm.alloca %[[ONE_1]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-//AMDGPU:   %[[RESULT_BOX_REF:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+//AMDGPU:   %[[RESULT_BOX_REF:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
 //CHECK:    %[[THREE:.*]] = llvm.mlir.constant(3 : index) : i64
 //CHECK:    %[[FOUR:.*]] = llvm.mlir.constant(4 : index) : i64
 //CHECK:    %[[FIVE:.*]] = llvm.mlir.constant(5 : index) : i64
@@ -2294,7 +2294,7 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
 //CHECK:    %[[FLOAT_TYPE:.*]] = llvm.mlir.constant(27 : i32) : i32
 //CHECK:    %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 //CHECK:    %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-//CHECK:    %[[ELEM_SIZE_I64:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+//CHECK:    %[[ELEM_SIZE_I64:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 //CHECK:    %[[RBOX:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:    %[[RBOX_TMP1:.*]] = llvm.insertvalue %[[ELEM_SIZE_I64]], %[[RBOX]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:    %[[CFI_VERSION:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -2311,11 +2311,11 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
 //CHECK:    %[[ADDENDUM_I8:.*]] = llvm.trunc %[[ADDENDUM]] : i32 to i8
 //CHECK:    %[[RBOX_TMP6:.*]] = llvm.insertvalue %[[ADDENDUM_I8]], %[[RBOX_TMP5]][6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:    %[[DIM1_STRIDE_REF:.*]] = llvm.getelementptr %[[ARG0]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-//CHECK:    %[[DIM1_STRIDE:.*]] = llvm.load %[[DIM1_STRIDE_REF]] : !llvm.ptr -> i64
+//CHECK:    %[[DIM1_STRIDE:.*]] = ptr.load %[[DIM1_STRIDE_REF]] : !llvm.ptr -> i64
 //CHECK:    %[[DIM2_STRIDE_REF:.*]] = llvm.getelementptr %[[ARG0]][0, 7, 1, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-//CHECK:    %[[DIM2_STRIDE:.*]] = llvm.load %[[DIM2_STRIDE_REF]] : !llvm.ptr -> i64
+//CHECK:    %[[DIM2_STRIDE:.*]] = ptr.load %[[DIM2_STRIDE_REF]] : !llvm.ptr -> i64
 //CHECK:    %[[SOURCE_ARRAY_PTR:.*]] = llvm.getelementptr %[[ARG0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-//CHECK:    %[[SOURCE_ARRAY:.*]] = llvm.load %[[SOURCE_ARRAY_PTR]] : !llvm.ptr -> !llvm.ptr
+//CHECK:    %[[SOURCE_ARRAY:.*]] = ptr.load %[[SOURCE_ARRAY_PTR]] : !llvm.ptr -> !llvm.ptr
 //CHECK:    %[[ZERO_ELEMS:.*]] = llvm.mlir.constant(0 : i64) : i64
 //CHECK:    %[[DIM1_LB_DIFF:.*]] = llvm.sub %[[FIVE]], %[[THREE]]  : i64
 //CHECK:    %[[DIM1_LB_OFFSET:.*]] = llvm.mul %[[DIM1_LB_DIFF]], %[[DIM1_STRIDE]]  : i64
@@ -2334,7 +2334,7 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
 //CHECK:    %[[RBOX_TMP7_2:.*]] = llvm.insertvalue %[[RESULT_NELEMS]], %[[RBOX_TMP7_1]][7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:    %[[RBOX_TMP7_3:.*]] = llvm.insertvalue %[[RESULT_STRIDE]], %[[RBOX_TMP7_2]][7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:    %[[RESULT_BOX:.*]] = llvm.insertvalue %[[RESULT_PTR]], %[[RBOX_TMP7_3]][0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-//CHECK:    llvm.store %[[RESULT_BOX]], %[[RESULT_BOX_REF]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+//CHECK:    ptr.store %[[RESULT_BOX]], %[[RESULT_BOX_REF]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
 //CHECK:    llvm.call @bar1(%[[RESULT_BOX_REF]]) : (!llvm.ptr) -> ()
 
 
@@ -2358,7 +2358,7 @@ func.func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}
 //CHECK:   %[[ONE:.*]] = llvm.mlir.constant(1 : i32) : i32
 //GENERIC: %[[RESULT_BOX_REF:.*]] = llvm.alloca %[[ONE]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 //AMDGPU:  %[[AA:.*]] = llvm.alloca %[[ONE]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-//AMDGPU:  %[[RESULT_BOX_REF:.*]] = llvm.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
+//AMDGPU:  %[[RESULT_BOX_REF:.*]] = ptr.addrspacecast %[[AA]] : !llvm.ptr<5> to !llvm.ptr
 //CHECK:   %[[RESULT_LB:.*]] = llvm.mlir.constant(3 : i64) : i64
 //CHECK:   %[[RESULT_UB:.*]] = llvm.mlir.constant(60 : i64) : i64
 //CHECK:   %[[RESULT_STRIDE:.*]] = llvm.mlir.constant(9 : i64) : i64
@@ -2367,7 +2367,7 @@ func.func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}
 //CHECK:   %[[TYPE_CHAR:.*]] = llvm.mlir.constant(40 : i32) : i32
 //CHECK:   %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
 //CHECK:   %[[GEP:.*]] = llvm.getelementptr %[[NULL]][1]
-//CHECK:   %[[CHAR_SIZE:.*]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+//CHECK:   %[[CHAR_SIZE:.*]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 //CHECK:   %[[ELEM_SIZE:.*]] = llvm.mul %[[CHAR_SIZE]], %[[ELEM_COUNT]]
 //CHECK:   %[[RBOX_TMP1:.*]] = llvm.insertvalue %[[ELEM_SIZE]], %{{.*}}[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:   %[[RBOX_TMP2:.*]] = llvm.insertvalue %{{.*}}, %[[RBOX_TMP1]][2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
@@ -2381,9 +2381,9 @@ func.func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}
 //CHECK:   %[[ADDENDUM_I8:.*]] = llvm.trunc %[[ADDENDUM]] : i32 to i8
 //CHECK:   %[[RBOX_TMP6:.*]] = llvm.insertvalue %[[ADDENDUM_I8]], %[[RBOX_TMP5]][6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:   %[[SRC_STRIDE_PTR:.*]] = llvm.getelementptr %[[ARG0]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-//CHECK:   %[[SRC_STRIDE:.*]] = llvm.load %[[SRC_STRIDE_PTR]] : !llvm.ptr -> i64
+//CHECK:   %[[SRC_STRIDE:.*]] = ptr.load %[[SRC_STRIDE_PTR]] : !llvm.ptr -> i64
 //CHECK:   %[[SRC_ARRAY_PTR:.*]] = llvm.getelementptr %[[ARG0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-//CHECK:   %[[SRC_ARRAY:.*]] = llvm.load %[[SRC_ARRAY_PTR]] : !llvm.ptr -> !llvm.ptr
+//CHECK:   %[[SRC_ARRAY:.*]] = ptr.load %[[SRC_ARRAY_PTR]] : !llvm.ptr -> !llvm.ptr
 //CHECK:   %[[ZERO_6:.*]] = llvm.mlir.constant(0 : i64) : i64
 //CHECK:   %[[COMPONENT:.*]] = llvm.getelementptr %[[SRC_ARRAY]][%[[ZERO_6]], 1, %[[COMPONENT_OFFSET_1]]] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.struct<"t", (i32, array<10 x i8>)>
 //CHECK:   %[[SRC_LB:.*]] = llvm.mlir.constant(1 : i64) : i64
@@ -2401,7 +2401,7 @@ func.func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}
 //CHECK:   %[[RBOX_TMP7_2:.*]] = llvm.insertvalue %[[RESULT_NELEMS]], %[[RBOX_TMP7_1]][7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:   %[[RBOX_TMP7_3:.*]] = llvm.insertvalue %[[RESULT_TOTAL_STRIDE]], %[[RBOX_TMP7_2]][7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
 //CHECK:   %[[RESULT_BOX:.*]] = llvm.insertvalue %[[RESULT_PTR]], %[[RBOX_TMP7_3]][0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-//CHECK:   llvm.store %[[RESULT_BOX]], %[[RESULT_BOX_REF]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
+//CHECK:   ptr.store %[[RESULT_BOX]], %[[RESULT_BOX_REF]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr
 //CHECK:   llvm.call @bar(%[[RESULT_BOX_REF]]) : (!llvm.ptr) -> ()
 //CHECK:   llvm.return
 //CHECK: }
@@ -2450,7 +2450,7 @@ func.func @coordinate_box_derived_1(%arg0: !fir.box<!fir.type<derived_1{field_1:
 // CHECK-SAME: %[[BOX:.*]]: !llvm.ptr)
 // CHECK:    %[[COORDINATE:.*]] = llvm.mlir.constant(1 : i32) : i32
 // CHECK:    %[[DERIVED_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i64>)>
-// CHECK:    %[[DERIVED_VAL:.*]] = llvm.load %[[DERIVED_ADDR]] : !llvm.ptr -> !llvm.ptr
+// CHECK:    %[[DERIVED_VAL:.*]] = ptr.load %[[DERIVED_ADDR]] : !llvm.ptr -> !llvm.ptr
 // CHECK:    %[[SUBOBJECT_ADDR:.*]] = llvm.getelementptr %[[DERIVED_VAL]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"derived_1", (i32, i32)>
 // CHECK-NEXT:    llvm.return
 
@@ -2467,7 +2467,7 @@ func.func @coordinate_box_derived_2(%arg0: !fir.box<!fir.type<derived_2{field_1:
 // CHECK-NEXT:    %[[C0_0:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK-NEXT:    %[[C1:.*]] = llvm.mlir.constant(1 : i32) : i32
 // CHECK:         %[[DERIVED_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}32, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i64>)>
-// CHECK-NEXT:    %[[DERIVED_VAL:.*]] = llvm.load %[[DERIVED_ADDR]] : !llvm.ptr -> !llvm.ptr
+// CHECK-NEXT:    %[[DERIVED_VAL:.*]] = ptr.load %[[DERIVED_ADDR]] : !llvm.ptr -> !llvm.ptr
 // CHECK-NEXT:    %[[ANOTHER_DERIVED_ADDR:.*]] = llvm.getelementptr %[[DERIVED_VAL]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"derived_2", (struct<"another_derived", (i32, f32)>, i32)>
 // CHECK-NEXT:    %[[SUBOBJECT_ADDR:.*]] = llvm.getelementptr %[[ANOTHER_DERIVED_ADDR]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"another_derived", (i32, f32)>
 // CHECK-NEXT:   llvm.return
@@ -2489,11 +2489,11 @@ func.func @coordinate_box_array_1d(%arg0: !fir.box<!fir.array<10 x f32>>, %arg1:
 // CHECK-SAME:  %[[COORDINATE:.*]]: i64
 // There's only one box here. Its index is `0`. Generate it.
 // CHECK:       %[[ARRAY_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[ARRAY_OBJECT:.*]] = llvm.load %[[ARRAY_ADDR]] : !llvm.ptr -> !llvm.ptr
+// CHECK-NEXT:  %[[ARRAY_OBJECT:.*]] = ptr.load %[[ARRAY_ADDR]] : !llvm.ptr -> !llvm.ptr
 // CHECK-NEXT:  %[[OFFSET_INIT:.*]] = llvm.mlir.constant(0 : i64) : i64
 // Index of the 1st CFI_dim_t object (corresonds the the 1st dimension)
 // CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_VAL:.*]] = llvm.load %[[DIM_1_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
+// CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_VAL:.*]] = ptr.load %[[DIM_1_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
 // CHECK-NEXT:  %[[BYTE_OFFSET:.*]] = llvm.mul %[[COORDINATE]], %[[DIM_1_MEM_STRIDE_VAL]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOJECT_OFFSET:.*]] = llvm.add %[[BYTE_OFFSET]], %[[OFFSET_INIT]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOBJECT_ADDR:.*]] = llvm.getelementptr %[[ARRAY_OBJECT]][%[[SUBOJECT_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
@@ -2508,11 +2508,11 @@ func.func @coordinate_of_box_dynamic_array_1d(%arg0: !fir.box<!fir.array<? x f32
 // CHECK-SAME:  %[[BOX:.*]]: !llvm.ptr
 // CHECK-SAME:  %[[COORDINATE:.*]]: i64
 // CHECK-NEXT:  %[[ARRAY_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[ARRAY_OBJECT:.*]] = llvm.load %[[ARRAY_ADDR]] : !llvm.ptr -> !llvm.ptr
+// CHECK-NEXT:  %[[ARRAY_OBJECT:.*]] = ptr.load %[[ARRAY_ADDR]] : !llvm.ptr -> !llvm.ptr
 // CHECK-NEXT:  %[[OFFSET_INIT:.*]] = llvm.mlir.constant(0 : i64) : i64
 // Index of the 1st CFI_dim_t object (corresonds the the 1st dimension)
 // CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_VAL:.*]] = llvm.load %[[DIM_1_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
+// CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_VAL:.*]] = ptr.load %[[DIM_1_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
 // CHECK-NEXT:  %[[BYTE_OFFSET:.*]] = llvm.mul %[[COORDINATE]], %[[DIM_1_MEM_STRIDE_VAL]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOJECT_OFFSET:.*]] = llvm.add %[[BYTE_OFFSET]], %[[OFFSET_INIT]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOBJECT_ADDR:.*]] = llvm.getelementptr %[[ARRAY_OBJECT]][%[[SUBOJECT_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
@@ -2529,16 +2529,16 @@ func.func @coordinate_box_array_2d(%arg0: !fir.box<!fir.array<10 x 10 x f32>>, %
 // CHECK-SAME: %[[BOX:.*]]: !llvm.ptr
 // CHECK-SAME: %[[COORDINATE_1:.*]]: i64, %[[COORDINATE_2:.*]]: i64)
 // CHECK-NEXT:  %[[ARRAY_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[ARRAY_OBJECT:.*]] = llvm.load %[[ARRAY_ADDR]] : !llvm.ptr -> !llvm.ptr
+// CHECK-NEXT:  %[[ARRAY_OBJECT:.*]] = ptr.load %[[ARRAY_ADDR]] : !llvm.ptr -> !llvm.ptr
 // CHECK-NEXT:  %[[OFFSET_INIT:.*]] = llvm.mlir.constant(0 : i64) : i64
 // Index of the 1st CFI_dim_t object (corresonds the the 1st dimension)
 // CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_VAL:.*]] = llvm.load %[[DIM_1_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
+// CHECK-NEXT:  %[[DIM_1_MEM_STRIDE_VAL:.*]] = ptr.load %[[DIM_1_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
 // CHECK-NEXT:  %[[BYTE_OFFSET_1:.*]] = llvm.mul %[[COORDINATE_1]], %[[DIM_1_MEM_STRIDE_VAL]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOBJECT_OFFSET_1:.*]] = llvm.add %[[BYTE_OFFSET]], %[[OFFSET_INIT]] overflow<nsw> : i64
 // Index of the 1st CFI_dim_t object (corresonds the the 2nd dimension)
 // CHECK-NEXT:  %[[DIM_2_MEM_STRIDE_ADDR:.*]] = llvm.getelementptr %[[BOX]][0, 7, 1, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i64>>)>
-// CHECK-NEXT:  %[[DIM_2_MEM_STRIDE_VAL:.*]] = llvm.load %[[DIM_2_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
+// CHECK-NEXT:  %[[DIM_2_MEM_STRIDE_VAL:.*]] = ptr.load %[[DIM_2_MEM_STRIDE_ADDR]] : !llvm.ptr -> i64
 // CHECK-NEXT:  %[[BYTE_OFFSET_2:.*]] = llvm.mul %[[COORDINATE_2]], %[[DIM_2_MEM_STRIDE_VAL]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOBJECT_OFFSET_2:.*]] = llvm.add %[[BYTE_OFFSET_2]], %[[SUBOBJECT_OFFSET_1]] overflow<nsw> : i64
 // CHECK-NEXT:  %[[SUBOBJECT_ADDR:.*]] = llvm.getelementptr %[[ARRAY_OBJECT]][%[[SUBOBJECT_OFFSET_2]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
@@ -2558,10 +2558,10 @@ func.func @coordinate_box_derived_inside_array(%arg0: !fir.box<!fir.array<10 x !
 // CHECK-SAME:    %[[BOX:.*]]: !llvm.ptr,
 // CHECK-SAME:    %[[COORDINATE_1:.*]]: i64) {
 // CHECK:         %[[VAL_6:.*]] = llvm.getelementptr %[[BOX]]{{\[}}0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:         %[[ARRAY:.*]] = llvm.load %[[VAL_6]] : !llvm.ptr -> !llvm.ptr
+// CHECK:         %[[ARRAY:.*]] = ptr.load %[[VAL_6]] : !llvm.ptr -> !llvm.ptr
 // CHECK:         %[[VAL_8:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:         %[[VAL_13:.*]] = llvm.getelementptr %[[BOX]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr,  !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:         %[[VAL_14:.*]] = llvm.load %[[VAL_13]] : !llvm.ptr -> i64
+// CHECK:         %[[VAL_14:.*]] = ptr.load %[[VAL_13]] : !llvm.ptr -> i64
 // CHECK:         %[[VAL_15:.*]] = llvm.mul %[[COORDINATE_1]], %[[VAL_14]] overflow<nsw> : i64
 // CHECK:         %[[OFFSET:.*]] = llvm.add %[[VAL_15]], %[[VAL_8]] overflow<nsw> : i64
 // CHECK:         %[[DERIVED:.*]] = llvm.getelementptr %[[ARRAY]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
diff --git a/flang/test/Fir/embox-char.fir b/flang/test/Fir/embox-char.fir
index 30015a5f7ae380..f505fde95e4dae 100644
--- a/flang/test/Fir/embox-char.fir
+++ b/flang/test/Fir/embox-char.fir
@@ -20,29 +20,29 @@
 // CHECK:           %[[VAL_11:.*]] = llvm.mlir.constant(0 : index) : i64
 // CHECK:           %[[VAL_12:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK:           %[[VAL_13_WIDTH:.*]] = llvm.mlir.constant(4 : index) : i64
-// CHECK:           %[[VAL_14:.*]] = llvm.load %[[VAL_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           llvm.store %[[VAL_14]], %[[VAL_10]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:           %[[VAL_14:.*]] = ptr.load %[[VAL_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
+// CHECK:           ptr.store %[[VAL_14]], %[[VAL_10]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
 // CHECK:           %[[VAL_15:.*]] = llvm.getelementptr %[[VAL_10]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_16_BYTESIZE:.*]] = llvm.load %[[VAL_15]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_16_BYTESIZE:.*]] = ptr.load %[[VAL_15]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_17:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_12]], 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_18_LB1:.*]] = llvm.load %[[VAL_17]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_18_LB1:.*]] = ptr.load %[[VAL_17]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_19:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_12]], 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_20_EX1:.*]] = llvm.load %[[VAL_19]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_20_EX1:.*]] = ptr.load %[[VAL_19]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_21:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_12]], 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_22_ST1:.*]] = llvm.load %[[VAL_21]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_22_ST1:.*]] = ptr.load %[[VAL_21]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_23:.*]] = llvm.getelementptr %[[VAL_10]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_24_BASEPTR:.*]] = llvm.load %[[VAL_23]] : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_24_BASEPTR:.*]] = ptr.load %[[VAL_23]] : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_25:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_11]], 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_26_LB0:.*]] = llvm.load %[[VAL_25]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_26_LB0:.*]] = ptr.load %[[VAL_25]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_27:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_11]], 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_28_EX0:.*]] = llvm.load %[[VAL_27]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_28_EX0:.*]] = ptr.load %[[VAL_27]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_29:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_11]], 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_30_ST0:.*]] = llvm.load %[[VAL_29]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_30_ST0:.*]] = ptr.load %[[VAL_29]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_31_LEN:.*]] = llvm.sdiv %[[VAL_16_BYTESIZE]], %[[VAL_13_WIDTH]]  : i64
 // CHECK:           %[[VAL_32:.*]] = llvm.mlir.constant(44 : i32) : i32
 // CHECK:           %[[VAL_33:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:           %[[VAL_34:.*]] = llvm.getelementptr %[[VAL_33]][1] : (!llvm.ptr) -> !llvm.ptr, i32
-// CHECK:           %[[VAL_35:.*]] = llvm.ptrtoint %[[VAL_34]] : !llvm.ptr to i64
+// CHECK:           %[[VAL_35:.*]] = ptr.ptrtoint %[[VAL_34]] : !llvm.ptr to i64
 // CHECK:           %[[VAL_36_BYTESIZE:.*]] = llvm.mul %[[VAL_35]], %[[VAL_31_LEN]]  : i64
 // CHECK:           %[[VAL_37:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
 // CHECK:           %[[VAL_38:.*]] = llvm.insertvalue %[[VAL_36_BYTESIZE]], %[[VAL_37]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
@@ -91,7 +91,7 @@
 // CHECK:           %[[VAL_81:.*]] = llvm.mul %[[VAL_67]], %[[VAL_20_EX1]]  : i64
 // CHECK:           %[[VAL_82:.*]] = llvm.getelementptr %[[VAL_24_BASEPTR]]{{\[}}%[[VAL_70_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
 // CHECK:           %[[VAL_84:.*]] = llvm.insertvalue %[[VAL_82]], %[[VAL_79]][0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           llvm.store %[[VAL_84]], %[[VAL_8]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:           ptr.store %[[VAL_84]], %[[VAL_8]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
 // CHECK:           llvm.return
 // CHECK:         }
 func.func @test_char4(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.char<4,?>>>>>, %arg1 : index, %arg2 : index, %arg3 : index, %arg4 : index, %arg5 : index, %arg6 : index) {
@@ -117,28 +117,28 @@ func.func @test_char4(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.cha
 // CHECK:           %[[VAL_10:.*]] = llvm.alloca %[[VAL_9]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
 // CHECK:           %[[VAL_11:.*]] = llvm.mlir.constant(0 : index) : i64
 // CHECK:           %[[VAL_12_c1:.*]] = llvm.mlir.constant(1 : index) : i64
-// CHECK:           %[[VAL_14:.*]] = llvm.load %[[VAL_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           llvm.store %[[VAL_14]], %[[VAL_10]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:           %[[VAL_14:.*]] = ptr.load %[[VAL_0]] : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
+// CHECK:           ptr.store %[[VAL_14]], %[[VAL_10]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
 // CHECK:           %[[VAL_15:.*]] = llvm.getelementptr %[[VAL_10]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_16_BYTESIZE:.*]] = llvm.load %[[VAL_15]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_16_BYTESIZE:.*]] = ptr.load %[[VAL_15]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_17:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_12]], 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_18_LB1:.*]] = llvm.load %[[VAL_17]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_18_LB1:.*]] = ptr.load %[[VAL_17]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_19:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_12]], 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_20_EX1:.*]] = llvm.load %[[VAL_19]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_20_EX1:.*]] = ptr.load %[[VAL_19]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_21:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_12]], 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_22_ST1:.*]] = llvm.load %[[VAL_21]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_22_ST1:.*]] = ptr.load %[[VAL_21]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_23:.*]] = llvm.getelementptr %[[VAL_10]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_24_BASEPTR:.*]] = llvm.load %[[VAL_23]] : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_24_BASEPTR:.*]] = ptr.load %[[VAL_23]] : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_25:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_11]], 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_26_LB0:.*]] = llvm.load %[[VAL_25]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_26_LB0:.*]] = ptr.load %[[VAL_25]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_27:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_11]], 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_28_EX0:.*]] = llvm.load %[[VAL_27]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_28_EX0:.*]] = ptr.load %[[VAL_27]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_29:.*]] = llvm.getelementptr %[[VAL_10]][0, 7, %[[VAL_11]], 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           %[[VAL_30_ST0:.*]] = llvm.load %[[VAL_29]] : !llvm.ptr -> i64
+// CHECK:           %[[VAL_30_ST0:.*]] = ptr.load %[[VAL_29]] : !llvm.ptr -> i64
 // CHECK:           %[[VAL_32:.*]] = llvm.mlir.constant(40 : i32) : i32
 // CHECK:           %[[VAL_33:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:           %[[VAL_34:.*]] = llvm.getelementptr %[[VAL_33]][1] : (!llvm.ptr) -> !llvm.ptr, i8
-// CHECK:           %[[VAL_35:.*]] = llvm.ptrtoint %[[VAL_34]] : !llvm.ptr to i64
+// CHECK:           %[[VAL_35:.*]] = ptr.ptrtoint %[[VAL_34]] : !llvm.ptr to i64
 // CHECK:           %[[VAL_36_BYTESIZE:.*]] = llvm.mul %[[VAL_35]], %[[VAL_16_BYTESIZE]]  : i64
 // CHECK:           %[[VAL_37:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
 // CHECK:           %[[VAL_38:.*]] = llvm.insertvalue %[[VAL_36_BYTESIZE]], %[[VAL_37]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
@@ -187,7 +187,7 @@ func.func @test_char4(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.cha
 // CHECK:           %[[VAL_81:.*]] = llvm.mul %[[VAL_67]], %[[VAL_20_EX1]]  : i64
 // CHECK:           %[[VAL_82:.*]] = llvm.getelementptr %[[VAL_24_BASEPTR]]{{\[}}%[[VAL_70_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
 // CHECK:           %[[VAL_84:.*]] = llvm.insertvalue %[[VAL_82]], %[[VAL_79]][0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>
-// CHECK:           llvm.store %[[VAL_84]], %[[VAL_8]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
+// CHECK:           ptr.store %[[VAL_84]], %[[VAL_8]] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<2 x array<3 x i64>>)>, !llvm.ptr
 // CHECK:           llvm.return
 // CHECK:         }
 func.func @test_char1(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.char<1,?>>>>>, %arg1 : index, %arg2 : index, %arg3 : index, %arg4 : index, %arg5 : index, %arg6 : index) {
diff --git a/flang/test/Fir/embox-substring.fir b/flang/test/Fir/embox-substring.fir
index f2042f9bda7fc4..882c1b2a2255ce 100644
--- a/flang/test/Fir/embox-substring.fir
+++ b/flang/test/Fir/embox-substring.fir
@@ -32,7 +32,7 @@ func.func private @dump(!fir.box<!fir.array<2x!fir.char<1>>>)
 // CHECK:           llvm.getelementptr
 // CHECK:           %[[VAL_28:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK:           %[[VAL_29:.*]] = llvm.getelementptr %[[VAL_28]][1] : (!llvm.ptr) -> !llvm.ptr, i8
-// CHECK:           %[[VAL_30:.*]] = llvm.ptrtoint %[[VAL_29]] : !llvm.ptr to i64
+// CHECK:           %[[VAL_30:.*]] = ptr.ptrtoint %[[VAL_29]] : !llvm.ptr to i64
 // CHECK:           %[[VAL_31:.*]] = llvm.mul %[[VAL_30]], %[[VAL_1]]  : i64
 // CHECK:           %[[VAL_42:.*]] = llvm.mul %[[VAL_31]], %[[VAL_5]]  : i64
 // CHECK:           %[[VAL_43:.*]] = llvm.insertvalue %[[VAL_42]], %{{.*}}[7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
diff --git a/flang/test/Fir/rebox-susbtring.fir b/flang/test/Fir/rebox-susbtring.fir
index 8f7f4facd13a27..d9c744e3ae40bc 100644
--- a/flang/test/Fir/rebox-susbtring.fir
+++ b/flang/test/Fir/rebox-susbtring.fir
@@ -21,7 +21,7 @@ func.func @char_section(%arg0: !fir.box<!fir.array<?x!fir.char<1,20>>>) {
 // CHECK:         %[[VAL_4:.*]] = llvm.mlir.constant(1 : i64) : i64
 
 // CHECK:         %[[VAL_37:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<{{.*}}>
-// CHECK:         %[[VAL_38:.*]] = llvm.load %[[VAL_37]] : !llvm.ptr -> !llvm.ptr
+// CHECK:         %[[VAL_38:.*]] = ptr.load %[[VAL_37]] : !llvm.ptr -> !llvm.ptr
 // CHECK:         %[[VAL_30:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:         %[[VAL_40:.*]] = llvm.getelementptr %[[VAL_38]]{{\[}}%[[VAL_30]], %[[VAL_4]]] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<20 x i8>
 
@@ -51,7 +51,7 @@ func.func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}
 // CHECK:         %[[VAL_1:.*]] = llvm.mlir.constant(1 : i32) : i32
 
 // CHECK:         %[[VAL_30:.*]] = llvm.getelementptr %[[VAL_0]]{{\[}}0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<{{.*}}>
-// CHECK:         %[[VAL_31:.*]] = llvm.load %[[VAL_30]] : !llvm.ptr -> !llvm.ptr
+// CHECK:         %[[VAL_31:.*]] = ptr.load %[[VAL_30]] : !llvm.ptr -> !llvm.ptr
 // CHECK:         %[[VAL_21:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:         %[[VAL_33:.*]] = llvm.getelementptr %[[VAL_31]]{{\[}}%[[VAL_21]], 1, %[[VAL_4]]] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.struct<{{.*}}>
 
diff --git a/flang/test/Fir/tbaa-codegen.fir b/flang/test/Fir/tbaa-codegen.fir
index 87bb15c0fea6ca..116bc65afaaf75 100644
--- a/flang/test/Fir/tbaa-codegen.fir
+++ b/flang/test/Fir/tbaa-codegen.fir
@@ -7,12 +7,12 @@
 //   integer, intent(inout) :: a(:)
 //   a(1) = a(2)
 // end subroutine
-#tbaa_root = #llvm.tbaa_root<id = "Flang function root _QPsimple">
-#tbaa_type_desc = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
-#tbaa_type_desc1 = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
-#tbaa_type_desc2 = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc1, 0>}>
-#tbaa_type_desc3 = #llvm.tbaa_type_desc<id = "dummy arg data/_QFfuncEa", members = {<#tbaa_type_desc2, 0>}>
-#tbaa_tag = #llvm.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
+#tbaa_root = #ptr.tbaa_root<id = "Flang function root _QPsimple">
+#tbaa_type_desc = #ptr.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+#tbaa_type_desc1 = #ptr.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+#tbaa_type_desc2 = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc1, 0>}>
+#tbaa_type_desc3 = #ptr.tbaa_type_desc<id = "dummy arg data/_QFfuncEa", members = {<#tbaa_type_desc2, 0>}>
+#tbaa_tag = #ptr.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
 module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "aarch64-unknown-linux-gnu"} {
   func.func @_QPsimple(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}) {
     %c1 = arith.constant 1 : index
diff --git a/flang/test/Fir/tbaa-codegen2.fir b/flang/test/Fir/tbaa-codegen2.fir
index e649c06731c6ba..ffa07c0a625057 100644
--- a/flang/test/Fir/tbaa-codegen2.fir
+++ b/flang/test/Fir/tbaa-codegen2.fir
@@ -8,12 +8,12 @@
 //   integer, intent(inout) :: a(:)
 //   a = a+1
 //   a(1) = a(2)
-#tbaa_root = #llvm.tbaa_root<id = "Flang function root _QPfunc">
-#tbaa_type_desc = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
-#tbaa_type_desc1 = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
-#tbaa_type_desc2 = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc1, 0>}>
-#tbaa_type_desc3 = #llvm.tbaa_type_desc<id = "dummy arg data/_QFfuncEa", members = {<#tbaa_type_desc2, 0>}>
-#tbaa_tag = #llvm.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
+#tbaa_root = #ptr.tbaa_root<id = "Flang function root _QPfunc">
+#tbaa_type_desc = #ptr.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+#tbaa_type_desc1 = #ptr.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+#tbaa_type_desc2 = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc1, 0>}>
+#tbaa_type_desc3 = #ptr.tbaa_type_desc<id = "dummy arg data/_QFfuncEa", members = {<#tbaa_type_desc2, 0>}>
+#tbaa_tag = #ptr.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
 module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "aarch64-unknown-linux-gnu"} {
   func.func @_QPfunc(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}) {
     %c3_i32 = arith.constant 3 : i32
diff --git a/flang/test/Fir/tbaa.fir b/flang/test/Fir/tbaa.fir
index 048f53f5c6e47a..40ab889159371d 100644
--- a/flang/test/Fir/tbaa.fir
+++ b/flang/test/Fir/tbaa.fir
@@ -22,12 +22,12 @@ module {
   }
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[ANYDACC:.*]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
-// CHECK-DAG:     #[[$DATAT:.*]] = #llvm.tbaa_tag<base_type = #[[ANYDACC]], access_type = #[[ANYDACC]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[ANYDACC:.*]] = #ptr.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[$DATAT:.*]] = #ptr.tbaa_tag<base_type = #[[ANYDACC]], access_type = #[[ANYDACC]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa(
 // CHECK-SAME:                    %[[VAL_0:.*]]: !llvm.ptr {fir.bindc_name = "a"}) {
@@ -37,21 +37,21 @@ module {
 // CHECK:           %[[VAL_4:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:           %[[VAL_5:.*]] = llvm.mlir.constant(10 : i32) : i32
 // CHECK:           %[[VAL_6:.*]] = llvm.getelementptr %[[VAL_0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_7:.*]] = llvm.load %[[VAL_6]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_7:.*]] = ptr.load %[[VAL_6]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_8:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:           %[[VAL_9:.*]] = llvm.getelementptr %[[VAL_0]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_10:.*]] = llvm.load %[[VAL_9]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_10:.*]] = ptr.load %[[VAL_9]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_11:.*]] = llvm.mul %[[VAL_4]], %[[VAL_10]] overflow<nsw> : i64
 // CHECK:           %[[VAL_12:.*]] = llvm.add %[[VAL_11]], %[[VAL_8]] overflow<nsw> : i64
 // CHECK:           %[[VAL_14:.*]] = llvm.getelementptr %[[VAL_7]]{{\[}}%[[VAL_12]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
 // CHECK:           %[[VAL_16:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:           %[[VAL_17:.*]] = llvm.mlir.constant(-1 : i32) : i32
 // CHECK:           %[[VAL_18:.*]] = llvm.getelementptr %[[VAL_0]][0, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_19:.*]] = llvm.load %[[VAL_18]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_19:.*]] = ptr.load %[[VAL_18]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_20:.*]] = llvm.getelementptr %[[VAL_0]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_21:.*]] = llvm.load %[[VAL_20]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_21:.*]] = ptr.load %[[VAL_20]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_22:.*]] = llvm.getelementptr %[[VAL_0]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_23:.*]] = llvm.load %[[VAL_22]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
+// CHECK:           %[[VAL_23:.*]] = ptr.load %[[VAL_22]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
 // CHECK:           %[[VAL_24:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_25:.*]] = llvm.insertvalue %[[VAL_21]], %[[VAL_24]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_26:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -70,15 +70,15 @@ module {
 // CHECK:           %[[VAL_40B:.*]] = llvm.insertvalue %[[VAL_19]], %[[VAL_38]][7] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_40:.*]] = llvm.insertvalue %{{.*}}, %[[VAL_40B]][8, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_42:.*]] = llvm.insertvalue %[[VAL_14]], %[[VAL_40]][0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
-// CHECK:           llvm.store %[[VAL_42]], %[[VAL_2]] {tbaa = [#[[$BOXT]]]} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr
+// CHECK:           ptr.store %[[VAL_42]], %[[VAL_2]] {tbaa = [#[[$BOXT]]]} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>, !llvm.ptr
 // CHECK:           %[[VAL_43:.*]] = llvm.getelementptr %[[VAL_2]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_44:.*]] = llvm.load %[[VAL_43]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i8
+// CHECK:           %[[VAL_44:.*]] = ptr.load %[[VAL_43]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i8
 // CHECK:           %[[VAL_45:.*]] = llvm.icmp "eq" %[[VAL_44]], %[[VAL_3]] : i8
 // CHECK:           llvm.cond_br %[[VAL_45]], ^bb1, ^bb2
 // CHECK:         ^bb1:
 // CHECK:           %[[VAL_46:.*]] = llvm.getelementptr %[[VAL_2]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_47:.*]] = llvm.load %[[VAL_46]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
-// CHECK:           llvm.store %[[VAL_5]], %[[VAL_47]] {tbaa = [#[[$DATAT]]]} : i32, !llvm.ptr
+// CHECK:           %[[VAL_47:.*]] = ptr.load %[[VAL_46]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           ptr.store %[[VAL_5]], %[[VAL_47]] {tbaa = [#[[$DATAT]]]} : i32, !llvm.ptr
 // CHECK:           llvm.br ^bb2
 // CHECK:         ^bb2:
 // CHECK:           llvm.return
@@ -118,10 +118,10 @@ module {
   }
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa() {
 // CHECK:           %[[VAL_0:.*]] = llvm.mlir.constant(1 : i32) : i32
@@ -134,24 +134,24 @@ module {
 // CHECK:           %[[VAL_7:.*]] = llvm.mlir.addressof @_QFEx : !llvm.ptr
 // CHECK:           %[[VAL_8:.*]] = llvm.mlir.addressof @_QQclX2E2F64756D6D792E66393000 : !llvm.ptr
 // CHECK:           %[[VAL_10:.*]] = llvm.call @_FortranAioBeginExternalListOutput(%[[VAL_6]], %[[VAL_8]], %[[VAL_5]]) {fastmathFlags = #llvm.fastmath<contract>} : (i32, !llvm.ptr, i32) -> !llvm.ptr
-// CHECK:           %[[VAL_11:.*]] = llvm.load %[[VAL_7]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           llvm.store %[[VAL_11]], %[[VAL_3]] {tbaa = [#[[$BOXT]]]} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>, !llvm.ptr
+// CHECK:           %[[VAL_11:.*]] = ptr.load %[[VAL_7]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
+// CHECK:           ptr.store %[[VAL_11]], %[[VAL_3]] {tbaa = [#[[$BOXT]]]} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>, !llvm.ptr
 // CHECK:           %[[VAL_12:.*]] = llvm.getelementptr %[[VAL_3]][0, 7, %[[VAL_4]], 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_13:.*]] = llvm.load %[[VAL_12]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_13:.*]] = ptr.load %[[VAL_12]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_14:.*]] = llvm.getelementptr %[[VAL_3]][0, 7, %[[VAL_4]], 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_15:.*]] = llvm.load %[[VAL_14]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_15:.*]] = ptr.load %[[VAL_14]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_16:.*]] = llvm.getelementptr %[[VAL_3]][0, 7, %[[VAL_4]], 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_17:.*]] = llvm.load %[[VAL_16]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_17:.*]] = ptr.load %[[VAL_16]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_18:.*]] = llvm.getelementptr %[[VAL_3]][0, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_19:.*]] = llvm.load %[[VAL_18]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_19:.*]] = ptr.load %[[VAL_18]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_20:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:           %[[VAL_21:.*]] = llvm.mlir.constant(-1 : i32) : i32
 // CHECK:           %[[VAL_22:.*]] = llvm.getelementptr %[[VAL_3]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_23:.*]] = llvm.load %[[VAL_22]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_23:.*]] = ptr.load %[[VAL_22]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_24:.*]] = llvm.getelementptr %[[VAL_3]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_25:.*]] = llvm.load %[[VAL_24]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
+// CHECK:           %[[VAL_25:.*]] = ptr.load %[[VAL_24]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
 // CHECK:           %[[VAL_26:.*]] = llvm.getelementptr %[[VAL_3]][0, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_27:.*]] = llvm.load %[[VAL_26]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_27:.*]] = ptr.load %[[VAL_26]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_28:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_29:.*]] = llvm.insertvalue %[[VAL_23]], %[[VAL_28]][1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_30:.*]] = llvm.mlir.constant(20180515 : i32) : i32
@@ -170,13 +170,13 @@ module {
 // CHECK:           %[[VAL_44B:.*]] = llvm.insertvalue %[[VAL_27]], %[[VAL_42]][8] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_44:.*]] = llvm.insertvalue %{{.*}}, %[[VAL_44B]][9, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_45:.*]] = llvm.getelementptr %[[VAL_3]][0, 7, 0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_46:.*]] = llvm.load %[[VAL_45]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_46:.*]] = ptr.load %[[VAL_45]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_47:.*]] = llvm.getelementptr %[[VAL_3]][0, 7, 0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_48:.*]] = llvm.load %[[VAL_47]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_48:.*]] = ptr.load %[[VAL_47]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_49:.*]] = llvm.getelementptr %[[VAL_3]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_50:.*]] = llvm.load %[[VAL_49]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_50:.*]] = ptr.load %[[VAL_49]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_51:.*]] = llvm.getelementptr %[[VAL_3]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           %[[VAL_52:.*]] = llvm.load %[[VAL_51]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_52:.*]] = ptr.load %[[VAL_51]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_53:.*]] = llvm.mlir.constant(0 : i64) : i64
 // CHECK:           %[[VAL_54:.*]] = llvm.mlir.constant(1 : i64) : i64
 // CHECK:           %[[VAL_55:.*]] = llvm.icmp "eq" %[[VAL_48]], %[[VAL_53]] : i64
@@ -185,7 +185,7 @@ module {
 // CHECK:           %[[VAL_58:.*]] = llvm.insertvalue %[[VAL_48]], %[[VAL_57]][7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_59:.*]] = llvm.insertvalue %[[VAL_50]], %[[VAL_58]][7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
 // CHECK:           %[[VAL_61:.*]] = llvm.insertvalue %[[VAL_52]], %[[VAL_59]][0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>
-// CHECK:           llvm.store %[[VAL_61]], %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>, !llvm.ptr
+// CHECK:           ptr.store %[[VAL_61]], %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>, ptr, array<1 x i64>)>, !llvm.ptr
 // CHECK:           %[[VAL_63:.*]] = llvm.call @_FortranAioOutputDescriptor(%[[VAL_10]], %[[VAL_1]]) {fastmathFlags = #llvm.fastmath<contract>} : (!llvm.ptr, !llvm.ptr) -> i1
 // CHECK:           %[[VAL_64:.*]] = llvm.call @_FortranAioEndIoStatement(%[[VAL_10]]) {fastmathFlags = #llvm.fastmath<contract>} : (!llvm.ptr) -> i32
 // CHECK:           llvm.return
@@ -240,15 +240,15 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<*:f64>>) -> i32 {
   return %0 : i32
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa(
 // CHECK-SAME:                    %[[VAL_0:.*]]: !llvm.ptr) -> i32 {
 // CHECK:           %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
-// CHECK:           %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
+// CHECK:           %[[VAL_2:.*]] = ptr.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
 // CHECK:           llvm.return %[[VAL_2]] : i32
 // CHECK:         }
 
@@ -259,15 +259,15 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
   return %0 : i1
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa(
 // CHECK-SAME:                    %[[VAL_0:.*]]: !llvm.ptr) -> i1 {
 // CHECK:           %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
-// CHECK:           %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
+// CHECK:           %[[VAL_2:.*]] = ptr.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
 // CHECK:           %[[VAL_3:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK:           %[[VAL_4:.*]] = llvm.icmp "ne" %[[VAL_2]], %[[VAL_3]] : i32
 // CHECK:           llvm.return %[[VAL_4]] : i1
@@ -280,15 +280,15 @@ func.func @tbaa(%arg0: !fir.box<f32>) -> i32 {
   return %0 : i32
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa(
 // CHECK-SAME:                               %[[VAL_0:.*]]: !llvm.ptr) -> i32 {
 // CHECK:           %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
-// CHECK:           %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
+// CHECK:           %[[VAL_2:.*]] = ptr.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
 // CHECK:           llvm.return %[[VAL_2]] : i32
 // CHECK:         }
 
@@ -299,15 +299,15 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
   return %0 : i1
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa(
 // CHECK-SAME:                    %[[VAL_0:.*]]: !llvm.ptr) -> i1 {
 // CHECK:           %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
-// CHECK:           %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
+// CHECK:           %[[VAL_2:.*]] = ptr.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32
 // CHECK:           %[[VAL_3:.*]] = llvm.mlir.constant(2 : i32) : i32
 // CHECK:           %[[VAL_4:.*]] = llvm.and %[[VAL_2]], %[[VAL_3]]  : i32
 // CHECK:           %[[VAL_5:.*]] = llvm.mlir.constant(0 : i32) : i32
@@ -323,10 +323,10 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<?xi32>>) {
   return
 }
 
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
-// CHECK-DAG:     #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[BOXMEM:.*]] = #ptr.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}>
+// CHECK-DAG:     #[[$BOXT:.*]] = #ptr.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0>
 
 // CHECK-LABEL:   llvm.func @tbaa(
 // CHECK-SAME:                    %[[VAL_0:.*]]: !llvm.ptr) {
@@ -336,11 +336,11 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<?xi32>>) {
 // CHECK:           %[[VAL_4:.*]] = llvm.sub %[[VAL_1]], %[[VAL_2]] overflow<nsw> : i64
 // CHECK:           %[[VAL_5:.*]] = llvm.mul %[[VAL_4]], %[[VAL_2]] overflow<nsw> : i64
 // CHECK:           %[[VAL_6:.*]] = llvm.getelementptr %[[VAL_0]][0, 7, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-// CHECK:           %[[VAL_7:.*]] = llvm.load %[[VAL_6]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
+// CHECK:           %[[VAL_7:.*]] = ptr.load %[[VAL_6]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i64
 // CHECK:           %[[VAL_8:.*]] = llvm.mul %[[VAL_5]], %[[VAL_7]] overflow<nsw> : i64
 // CHECK:           %[[VAL_9:.*]] = llvm.add %[[VAL_8]], %[[VAL_3]] overflow<nsw> : i64
 // CHECK:           %[[VAL_10:.*]] = llvm.getelementptr %[[VAL_0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-// CHECK:           %[[VAL_11:.*]] = llvm.load %[[VAL_10]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
+// CHECK:           %[[VAL_11:.*]] = ptr.load %[[VAL_10]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> !llvm.ptr
 // CHECK:           %[[VAL_13:.*]] = llvm.getelementptr %[[VAL_11]]{{\[}}%[[VAL_9]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
 // CHECK:           llvm.return
 // CHECK:         }
@@ -349,9 +349,9 @@ func.func @tbaa(%arg0: !fir.box<!fir.array<?xi32>>) {
 
 // Check that the scalar aggregate load/store with a descriptor member
 // is mapped to any-access.
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[$ANYT:.*]] = #llvm.tbaa_tag<base_type = #[[ANYACC]], access_type = #[[ANYACC]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[$ANYT:.*]] = #ptr.tbaa_tag<base_type = #[[ANYACC]], access_type = #[[ANYACC]], offset = 0>
 
 func.func @tbaa(%arg0: !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>, %arg1: !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>) {
   %0 = fir.load %arg0 : !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>
@@ -359,16 +359,16 @@ func.func @tbaa(%arg0: !fir.ref<!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}
   return
 }
 // CHECK-LABEL:   llvm.func @tbaa(
-// CHECK: llvm.load{{.*}}{tbaa = [#[[$ANYT]]]}
-// CHECK: llvm.store{{.*}}{tbaa = [#[[$ANYT]]]}
+// CHECK: ptr.load{{.*}}{tbaa = [#[[$ANYT]]]}
+// CHECK: ptr.store{{.*}}{tbaa = [#[[$ANYT]]]}
 
 // -----
 
 // Check that the array aggregate load/store with a descriptor member
 // is mapped to any-access.
-// CHECK-DAG:     #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root ">
-// CHECK-DAG:     #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK-DAG:     #[[$ANYT:.*]] = #llvm.tbaa_tag<base_type = #[[ANYACC]], access_type = #[[ANYACC]], offset = 0>
+// CHECK-DAG:     #[[ROOT:.*]] = #ptr.tbaa_root<id = "Flang function root ">
+// CHECK-DAG:     #[[ANYACC:.*]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK-DAG:     #[[$ANYT:.*]] = #ptr.tbaa_tag<base_type = #[[ANYACC]], access_type = #[[ANYACC]], offset = 0>
 
 func.func @tbaa(%arg0: !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>, %arg1: !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>) {
   %0 = fir.load %arg0 : !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>
@@ -376,5 +376,5 @@ func.func @tbaa(%arg0: !fir.ref<!fir.array<2x!fir.type<_QMtypesTt{x:!fir.box<!fi
   return
 }
 // CHECK-LABEL:   llvm.func @tbaa(
-// CHECK: llvm.load{{.*}}{tbaa = [#[[$ANYT]]]}
-// CHECK: llvm.store{{.*}}{tbaa = [#[[$ANYT]]]}
+// CHECK: ptr.load{{.*}}{tbaa = [#[[$ANYT]]]}
+// CHECK: ptr.store{{.*}}{tbaa = [#[[$ANYT]]]}
diff --git a/flang/test/Lower/OpenMP/FIR/flush.f90 b/flang/test/Lower/OpenMP/FIR/flush.f90
index 2868367fbdba64..f581243626023f 100644
--- a/flang/test/Lower/OpenMP/FIR/flush.f90
+++ b/flang/test/Lower/OpenMP/FIR/flush.f90
@@ -33,10 +33,10 @@ subroutine flush_parallel(a, b, c)
 !FIRDialect: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i32
 !FIRDialect: fir.store %{{.*}} to %{{.*}} : !fir.ref<i32>
 
-!LLVMIRDialect: %{{.*}} = llvm.load %{{.*}} : !llvm.ptr -> i32
-!LLVMIRDialect: %{{.*}} = llvm.load %{{.*}} : !llvm.ptr -> i32
+!LLVMIRDialect: %{{.*}} = ptr.load %{{.*}} : !llvm.ptr -> i32
+!LLVMIRDialect: %{{.*}} = ptr.load %{{.*}} : !llvm.ptr -> i32
 !LLVMIRDialect: %{{.*}} = llvm.add %{{.*}}, %{{.*}} : i32
-!LLVMIRDialect: llvm.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
+!LLVMIRDialect: ptr.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
     c = a + b
 
 !OMPDialect: omp.terminator
diff --git a/flang/test/Transforms/tbaa.fir b/flang/test/Transforms/tbaa.fir
index 7825ae60c71e68..99f2b88624b0c2 100644
--- a/flang/test/Transforms/tbaa.fir
+++ b/flang/test/Transforms/tbaa.fir
@@ -16,12 +16,12 @@
     return
   }
 
-// CHECK: #[[ONE_ARG_ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPonearg">
-// CHECK: #[[ONE_ARG_ANY_ACCESS:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ONE_ARG_ROOT]], 0>}>
-// CHECK: #[[ONE_ARG_ANY_DATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ONE_ARG_ANY_ACCESS]], 0>}>
-// CHECK: #[[ONE_ARG_ANY_ARG:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[ONE_ARG_ANY_DATA]], 0>}>
-// CHECK: #[[ONE_ARG_A:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFoneargEa", members = {<#[[ONE_ARG_ANY_ARG]], 0>}>
-// CHECK: #[[ONE_ARG_A_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[ONE_ARG_A]], access_type = #[[ONE_ARG_A]], offset = 0>
+// CHECK: #[[ONE_ARG_ROOT:.+]] = #ptr.tbaa_root<id = "Flang function root _QPonearg">
+// CHECK: #[[ONE_ARG_ANY_ACCESS:.+]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ONE_ARG_ROOT]], 0>}>
+// CHECK: #[[ONE_ARG_ANY_DATA:.+]] = #ptr.tbaa_type_desc<id = "any data access", members = {<#[[ONE_ARG_ANY_ACCESS]], 0>}>
+// CHECK: #[[ONE_ARG_ANY_ARG:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#[[ONE_ARG_ANY_DATA]], 0>}>
+// CHECK: #[[ONE_ARG_A:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QFoneargEa", members = {<#[[ONE_ARG_ANY_ARG]], 0>}>
+// CHECK: #[[ONE_ARG_A_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[ONE_ARG_A]], access_type = #[[ONE_ARG_A]], offset = 0>
 
 // CHECK-LABEL:   func.func @_QPonearg(
 // CHECK-SAME:                         %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}) {
@@ -55,14 +55,14 @@
     return
   }
 
-// CHECK: #[[TWO_ARG_ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtwoarg">
-// CHECK: #[[TWO_ARG_ANY_ACCESS:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TWO_ARG_ROOT]], 0>}>
-// CHECK: #[[TWO_ARG_ANY_DATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[TWO_ARG_ANY_ACCESS]], 0>}>
-// CHECK: #[[TWO_ARG_ANY_ARG:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[TWO_ARG_ANY_DATA]], 0>}>
-// CHECK: #[[TWO_ARG_B:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtwoargEb", members = {<#[[TWO_ARG_ANY_ARG]], 0>}>
-// CHECK: #[[TWO_ARG_A:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtwoargEa", members = {<#[[TWO_ARG_ANY_ARG]], 0>}>
-// CHECK: #[[TWO_ARG_B_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[TWO_ARG_B]], access_type = #[[TWO_ARG_B]], offset = 0>
-// CHECK: #[[TWO_ARG_A_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[TWO_ARG_A]], access_type = #[[TWO_ARG_A]], offset = 0>
+// CHECK: #[[TWO_ARG_ROOT:.+]] = #ptr.tbaa_root<id = "Flang function root _QPtwoarg">
+// CHECK: #[[TWO_ARG_ANY_ACCESS:.+]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[TWO_ARG_ROOT]], 0>}>
+// CHECK: #[[TWO_ARG_ANY_DATA:.+]] = #ptr.tbaa_type_desc<id = "any data access", members = {<#[[TWO_ARG_ANY_ACCESS]], 0>}>
+// CHECK: #[[TWO_ARG_ANY_ARG:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#[[TWO_ARG_ANY_DATA]], 0>}>
+// CHECK: #[[TWO_ARG_B:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QFtwoargEb", members = {<#[[TWO_ARG_ANY_ARG]], 0>}>
+// CHECK: #[[TWO_ARG_A:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QFtwoargEa", members = {<#[[TWO_ARG_ANY_ARG]], 0>}>
+// CHECK: #[[TWO_ARG_B_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[TWO_ARG_B]], access_type = #[[TWO_ARG_B]], offset = 0>
+// CHECK: #[[TWO_ARG_A_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[TWO_ARG_A]], access_type = #[[TWO_ARG_A]], offset = 0>
 
 // CHECK-LABEL:   func.func @_QPtwoarg(
 // CHECK-SAME:                         %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"},
@@ -99,12 +99,12 @@
     return
   }
 
-// CHECK: #[[TARGET_ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtargetarg">
-// CHECK: #[[TARGET_ANY_ACCESS:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TARGET_ROOT]], 0>}>
-// CHECK: #[[TARGET_ANY_DATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[TARGET_ANY_ACCESS]], 0>}>
-// CHECK: #[[TARGET_ANY_ARG:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[TARGET_ANY_DATA]], 0>}>
-// CHECK: #[[TARGET_B:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtargetargEb", members = {<#[[TARGET_ANY_ARG]], 0>}>
-// CHECK: #[[TARGET_B_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[TARGET_B]], access_type = #[[TARGET_B]], offset = 0>
+// CHECK: #[[TARGET_ROOT:.+]] = #ptr.tbaa_root<id = "Flang function root _QPtargetarg">
+// CHECK: #[[TARGET_ANY_ACCESS:.+]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[TARGET_ROOT]], 0>}>
+// CHECK: #[[TARGET_ANY_DATA:.+]] = #ptr.tbaa_type_desc<id = "any data access", members = {<#[[TARGET_ANY_ACCESS]], 0>}>
+// CHECK: #[[TARGET_ANY_ARG:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#[[TARGET_ANY_DATA]], 0>}>
+// CHECK: #[[TARGET_B:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QFtargetargEb", members = {<#[[TARGET_ANY_ARG]], 0>}>
+// CHECK: #[[TARGET_B_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[TARGET_B]], access_type = #[[TARGET_B]], offset = 0>
 // No entry for "dummy arg data/a" because that pointer should get "any data access" becase it has the TARGET attribute
 
 // CHECK-LABEL:   func.func @_QPtargetarg(
@@ -146,12 +146,12 @@
     return
   }
 
-// CHECK: #[[POINTER_ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPpointerarg">
-// CHECK: #[[POINTER_ANY_ACCESS:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[POINTER_ROOT]], 0>}>
-// CHECK: #[[POINTER_ANY_DATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[POINTER_ANY_ACCESS]], 0>}>
-// CHECK: #[[POINTER_ANY_ARG:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[POINTER_ANY_DATA]], 0>}>
-// CHECK: #[[POINTER_B:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFpointerargEb", members = {<#[[POINTER_ANY_ARG]], 0>}>
-// CHECK: #[[POINTER_B_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[POINTER_B]], access_type = #[[POINTER_B]], offset = 0>
+// CHECK: #[[POINTER_ROOT:.+]] = #ptr.tbaa_root<id = "Flang function root _QPpointerarg">
+// CHECK: #[[POINTER_ANY_ACCESS:.+]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[POINTER_ROOT]], 0>}>
+// CHECK: #[[POINTER_ANY_DATA:.+]] = #ptr.tbaa_type_desc<id = "any data access", members = {<#[[POINTER_ANY_ACCESS]], 0>}>
+// CHECK: #[[POINTER_ANY_ARG:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#[[POINTER_ANY_DATA]], 0>}>
+// CHECK: #[[POINTER_B:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QFpointerargEb", members = {<#[[POINTER_ANY_ARG]], 0>}>
+// CHECK: #[[POINTER_B_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[POINTER_B]], access_type = #[[POINTER_B]], offset = 0>
 // No entry for "dummy arg data/a" because that pointer should get "any data access" becase it has the POINTER attribute
 
 // CHECK-LABEL:   func.func @_QPpointerarg(
diff --git a/flang/test/Transforms/tbaa2.fir b/flang/test/Transforms/tbaa2.fir
index ab39f65cdade70..e3779144a93d3f 100644
--- a/flang/test/Transforms/tbaa2.fir
+++ b/flang/test/Transforms/tbaa2.fir
@@ -44,35 +44,35 @@
     fir.has_value %0 : i32
   }
 
-// CHECK: #[[ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QMmodPcallee">
-// CHECK: #[[ANY_ACCESS:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
-// CHECK: #[[ANY_DATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANY_ACCESS]], 0>}>
-// CHECK: #[[ANY_GLBL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[ANY_DATA]], 0>}>
-// CHECK: #[[ANY_ARG:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[ANY_DATA]], 0>}>
-// CHECK: #[[ANY_DIRECT:.+]] = #llvm.tbaa_type_desc<id = "direct data", members = {<#[[ANY_DATA]], 0>}>
-// CHECK: #[[GLBL_ZSTART:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmodEzstart", members = {<#[[ANY_GLBL]], 0>}>
-// CHECK: #[[GLBL_ZSTOP:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmodEzstop", members = {<#[[ANY_GLBL]], 0>}>
-// CHECK: #[[GLBL_YSTART:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmodEystart", members = {<#[[ANY_GLBL]], 0>}>
-// CHECK: #[[GLBL_YSTOP:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmodEystop", members = {<#[[ANY_GLBL]], 0>}>
-// CHECK: #[[GLBL_XSTART:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmodExstart", members = {<#[[ANY_GLBL]], 0>}>
-// CHECK: #[[ARG_LOW:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QMmodFcalleeElow", members = {<#[[ANY_ARG]], 0>}>
-// CHECK: #[[DIRECT_A:.+]] = #llvm.tbaa_type_desc<id = "direct data/_QMmodEa", members = {<#[[ANY_DIRECT]], 0>}>
-// CHECK: #[[DIRECT_B:.+]] = #llvm.tbaa_type_desc<id = "direct data/_QMmodEb", members = {<#[[ANY_DIRECT]], 0>}>
-// CHECK: #[[ARG_Z:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QMmodFcalleeEz", members = {<#[[ANY_ARG]], 0>}>
-// CHECK: #[[GLBL_DYINV:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMmodEdyinv", members = {<#[[ANY_GLBL]], 0>}>
-// CHECK: #[[ARG_Y:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QMmodFcalleeEy", members = {<#[[ANY_ARG]], 0>}>
+// CHECK: #[[ROOT:.+]] = #ptr.tbaa_root<id = "Flang function root _QMmodPcallee">
+// CHECK: #[[ANY_ACCESS:.+]] = #ptr.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}>
+// CHECK: #[[ANY_DATA:.+]] = #ptr.tbaa_type_desc<id = "any data access", members = {<#[[ANY_ACCESS]], 0>}>
+// CHECK: #[[ANY_GLBL:.+]] = #ptr.tbaa_type_desc<id = "global data", members = {<#[[ANY_DATA]], 0>}>
+// CHECK: #[[ANY_ARG:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data", members = {<#[[ANY_DATA]], 0>}>
+// CHECK: #[[ANY_DIRECT:.+]] = #ptr.tbaa_type_desc<id = "direct data", members = {<#[[ANY_DATA]], 0>}>
+// CHECK: #[[GLBL_ZSTART:.+]] = #ptr.tbaa_type_desc<id = "global data/_QMmodEzstart", members = {<#[[ANY_GLBL]], 0>}>
+// CHECK: #[[GLBL_ZSTOP:.+]] = #ptr.tbaa_type_desc<id = "global data/_QMmodEzstop", members = {<#[[ANY_GLBL]], 0>}>
+// CHECK: #[[GLBL_YSTART:.+]] = #ptr.tbaa_type_desc<id = "global data/_QMmodEystart", members = {<#[[ANY_GLBL]], 0>}>
+// CHECK: #[[GLBL_YSTOP:.+]] = #ptr.tbaa_type_desc<id = "global data/_QMmodEystop", members = {<#[[ANY_GLBL]], 0>}>
+// CHECK: #[[GLBL_XSTART:.+]] = #ptr.tbaa_type_desc<id = "global data/_QMmodExstart", members = {<#[[ANY_GLBL]], 0>}>
+// CHECK: #[[ARG_LOW:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QMmodFcalleeElow", members = {<#[[ANY_ARG]], 0>}>
+// CHECK: #[[DIRECT_A:.+]] = #ptr.tbaa_type_desc<id = "direct data/_QMmodEa", members = {<#[[ANY_DIRECT]], 0>}>
+// CHECK: #[[DIRECT_B:.+]] = #ptr.tbaa_type_desc<id = "direct data/_QMmodEb", members = {<#[[ANY_DIRECT]], 0>}>
+// CHECK: #[[ARG_Z:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QMmodFcalleeEz", members = {<#[[ANY_ARG]], 0>}>
+// CHECK: #[[GLBL_DYINV:.+]] = #ptr.tbaa_type_desc<id = "global data/_QMmodEdyinv", members = {<#[[ANY_GLBL]], 0>}>
+// CHECK: #[[ARG_Y:.+]] = #ptr.tbaa_type_desc<id = "dummy arg data/_QMmodFcalleeEy", members = {<#[[ANY_ARG]], 0>}>
 
-// CHECK: #[[GLBL_ZSTART_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLBL_ZSTART]], access_type = #[[GLBL_ZSTART]], offset = 0>
-// CHECK: #[[GLBL_ZSTOP_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLBL_ZSTOP]], access_type = #[[GLBL_ZSTOP]], offset = 0>
-// CHECK: #[[GLBL_YSTART_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLBL_YSTART]], access_type = #[[GLBL_YSTART]], offset = 0>
-// CHECK: #[[GLBL_YSTOP_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLBL_YSTOP]], access_type = #[[GLBL_YSTOP]], offset = 0>
-// CHECK: #[[GLBL_XSTART_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLBL_XSTART]], access_type = #[[GLBL_XSTART]], offset = 0>
-// CHECK: #[[ARG_LOW_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[ARG_LOW]], access_type = #[[ARG_LOW]], offset = 0>
-// CHECK: #[[DIRECT_A_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[DIRECT_A]], access_type = #[[DIRECT_A]], offset = 0>
-// CHECK: #[[DIRECT_B_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[DIRECT_B]], access_type = #[[DIRECT_B]], offset = 0>
-// CHECK: #[[ARG_Z_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[ARG_Z]], access_type = #[[ARG_Z]], offset = 0>
-// CHECK: #[[GLBL_DYINV_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLBL_DYINV]], access_type = #[[GLBL_DYINV]], offset = 0>
-// CHECK: #[[ARG_Y_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[ARG_Y]], access_type = #[[ARG_Y]], offset = 0>
+// CHECK: #[[GLBL_ZSTART_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[GLBL_ZSTART]], access_type = #[[GLBL_ZSTART]], offset = 0>
+// CHECK: #[[GLBL_ZSTOP_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[GLBL_ZSTOP]], access_type = #[[GLBL_ZSTOP]], offset = 0>
+// CHECK: #[[GLBL_YSTART_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[GLBL_YSTART]], access_type = #[[GLBL_YSTART]], offset = 0>
+// CHECK: #[[GLBL_YSTOP_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[GLBL_YSTOP]], access_type = #[[GLBL_YSTOP]], offset = 0>
+// CHECK: #[[GLBL_XSTART_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[GLBL_XSTART]], access_type = #[[GLBL_XSTART]], offset = 0>
+// CHECK: #[[ARG_LOW_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[ARG_LOW]], access_type = #[[ARG_LOW]], offset = 0>
+// CHECK: #[[DIRECT_A_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[DIRECT_A]], access_type = #[[DIRECT_A]], offset = 0>
+// CHECK: #[[DIRECT_B_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[DIRECT_B]], access_type = #[[DIRECT_B]], offset = 0>
+// CHECK: #[[ARG_Z_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[ARG_Z]], access_type = #[[ARG_Z]], offset = 0>
+// CHECK: #[[GLBL_DYINV_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[GLBL_DYINV]], access_type = #[[GLBL_DYINV]], offset = 0>
+// CHECK: #[[ARG_Y_TAG:.+]] = #ptr.tbaa_tag<base_type = #[[ARG_Y]], access_type = #[[ARG_Y]], offset = 0>
 
   func.func @_QMmodPcallee(%arg0: !fir.box<!fir.array<?x?x?xf32>> {fir.bindc_name = "z"}, %arg1: !fir.box<!fir.array<?x?x?xf32>> {fir.bindc_name = "y"}, %arg2: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>> {fir.bindc_name = "low"}) {
     %c2 = arith.constant 2 : index
diff --git a/mlir/include/mlir/Dialect/CMakeLists.txt b/mlir/include/mlir/Dialect/CMakeLists.txt
index 2da79011fa26a3..5f0e9806926145 100644
--- a/mlir/include/mlir/Dialect/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/CMakeLists.txt
@@ -28,6 +28,7 @@ add_subdirectory(OpenACCMPCommon)
 add_subdirectory(OpenMP)
 add_subdirectory(PDL)
 add_subdirectory(PDLInterp)
+add_subdirectory(Ptr)
 add_subdirectory(Quant)
 add_subdirectory(SCF)
 add_subdirectory(Shape)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 91bd3702f93b97..82df94a4ebb708 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -11,6 +11,7 @@
 
 include "mlir/Dialect/LLVMIR/LLVMDialect.td"
 include "mlir/Dialect/LLVMIR/LLVMInterfaces.td"
+include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td"
 include "mlir/IR/AttrTypeBase.td"
 include "mlir/IR/CommonAttrConstraints.td"
 
@@ -22,6 +23,27 @@ class LLVM_Attr<string name, string attrMnemonic,
   let mnemonic = attrMnemonic;
 }
 
+//===----------------------------------------------------------------------===//
+// AddressSpaceAttr
+//===----------------------------------------------------------------------===//
+
+def AddressSpaceAttr : LLVM_Attr<"AddressSpace", "address_space", [
+    DeclareAttrInterfaceMethods<MemorySpaceAttrInterface, [
+      "getMemorySpaceDialect",
+      "getDefaultMemorySpace",
+      "getAddressSpace",
+      "isValidLoad",
+      "isValidStore",
+      "isValidAtomicOp",
+      "isValidAtomicXchg",
+      "isValidAddrSpaceCast",
+      "isValidPtrIntCast"
+    ]>
+  ]> {
+  let parameters = (ins DefaultValuedParameter<"unsigned", "0">:$as);
+  let assemblyFormat = "(`<` $as^ `>`)?";
+}
+
 //===----------------------------------------------------------------------===//
 // CConvAttr
 //===----------------------------------------------------------------------===//
@@ -678,271 +700,49 @@ def LLVM_MemoryEffectsAttr : LLVM_Attr<"MemoryEffects", "memory_effects"> {
   let assemblyFormat = "`<` struct(params) `>`";
 }
 
-//===----------------------------------------------------------------------===//
-// AliasScopeDomainAttr
-//===----------------------------------------------------------------------===//
-
-def LLVM_AliasScopeDomainAttr : LLVM_Attr<"AliasScopeDomain",
-                                          "alias_scope_domain"> {
-  let parameters = (ins
-    "DistinctAttr":$id,
-    OptionalParameter<"StringAttr">:$description
-  );
-
-  let builders = [
-    AttrBuilder<(ins CArg<"StringAttr", "{}">:$description), [{
-      return $_get($_ctxt, DistinctAttr::create(UnitAttr::get($_ctxt)), description);
-    }]>
-  ];
-
-  let summary = "LLVM dialect alias scope domain metadata";
-
-  let description = [{
-    Defines a domain that may be associated with an alias scope.
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
-  }];
-
-  let assemblyFormat = "`<` struct(params) `>`";
-}
-
 //===----------------------------------------------------------------------===//
 // AliasScopeAttr
 //===----------------------------------------------------------------------===//
 
-def LLVM_AliasScopeAttr : LLVM_Attr<"AliasScope", "alias_scope"> {
-  let parameters = (ins
-    "DistinctAttr":$id,
-    "AliasScopeDomainAttr":$domain,
-    OptionalParameter<"StringAttr">:$description
-  );
-
-  let builders = [
-    AttrBuilderWithInferredContext<(ins
-      "AliasScopeDomainAttr":$domain,
-      CArg<"StringAttr", "{}">:$description
-    ), [{
-      MLIRContext *ctx = domain.getContext();
-      return $_get(ctx, DistinctAttr::create(UnitAttr::get(ctx)), domain, description);
-    }]>
-  ];
-
-  let description = [{
-    Defines an alias scope that can be attached to a memory-accessing operation.
-    Such scopes can be used in combination with `noalias` metadata to indicate
-    that sets of memory-affecting operations in one scope do not alias with
-    memory-affecting operations in another scope.
-
-    Example:
-    ```mlir
-    #domain = #llvm.alias_scope_domain<id = distinct[1]<>, description = "Optional domain description">
-    #scope1 = #llvm.alias_scope<id = distinct[2]<>, domain = #domain>
-    #scope2 = #llvm.alias_scope<id = distinct[3]<>, domain = #domain, description = "Optional scope description">
-    llvm.func @foo(%ptr1 : !llvm.ptr) {
-        %c0 = llvm.mlir.constant(0 : i32) : i32
-        %c4 = llvm.mlir.constant(4 : i32) : i32
-        %1 = llvm.ptrtoint %ptr1 : !llvm.ptr to i32
-        %2 = llvm.add %1, %c1 : i32
-        %ptr2 = llvm.inttoptr %2 : i32 to !llvm.ptr
-        llvm.store %c0, %ptr1 { alias_scopes = [#scope1], llvm.noalias = [#scope2] } : i32, !llvm.ptr
-        llvm.store %c4, %ptr2 { alias_scopes = [#scope2], llvm.noalias = [#scope1] } : i32, !llvm.ptr
-        llvm.return
-    }
-    ```
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
-  }];
-
-  let summary = "LLVM dialect alias scope";
-
-  let assemblyFormat = "`<` struct(params) `>`";
+def AtomicOrdering : Attr<
+  CPred<"::llvm::isa<::mlir::ptr::AtomicOrderingAttr>($_self)">,
+        "LLVM dialect atomic ordering"> {
+  let storageType = "::mlir::ptr::AtomicOrderingAttr";
+  let returnType = "::mlir::ptr::AtomicOrdering";
 }
 
-def LLVM_AliasScopeArrayAttr
-    : TypedArrayAttrBase<LLVM_AliasScopeAttr,
-                         LLVM_AliasScopeAttr.summary # " array"> {
-  let constBuilderCall = ?;
+def LLVM_AliasScopeDomainAttr : 
+    Attr<CPred<"::llvm::isa<::mlir::ptr::AliasScopeDomainAttr>($_self)">,
+        "LLVM dialect alias scope domain metadata"> {
+  let storageType = "::mlir::ptr::AliasScopeDomainAttr";
+  let returnType = "::mlir::ptr::AliasScopeDomainAttr";
+  let convertFromStorage = "$_self";
 }
 
-//===----------------------------------------------------------------------===//
-// AccessGroupAttr
-//===----------------------------------------------------------------------===//
-
-def LLVM_AccessGroupAttr : LLVM_Attr<"AccessGroup", "access_group"> {
-
-  let parameters = (ins "DistinctAttr":$id);
-
-  let builders = [
-    AttrBuilder<(ins), [{
-      return $_get($_ctxt, DistinctAttr::create(UnitAttr::get($_ctxt)));
-    }]>
-  ];
-
-  let summary = "LLVM dialect access group metadata";
-
-  let description = [{
-    Defines an access group metadata that can be set on any instruction
-    that potentially accesses memory via the `AccessGroupOpInterface` or on
-    branch instructions in the loop latch block via the `parallelAccesses`
-    parameter of `LoopAnnotationAttr`.
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#llvm-access-group-metadata
-  }];
-
-  let assemblyFormat = "`<` struct(params) `>`";
+def LLVM_AliasScopeAttr : 
+    Attr<CPred<"::llvm::isa<::mlir::ptr::AliasScopeAttr>($_self)">,
+        "LLVM dialect alias scope"> {
+  let storageType = "::mlir::ptr::AliasScopeAttr";
+  let returnType = "::mlir::ptr::AliasScopeAttr";
+  let convertFromStorage = "$_self";
 }
 
-def LLVM_AccessGroupArrayAttr
-    : TypedArrayAttrBase<LLVM_AccessGroupAttr,
-                         LLVM_AccessGroupAttr.summary # " array"> {
+def LLVM_AliasScopeArrayAttr : TypedArrayAttrBase<LLVM_AliasScopeAttr,
+    "LLVM dialect alias scope array"> {
   let constBuilderCall = ?;
 }
 
-//===----------------------------------------------------------------------===//
-// TBAARootAttr
-//===----------------------------------------------------------------------===//
-
-def LLVM_TBAARootAttr : LLVM_Attr<"TBAARoot", "tbaa_root", [], "TBAANodeAttr"> {
-  let parameters = (ins OptionalParameter<"StringAttr">:$id);
-
-  let summary = "LLVM dialect TBAA root metadata";
-  let description = [{
-    Defines a TBAA root node.
-
-    Example:
-    ```mlir
-    #cpp_root = #llvm.tbaa_root<identity = "Simple C/C++ TBAA">
-    #other_root = #llvm.tbaa_root
-    ```
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#tbaa-metadata
-  }];
-
-  let assemblyFormat = "(`<` struct(params)^ `>`)?";
-}
-
-//===----------------------------------------------------------------------===//
-// TBAATypeDescriptorAttr
-//===----------------------------------------------------------------------===//
-
-def LLVM_TBAAMemberAttr : LLVM_Attr<"TBAAMember", "tbaa_member"> {
-  let parameters = (ins
-    "TBAANodeAttr":$typeDesc,
-    "int64_t":$offset
-  );
-
-  let builders = [
-    AttrBuilderWithInferredContext<(ins "TBAANodeAttr":$typeDesc,
-                                        "int64_t":$offset), [{
-      return $_get(typeDesc.getContext(), typeDesc, offset);
-    }]>
-  ];
-
-  let assemblyFormat = "`<` params `>`";
-}
-
-def LLVM_TBAAMemberAttrArray : ArrayRefParameter<"TBAAMemberAttr"> {
-  let printer = [{
-    $_printer << '{';
-    llvm::interleaveComma($_self, $_printer, [&](TBAAMemberAttr attr) {
-        $_printer.printStrippedAttrOrType(attr);
-    });
-    $_printer << '}';
-  }];
-
-  let parser = [{
-    [&]() -> FailureOr<SmallVector<TBAAMemberAttr>> {
-        using Result = SmallVector<TBAAMemberAttr>;
-        if ($_parser.parseLBrace())
-            return failure();
-        FailureOr<Result> result = FieldParser<Result>::parse($_parser);
-        if (failed(result))
-            return failure();
-        if ($_parser.parseRBrace())
-            return failure();
-        return result;
-    }()
-  }];
-}
-
-def LLVM_TBAATypeDescriptorAttr : LLVM_Attr<"TBAATypeDescriptor",
-    "tbaa_type_desc", [], "TBAANodeAttr"> {
-  let parameters = (ins
-    StringRefParameter<>:$id,
-    LLVM_TBAAMemberAttrArray:$members
-  );
-
-  let summary = "LLVM dialect TBAA type metadata";
-
-  let description = [{
-    Defines a TBAA node describing a type.
-
-    Example:
-    ```mlir
-    #tbaa_root = #llvm.tbaa_root<identity = "Simple C/C++ TBAA">
-    #tbaa_type_desc1 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
-    #tbaa_type_desc2 = #llvm.tbaa_type_desc<id = "long long", members = {<#tbaa_root, 0>}>
-    #tbaa_type_desc3 = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc2, 0>, <#tbaa_type_desc2, 8>}>
-    #tbaa_type_desc4 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc1, 0>}>
-    #tbaa_type_desc5 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc4, 0>, <#tbaa_type_desc4, 4>}>
-    ```
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#tbaa-metadata
-  }];
-
-  let assemblyFormat = "`<` struct(params) `>`";
-}
-
-//===----------------------------------------------------------------------===//
-// TBAATagAttr
-//===----------------------------------------------------------------------===//
-
-def LLVM_TBAATagAttr : LLVM_Attr<"TBAATag", "tbaa_tag"> {
-  let parameters = (ins
-    "TBAATypeDescriptorAttr":$base_type,
-    "TBAATypeDescriptorAttr":$access_type,
-    "int64_t":$offset,
-    DefaultValuedParameter<"bool", "false">:$constant
-  );
-
-  let builders = [
-    AttrBuilderWithInferredContext<(ins "TBAATypeDescriptorAttr":$baseType,
-                                        "TBAATypeDescriptorAttr":$accessType,
-                                        "int64_t":$offset), [{
-      return $_get(baseType.getContext(), baseType, accessType, offset,
-                    /*constant=*/false);
-    }]>
-  ];
-
-  let summary = "LLVM dialect TBAA tag metadata";
-
-  let description = [{
-    Defines a TBAA node describing a memory access.
-
-    Example:
-    ```mlir
-    #tbaa_root = #llvm.tbaa_root<identity = "Simple C/C++ TBAA">
-    #tbaa_type_desc1 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
-    #tbaa_type_desc2 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc1, 0>}>
-    #tbaa_type_desc3 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc4, 0>, <#tbaa_type_desc4, 4>}>
-    #tbaa_tag = #llvm.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc2, offset = 0, constant = true>
-    ```
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#tbaa-metadata
-  }];
-
-  let assemblyFormat = "`<` struct(params) `>`";
+def LLVM_AccessGroupArrayAttr : TypedArrayAttrBase<
+    Attr<CPred<"::llvm::isa<::mlir::ptr::AccessGroupAttr>($_self)">,
+        "LLVM access group metadata">,
+    "LLVM access group metadata array"> {
+  let constBuilderCall = ?;
 }
 
-def LLVM_TBAATagArrayAttr
-    : TypedArrayAttrBase<LLVM_TBAATagAttr,
-                         LLVM_TBAATagAttr.summary # " array"> {
+def LLVM_TBAATagArrayAttr : TypedArrayAttrBase<
+    Attr<CPred<"::llvm::isa<::mlir::ptr::TBAATagAttr>($_self)">,
+        "LLVM dialect TBAA tag metadata">,
+    "LLVM dialect TBAA tag metadata array"> {
   let constBuilderCall = ?;
 }
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
index 091a817caf3d6e..fd1a1f6e59a786 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
@@ -15,6 +15,8 @@
 #define MLIR_DIALECT_LLVMIR_LLVMATTRS_H_
 
 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/Ptr/IR/MemoryModel.h"
+#include "mlir/Dialect/Ptr/IR/PtrAttrs.h"
 #include "mlir/IR/OpImplementation.h"
 #include <optional>
 
@@ -22,6 +24,16 @@
 
 namespace mlir {
 namespace LLVM {
+using AliasScopeDomainAttr = ::mlir::ptr::AliasScopeDomainAttr;
+using AliasScopeAttr = ::mlir::ptr::AliasScopeAttr;
+using AccessGroupAttr = ::mlir::ptr::AccessGroupAttr;
+using TBAARootAttr = ::mlir::ptr::TBAARootAttr;
+using TBAAMemberAttr = ::mlir::ptr::TBAAMemberAttr;
+using TBAATypeDescriptorAttr = ::mlir::ptr::TBAATypeDescriptorAttr;
+using TBAATagAttr = ::mlir::ptr::TBAATagAttr;
+using TBAANodeAttr = ::mlir::ptr::TBAANodeAttr;
+using AtomicOrdering = ::mlir::ptr::AtomicOrdering;
+using AtomicBinOp = ::mlir::ptr::AtomicBinOp;
 
 /// This class represents the base attribute for all debug info attributes.
 class DINodeAttr : public Attribute {
@@ -60,20 +72,6 @@ class DITypeAttr : public DINodeAttr {
   static bool classof(Attribute attr);
 };
 
-/// Base class for LLVM attributes participating in the TBAA graph.
-class TBAANodeAttr : public Attribute {
-public:
-  using Attribute::Attribute;
-
-  /// Support LLVM type casting.
-  static bool classof(Attribute attr);
-
-  /// Required by DenseMapInfo to create empty and tombstone key.
-  static TBAANodeAttr getFromOpaquePointer(const void *pointer) {
-    return TBAANodeAttr(reinterpret_cast<const ImplType *>(pointer));
-  }
-};
-
 // Inline the LLVM generated Linkage enum and utility.
 // This is only necessary to isolate the "enum generated code" from the
 // attribute definition itself.
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
index 9341a5a11cd629..c5f2e8c58e25a8 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h
@@ -18,6 +18,7 @@
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/Ptr/IR/PtrOps.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Dialect.h"
 #include "mlir/IR/OpDefinition.h"
@@ -58,6 +59,14 @@ struct LLVMDialectImpl;
 
 namespace mlir {
 namespace LLVM {
+using AtomicRMWOp = ::mlir::ptr::AtomicRMWOp;
+using AtomicCmpXchgOp = ::mlir::ptr::AtomicCmpXchgOp;
+using LoadOp = ::mlir::ptr::LoadOp;
+using StoreOp = ::mlir::ptr::StoreOp;
+using AddrSpaceCastOp = ::mlir::ptr::AddrSpaceCastOp;
+using IntToPtrOp = ::mlir::ptr::IntToPtrOp;
+using PtrToIntOp = ::mlir::ptr::PtrToIntOp;
+
 template <typename Values>
 class GEPIndicesAdaptor;
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
index c4c011f30b3bcd..0255836a82eafe 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
@@ -20,6 +20,9 @@ def LLVM_Dialect : Dialect {
   let hasRegionArgAttrVerify = 1;
   let hasRegionResultAttrVerify = 1;
   let hasOperationAttrVerify = 1;
+  let dependentDialects = [
+    "::mlir::ptr::PtrDialect"
+  ];
 
   let extraClassDeclaration = [{
     /// Name of the data layout attributes.
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
index 04d797031245e3..196c1a8a655e66 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
@@ -83,71 +83,6 @@ def AsmATTOrIntel : LLVM_EnumAttr<
   let cppNamespace = "::mlir::LLVM";
 }
 
-//===----------------------------------------------------------------------===//
-// Atomic Operations
-//===----------------------------------------------------------------------===//
-
-def AtomicBinOpXchg : LLVM_EnumAttrCase<"xchg", "xchg", "Xchg", 0>;
-def AtomicBinOpAdd  : LLVM_EnumAttrCase<"add", "add", "Add", 1>;
-def AtomicBinOpSub  : LLVM_EnumAttrCase<"sub", "sub", "Sub", 2>;
-def AtomicBinOpAnd  : LLVM_EnumAttrCase<"_and", "_and", "And", 3>;
-def AtomicBinOpNand : LLVM_EnumAttrCase<"nand", "nand", "Nand", 4>;
-def AtomicBinOpOr   : LLVM_EnumAttrCase<"_or", "_or", "Or", 5>;
-def AtomicBinOpXor  : LLVM_EnumAttrCase<"_xor", "_xor", "Xor", 6>;
-def AtomicBinOpMax  : LLVM_EnumAttrCase<"max", "max", "Max", 7>;
-def AtomicBinOpMin  : LLVM_EnumAttrCase<"min", "min", "Min", 8>;
-def AtomicBinOpUMax : LLVM_EnumAttrCase<"umax", "umax", "UMax", 9>;
-def AtomicBinOpUMin : LLVM_EnumAttrCase<"umin", "umin", "UMin", 10>;
-def AtomicBinOpFAdd : LLVM_EnumAttrCase<"fadd", "fadd", "FAdd", 11>;
-def AtomicBinOpFSub : LLVM_EnumAttrCase<"fsub", "fsub", "FSub", 12>;
-def AtomicBinOpFMax : LLVM_EnumAttrCase<"fmax", "fmax", "FMax", 13>;
-def AtomicBinOpFMin : LLVM_EnumAttrCase<"fmin", "fmin", "FMin", 14>;
-def AtomicBinOpUIncWrap : LLVM_EnumAttrCase<"uinc_wrap",
-                                            "uinc_wrap", "UIncWrap", 15>;
-def AtomicBinOpUDecWrap : LLVM_EnumAttrCase<"udec_wrap",
-                                            "udec_wrap", "UDecWrap", 16>;
-
-// A sentinel value that has no MLIR counterpart.
-def AtomicBadBinOp : LLVM_EnumAttrCase<"", "", "BAD_BINOP", 0>;
-
-def AtomicBinOp : LLVM_EnumAttr<
-    "AtomicBinOp",
-    "::llvm::AtomicRMWInst::BinOp",
-    "llvm.atomicrmw binary operations",
-    [AtomicBinOpXchg, AtomicBinOpAdd, AtomicBinOpSub, AtomicBinOpAnd,
-     AtomicBinOpNand, AtomicBinOpOr, AtomicBinOpXor, AtomicBinOpMax,
-     AtomicBinOpMin, AtomicBinOpUMax, AtomicBinOpUMin, AtomicBinOpFAdd,
-     AtomicBinOpFSub, AtomicBinOpFMax, AtomicBinOpFMin, AtomicBinOpUIncWrap,
-     AtomicBinOpUDecWrap],
-    [AtomicBadBinOp]> {
-  let cppNamespace = "::mlir::LLVM";
-}
-
-def AtomicOrderingNotAtomic : LLVM_EnumAttrCase<"not_atomic",
-                                                "not_atomic", "NotAtomic", 0>;
-def AtomicOrderingUnordered : LLVM_EnumAttrCase<"unordered",
-                                                "unordered", "Unordered", 1>;
-def AtomicOrderingMonotonic : LLVM_EnumAttrCase<"monotonic",
-                                                "monotonic", "Monotonic", 2>;
-def AtomicOrderingAcquire   : LLVM_EnumAttrCase<"acquire",
-                                                "acquire", "Acquire", 4>;
-def AtomicOrderingRelease   : LLVM_EnumAttrCase<"release",
-                                                "release", "Release", 5>;
-def AtomicOrderingAcquireRelease :
-      LLVM_EnumAttrCase<"acq_rel", "acq_rel", "AcquireRelease", 6>;
-def AtomicOrderingSequentiallyConsistent :
-      LLVM_EnumAttrCase<"seq_cst", "seq_cst", "SequentiallyConsistent", 7>;
-def AtomicOrdering : LLVM_EnumAttr<
-    "AtomicOrdering",
-    "::llvm::AtomicOrdering",
-    "Atomic ordering for LLVM's memory model",
-    [AtomicOrderingNotAtomic, AtomicOrderingUnordered, AtomicOrderingMonotonic,
-     AtomicOrderingAcquire, AtomicOrderingRelease, AtomicOrderingAcquireRelease,
-     AtomicOrderingSequentiallyConsistent
-    ]> {
-  let cppNamespace = "::mlir::LLVM";
-}
-
 //===----------------------------------------------------------------------===//
 // CallingConvention
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h
index 961e0be9d267d0..190d9a1086f2ee 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.h
@@ -14,20 +14,16 @@
 #define MLIR_DIALECT_LLVMIR_LLVMINTERFACES_H_
 
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+#include "mlir/Dialect/Ptr/IR/PtrInterfaces.h"
 
 namespace mlir {
 namespace LLVM {
 namespace detail {
-
-/// Verifies the access groups attribute of memory operations that implement the
-/// access group interface.
-LogicalResult verifyAccessGroupOpInterface(Operation *op);
-
-/// Verifies the alias analysis attributes of memory operations that implement
-/// the alias analysis interface.
-LogicalResult verifyAliasAnalysisOpInterface(Operation *op);
-
+using ptr::detail::verifyAccessGroupOpInterface;
+using ptr::detail::verifyAliasAnalysisOpInterface;
 } // namespace detail
+using ptr::AccessGroupOpInterface;
+using ptr::AliasAnalysisOpInterface;
 } // namespace LLVM
 } // namespace mlir
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
index cee752aeb269b7..429d90089c0209 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
@@ -14,6 +14,7 @@
 #define LLVMIR_INTERFACES
 
 include "mlir/IR/OpBase.td"
+include "mlir/Dialect/Ptr/IR/PtrInterfaces.td"
 
 def FastmathFlagsInterface : OpInterface<"FastmathFlagsInterface"> {
   let description = [{
@@ -141,132 +142,6 @@ def BranchWeightOpInterface : OpInterface<"BranchWeightOpInterface"> {
   ];
 }
 
-def AccessGroupOpInterface : OpInterface<"AccessGroupOpInterface"> {
-  let description = [{
-    An interface for memory operations that can carry access groups metadata.
-    It provides setters and getters for the operation's access groups attribute.
-    The default implementations of the interface methods expect the operation
-    to have an attribute of type ArrayAttr named access_groups.
-  }];
-
-  let cppNamespace = "::mlir::LLVM";
-  let verify = [{ return detail::verifyAccessGroupOpInterface($_op); }];
-
-  let methods = [
-    InterfaceMethod<
-      /*desc=*/        "Returns the access groups attribute or nullptr",
-      /*returnType=*/  "ArrayAttr",
-      /*methodName=*/  "getAccessGroupsOrNull",
-      /*args=*/        (ins),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        return op.getAccessGroupsAttr();
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Sets the access groups attribute",
-      /*returnType=*/  "void",
-      /*methodName=*/  "setAccessGroups",
-      /*args=*/        (ins "const ArrayAttr":$attr),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        op.setAccessGroupsAttr(attr);
-      }]
-      >
-  ];
-}
-
-def AliasAnalysisOpInterface : OpInterface<"AliasAnalysisOpInterface"> {
-  let description = [{
-    An interface for memory operations that can carry alias analysis metadata.
-    It provides setters and getters for the operation's alias analysis
-    attributes. The default implementations of the interface methods expect
-    the operation to have attributes of type ArrayAttr named alias_scopes,
-    noalias_scopes, and tbaa.
-  }];
-
-  let cppNamespace = "::mlir::LLVM";
-  let verify = [{ return detail::verifyAliasAnalysisOpInterface($_op); }];
-
-  let methods = [
-    InterfaceMethod<
-      /*desc=*/        "Returns the alias scopes attribute or nullptr",
-      /*returnType=*/  "ArrayAttr",
-      /*methodName=*/  "getAliasScopesOrNull",
-      /*args=*/        (ins),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        return op.getAliasScopesAttr();
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Sets the alias scopes attribute",
-      /*returnType=*/  "void",
-      /*methodName=*/  "setAliasScopes",
-      /*args=*/        (ins "const ArrayAttr":$attr),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        op.setAliasScopesAttr(attr);
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Returns the noalias scopes attribute or nullptr",
-      /*returnType=*/  "ArrayAttr",
-      /*methodName=*/  "getNoAliasScopesOrNull",
-      /*args=*/        (ins),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        return op.getNoaliasScopesAttr();
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Sets the noalias scopes attribute",
-      /*returnType=*/  "void",
-      /*methodName=*/  "setNoAliasScopes",
-      /*args=*/        (ins "const ArrayAttr":$attr),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        op.setNoaliasScopesAttr(attr);
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Returns the tbaa attribute or nullptr",
-      /*returnType=*/  "ArrayAttr",
-      /*methodName=*/  "getTBAATagsOrNull",
-      /*args=*/        (ins),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        return op.getTbaaAttr();
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Sets the tbaa attribute",
-      /*returnType=*/  "void",
-      /*methodName=*/  "setTBAATags",
-      /*args=*/        (ins "const ArrayAttr":$attr),
-      /*methodBody=*/  [{}],
-      /*defaultImpl=*/ [{
-        auto op = cast<ConcreteOp>(this->getOperation());
-        op.setTbaaAttr(attr);
-      }]
-      >,
-    InterfaceMethod<
-      /*desc=*/        "Returns a list of all pointer operands accessed by the "
-                       "operation",
-      /*returnType=*/  "::llvm::SmallVector<::mlir::Value>",
-      /*methodName=*/  "getAccessedOperands",
-      /*args=*/        (ins)
-      >
-  ];
-}
-
 def GetResultPtrElementType : OpInterface<"GetResultPtrElementType"> {
   let description = [{
     An interface for operations that yield an LLVMPointer. Allows the
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
index f4bac9376f2ea0..1636c911527cf7 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
@@ -563,7 +563,8 @@ class LLVM_DbgIntrOp<string name, string argName, list<Trait> traits = []>
 }
 
 def LLVM_DbgDeclareOp : LLVM_DbgIntrOp<"dbg.declare", "addr",
-    [DeclareOpInterfaceMethods<PromotableOpInterface>]> {
+    [DeclareOpInterfaceMethods<PromotableOpInterface, [
+      "requiresVisitingMutatedDefs", "visitMutatedDefs"]>]> {
   let summary = "Describes how the address relates to a source language variable.";
   let arguments = (ins
     LLVM_AnyPointer:$addr,
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index f8f9264b3889be..0f45e2ec566838 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -322,158 +322,6 @@ def LLVM_GEPOp : LLVM_Op<"getelementptr", [Pure,
   let hasVerifier = 1;
 }
 
-def LLVM_LoadOp : LLVM_MemAccessOpBase<"load",
-    [DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
-     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
-     DeclareOpInterfaceMethods<PromotableMemOpInterface>,
-     DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>]> {
-  dag args = (ins LLVM_AnyPointer:$addr,
-              OptionalAttr<I64Attr>:$alignment,
-              UnitAttr:$volatile_,
-              UnitAttr:$nontemporal,
-              UnitAttr:$invariant,
-              DefaultValuedAttr<
-                AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering,
-              OptionalAttr<StrAttr>:$syncscope);
-  // Append the aliasing related attributes defined in LLVM_MemAccessOpBase.
-  let arguments = !con(args, aliasAttrs);
-  let results = (outs LLVM_LoadableType:$res);
-  string llvmInstName = "Load";
-  let description = [{
-    The `load` operation is used to read from memory. A load may be marked as
-    atomic, volatile, and/or nontemporal, and takes a number of optional
-    attributes that specify aliasing information.
-
-    An atomic load only supports a limited set of pointer, integer, and
-    floating point types, and requires an explicit alignment.
-
-    Examples:
-    ```mlir
-    // A volatile load of a float variable.
-    %0 = llvm.load volatile %ptr : !llvm.ptr -> f32
-
-    // A nontemporal load of a float variable.
-    %0 = llvm.load %ptr {nontemporal} : !llvm.ptr -> f32
-
-    // An atomic load of an integer variable.
-    %0 = llvm.load %ptr atomic monotonic {alignment = 8 : i64}
-        : !llvm.ptr -> i64
-    ```
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#load-instruction
-  }];
-  let assemblyFormat = [{
-    (`volatile` $volatile_^)? $addr
-    (`atomic` (`syncscope` `(` $syncscope^ `)`)? $ordering^)?
-    (`invariant` $invariant^)?
-    attr-dict `:` qualified(type($addr)) `->` type($res)
-  }];
-  string llvmBuilder = [{
-    auto *inst = builder.CreateLoad($_resultType, $addr, $volatile_);
-    $res = inst;
-    if ($invariant) {
-      llvm::MDNode *metadata = llvm::MDNode::get(inst->getContext(), std::nullopt);
-      inst->setMetadata(llvm::LLVMContext::MD_invariant_load, metadata);
-    }
-  }] # setOrderingCode
-     # setSyncScopeCode
-     # setAlignmentCode
-     # setNonTemporalMetadataCode
-     # setAccessGroupsMetadataCode
-     # setAliasAnalysisMetadataCode;
-  string mlirBuilder = [{
-    auto *loadInst = cast<llvm::LoadInst>(inst);
-    unsigned alignment = loadInst->getAlign().value();
-    $res = $_builder.create<LLVM::LoadOp>($_location, $_resultType, $addr,
-        alignment, loadInst->isVolatile(),
-        loadInst->hasMetadata(llvm::LLVMContext::MD_nontemporal),
-        loadInst->hasMetadata(llvm::LLVMContext::MD_invariant_load),
-        convertAtomicOrderingFromLLVM(loadInst->getOrdering()),
-        getLLVMSyncScope(loadInst));
-  }];
-  let builders = [
-    OpBuilder<(ins "Type":$type, "Value":$addr,
-      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
-      CArg<"bool", "false">:$isNonTemporal, CArg<"bool", "false">:$isInvariant,
-      CArg<"AtomicOrdering", "AtomicOrdering::not_atomic">:$ordering,
-      CArg<"StringRef", "StringRef()">:$syncscope)>
-  ];
-  let hasVerifier = 1;
-}
-
-def LLVM_StoreOp : LLVM_MemAccessOpBase<"store",
-    [DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
-     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
-     DeclareOpInterfaceMethods<PromotableMemOpInterface>,
-     DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>]> {
-  dag args = (ins LLVM_LoadableType:$value,
-              LLVM_AnyPointer:$addr,
-              OptionalAttr<I64Attr>:$alignment,
-              UnitAttr:$volatile_,
-              UnitAttr:$nontemporal,
-              DefaultValuedAttr<
-                AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering,
-              OptionalAttr<StrAttr>:$syncscope);
-  // Append the aliasing related attributes defined in LLVM_MemAccessOpBase.
-  let arguments = !con(args, aliasAttrs);
-  string llvmInstName = "Store";
-  let description = [{
-    The `store` operation is used to write to memory. A store may be marked as
-    atomic, volatile, and/or nontemporal, and takes a number of optional
-    attributes that specify aliasing information.
-
-    An atomic store only supports a limited set of pointer, integer, and
-    floating point types, and requires an explicit alignment.
-
-    Examples:
-    ```mlir
-    // A volatile store of a float variable.
-    llvm.store volatile %val, %ptr : f32, !llvm.ptr
-
-    // A nontemporal store of a float variable.
-    llvm.store %val, %ptr {nontemporal} : f32, !llvm.ptr
-
-    // An atomic store of an integer variable.
-    llvm.store %val, %ptr atomic monotonic {alignment = 8 : i64}
-        : i64, !llvm.ptr
-    ```
-
-    See the following link for more details:
-    https://llvm.org/docs/LangRef.html#store-instruction
-  }];
-  let assemblyFormat = [{
-    (`volatile` $volatile_^)? $value `,` $addr
-    (`atomic` (`syncscope` `(` $syncscope^ `)`)? $ordering^)?
-    attr-dict `:` type($value) `,` qualified(type($addr))
-  }];
-  string llvmBuilder = [{
-    auto *inst = builder.CreateStore($value, $addr, $volatile_);
-  }] # setOrderingCode
-     # setSyncScopeCode
-     # setAlignmentCode
-     # setNonTemporalMetadataCode
-     # setAccessGroupsMetadataCode
-     # setAliasAnalysisMetadataCode;
-  string mlirBuilder = [{
-    auto *storeInst = cast<llvm::StoreInst>(inst);
-    unsigned alignment = storeInst->getAlign().value();
-    $_op = $_builder.create<LLVM::StoreOp>($_location, $value, $addr,
-        alignment, storeInst->isVolatile(),
-        storeInst->hasMetadata(llvm::LLVMContext::MD_nontemporal),
-        convertAtomicOrderingFromLLVM(storeInst->getOrdering()),
-        getLLVMSyncScope(storeInst));
-  }];
-  let builders = [
-    OpBuilder<(ins "Value":$value, "Value":$addr,
-      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
-      CArg<"bool", "false">:$isNonTemporal,
-      CArg<"AtomicOrdering", "AtomicOrdering::not_atomic">:$ordering,
-      CArg<"StringRef", "StringRef()">:$syncscope)>
-  ];
-  let hasVerifier = 1;
-}
-
 // Casts.
 class LLVM_CastOp<string mnemonic, string instName, Type type,
                   Type resultType, list<Trait> traits = []> :
@@ -494,18 +342,6 @@ def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "BitCast", LLVM_AnyNonAggregate,
   let hasFolder = 1;
   let hasVerifier = 1;
 }
-def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "AddrSpaceCast",
-    LLVM_ScalarOrVectorOf<LLVM_AnyPointer>,
-    LLVM_ScalarOrVectorOf<LLVM_AnyPointer>,
-    [DeclareOpInterfaceMethods<PromotableOpInterface>]> {
-  let hasFolder = 1;
-}
-def LLVM_IntToPtrOp : LLVM_CastOp<"inttoptr", "IntToPtr",
-                                  LLVM_ScalarOrVectorOf<AnySignlessInteger>,
-                                  LLVM_ScalarOrVectorOf<LLVM_AnyPointer>>;
-def LLVM_PtrToIntOp : LLVM_CastOp<"ptrtoint", "PtrToInt",
-                                  LLVM_ScalarOrVectorOf<LLVM_AnyPointer>,
-                                  LLVM_ScalarOrVectorOf<AnySignlessInteger>>;
 def LLVM_SExtOp : LLVM_CastOp<"sext", "SExt",
                               LLVM_ScalarOrVectorOf<AnySignlessInteger>,
                               LLVM_ScalarOrVectorOf<AnySignlessInteger>> {
@@ -1649,117 +1485,12 @@ def LLVM_ConstantOp
 // Atomic operations.
 //
 
-def LLVM_AtomicRMWType : AnyTypeOf<[LLVM_AnyFloat, LLVM_AnyPointer, AnySignlessInteger]>;
-
-def LLVM_AtomicRMWOp : LLVM_MemAccessOpBase<"atomicrmw", [
-      TypesMatchWith<"result #0 and operand #1 have the same type",
-                     "val", "res", "$_self">]> {
-  dag args = (ins AtomicBinOp:$bin_op,
-              LLVM_AnyPointer:$ptr,
-              LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering,
-              OptionalAttr<StrAttr>:$syncscope,
-              OptionalAttr<I64Attr>:$alignment,
-              UnitAttr:$volatile_);
-  // Append the aliasing related attributes defined in LLVM_MemAccessOpBase.
-  let arguments = !con(args, aliasAttrs);
-  let results = (outs LLVM_AtomicRMWType:$res);
-  let assemblyFormat = [{
-    (`volatile` $volatile_^)? $bin_op $ptr `,` $val
-    (`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict `:`
-    qualified(type($ptr)) `,` type($val)
-  }];
-  string llvmInstName = "AtomicRMW";
-  string llvmBuilder = [{
-    auto *inst = builder.CreateAtomicRMW(
-        convertAtomicBinOpToLLVM($bin_op), $ptr, $val, llvm::MaybeAlign(),
-        convertAtomicOrderingToLLVM($ordering));
-    $res = inst;
-  }] # setVolatileCode
-     # setSyncScopeCode
-     # setAlignmentCode
-     # setAccessGroupsMetadataCode
-     # setAliasAnalysisMetadataCode;
-  string mlirBuilder = [{
-    auto *atomicInst = cast<llvm::AtomicRMWInst>(inst);
-    unsigned alignment = atomicInst->getAlign().value();
-    $res = $_builder.create<LLVM::AtomicRMWOp>($_location,
-        convertAtomicBinOpFromLLVM(atomicInst->getOperation()), $ptr, $val,
-        convertAtomicOrderingFromLLVM(atomicInst->getOrdering()),
-        getLLVMSyncScope(atomicInst), alignment, atomicInst->isVolatile());
-  }];
-  list<int> llvmArgIndices = [-1, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1];
-  let builders = [
-    OpBuilder<(ins "LLVM::AtomicBinOp":$binOp, "Value":$ptr, "Value":$val,
-      "LLVM::AtomicOrdering":$ordering,
-      CArg<"StringRef", "StringRef()">:$syncscope,
-      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile
-    )>
-  ];
-  let hasVerifier = 1;
-}
-
-def LLVM_AtomicCmpXchgType : AnyTypeOf<[AnySignlessInteger, LLVM_AnyPointer]>;
-
-def LLVM_AtomicCmpXchgOp : LLVM_MemAccessOpBase<"cmpxchg", [
-      TypesMatchWith<"operand #1 and operand #2 have the same type",
-                     "val", "cmp", "$_self">,
-      TypesMatchWith<"result #0 has an LLVM struct type consisting of "
-                     "the type of operand #2 and a bool", "val", "res",
-                     "getValAndBoolStructType($_self)">]> {
-  dag args = (ins LLVM_AnyPointer:$ptr,
-              LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val,
-              AtomicOrdering:$success_ordering,
-              AtomicOrdering:$failure_ordering,
-              OptionalAttr<StrAttr>:$syncscope,
-              OptionalAttr<I64Attr>:$alignment,
-              UnitAttr:$weak,
-              UnitAttr:$volatile_);
-  // Append the aliasing related attributes defined in LLVM_MemAccessOpBase.
-  let arguments = !con(args, aliasAttrs);
-  let results = (outs LLVM_AnyStruct:$res);
-  let assemblyFormat = [{
-    (`weak` $weak^)? (`volatile` $volatile_^)? $ptr `,` $cmp `,` $val
-    (`syncscope` `(` $syncscope^ `)`)? $success_ordering $failure_ordering
-    attr-dict `:` qualified(type($ptr)) `,` type($val)
-  }];
-  string llvmInstName = "AtomicCmpXchg";
-  string llvmBuilder = [{
-    auto *inst = builder.CreateAtomicCmpXchg($ptr, $cmp, $val,
-        llvm::MaybeAlign(), convertAtomicOrderingToLLVM($success_ordering),
-        convertAtomicOrderingToLLVM($failure_ordering));
-    $res = inst;
-    inst->setWeak($weak);
-  }] # setVolatileCode
-     # setSyncScopeCode
-     # setAlignmentCode
-     # setAccessGroupsMetadataCode
-     # setAliasAnalysisMetadataCode;
-  string mlirBuilder = [{
-    auto *cmpXchgInst = cast<llvm::AtomicCmpXchgInst>(inst);
-    unsigned alignment = cmpXchgInst->getAlign().value();
-    $res = $_builder.create<LLVM::AtomicCmpXchgOp>(
-      $_location, $ptr, $cmp, $val,
-      convertAtomicOrderingFromLLVM(cmpXchgInst->getSuccessOrdering()),
-      convertAtomicOrderingFromLLVM(cmpXchgInst->getFailureOrdering()),
-      getLLVMSyncScope(cmpXchgInst), alignment, cmpXchgInst->isWeak(),
-      cmpXchgInst->isVolatile());
-  }];
-  let builders = [
-    OpBuilder<(ins "Value":$ptr, "Value":$cmp, "Value":$val,
-      "LLVM::AtomicOrdering":$successOrdering,
-      "LLVM::AtomicOrdering":$failureOrdering,
-      CArg<"StringRef", "StringRef()">:$syncscope,
-      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isWeak,
-      CArg<"bool", "false">:$isVolatile
-    )>
-  ];
-  let hasVerifier = 1;
-}
-
 def LLVM_FenceOp : LLVM_Op<"fence">, LLVM_MemOpPatterns {
   let arguments = (ins AtomicOrdering:$ordering,
                    OptionalAttr<StrAttr>:$syncscope);
-  let assemblyFormat = "(`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict";
+  let assemblyFormat = [{
+    (`syncscope` `(` $syncscope^ `)`)? custom<AtomicOrdering>($ordering) attr-dict
+  }];
   string llvmInstName = "Fence";
   let llvmBuilder = [{
     auto *inst = builder.CreateFence(convertAtomicOrderingToLLVM($ordering));
@@ -1774,7 +1505,7 @@ def LLVM_FenceOp : LLVM_Op<"fence">, LLVM_MemOpPatterns {
   let builders = [
     LLVM_VoidResultTypeOpBuilder,
     LLVM_ZeroResultOpBuilder,
-    OpBuilder<(ins "LLVM::AtomicOrdering":$ordering,
+    OpBuilder<(ins "ptr::AtomicOrdering":$ordering,
       CArg<"StringRef", "StringRef()">:$syncscope)>
   ];
   let hasVerifier = 1;
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
index 93733ccd4929ae..71f5802f73be9d 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
@@ -14,6 +14,7 @@
 #ifndef MLIR_DIALECT_LLVMIR_LLVMTYPES_H_
 #define MLIR_DIALECT_LLVMIR_LLVMTYPES_H_
 
+#include "mlir/Dialect/Ptr/IR/PtrTypes.h"
 #include "mlir/IR/Types.h"
 #include "mlir/Interfaces/DataLayoutInterfaces.h"
 #include "mlir/Interfaces/MemorySlotInterfaces.h"
@@ -31,6 +32,7 @@ class AsmPrinter;
 
 namespace LLVM {
 class LLVMDialect;
+class LLVMPointerType;
 
 namespace detail {
 struct LLVMFunctionTypeStorage;
@@ -283,18 +285,35 @@ Type getScalableVectorType(Type elementType, unsigned numElements);
 /// (aggregates such as struct) or types that don't have a size (such as void).
 llvm::TypeSize getPrimitiveTypeSizeInBits(Type type);
 
-/// The positions of different values in the data layout entry for pointers.
-enum class PtrDLEntryPos { Size = 0, Abi = 1, Preferred = 2, Index = 3 };
-
-/// Returns the value that corresponds to named position `pos` from the
-/// data layout entry `attr` assuming it's a dense integer elements attribute.
-/// Returns `std::nullopt` if `pos` is not present in the entry.
-/// Currently only `PtrDLEntryPos::Index` is optional, and all other positions
-/// may be assumed to be present.
-std::optional<uint64_t> extractPointerSpecValue(Attribute attr,
-                                                PtrDLEntryPos pos);
+/// Returns whether a pointer type is an LLVM pointer.
+bool isLLVMPointerType(Type type);
 
+/// Utility class for creating pointer types of the form
+/// `ptr.ptr<#llvm.address_space<#int_attr>>`
+class LLVMPointerType : public ptr::PtrType {
+public:
+  LLVMPointerType() : ptr::PtrType() {}
+  LLVMPointerType(const ptr::PtrType &ty) : ptr::PtrType(ty) {}
+  template <typename T>
+  static bool classof(T val) {
+    static_assert(std::is_convertible<Type, T>::value,
+                  "casting from a non-convertible type");
+    return isLLVMPointerType(val);
+  }
+  static PtrType get(::mlir::MLIRContext *context, unsigned addressSpace = 0);
+  static ::mlir::Type parse(::mlir::AsmParser &odsParser);
+  void print(::mlir::AsmPrinter &odsPrinter) const;
+};
 } // namespace LLVM
 } // namespace mlir
 
+namespace mlir {
+namespace detail {
+template <>
+class TypeIDResolver<LLVM::LLVMPointerType> {
+public:
+  static TypeID resolveTypeID() { return TypeID::get<ptr::PtrType>(); }
+};
+} /* namespace detail */
+} // namespace mlir
 #endif // MLIR_DIALECT_LLVMIR_LLVMTYPES_H_
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td
index b7176aa93ff1f7..b911c3d7d6dcc4 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td
@@ -20,6 +20,14 @@ class LLVMType<string typeName, string typeMnemonic, list<Trait> traits = []>
   let mnemonic = typeMnemonic;
 }
 
+
+//===----------------------------------------------------------------------===//
+// LLVMPointerType
+//===----------------------------------------------------------------------===//
+def LLVMPointerType :
+  Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMPointer>($_self)">, "pointer",
+             "::mlir::LLVM::LLVMPointer">;
+
 //===----------------------------------------------------------------------===//
 // LLVMArrayType
 //===----------------------------------------------------------------------===//
@@ -117,39 +125,6 @@ def LLVMFunctionType : LLVMType<"LLVMFunction", "func"> {
   }];
 }
 
-//===----------------------------------------------------------------------===//
-// LLVMPointerType
-//===----------------------------------------------------------------------===//
-
-def LLVMPointerType : LLVMType<"LLVMPointer", "ptr", [
-    DeclareTypeInterfaceMethods<DataLayoutTypeInterface, [
-      "getIndexBitwidth", "areCompatible", "verifyEntries"]>]> {
-  let summary = "LLVM pointer type";
-  let description = [{
-    The `!llvm.ptr` type is an LLVM pointer type. This type typically represents
-    a reference to an object in memory. Pointers are optionally parameterized
-    by the address space.
-
-    Example:
-
-    ```mlir
-    !llvm.ptr
-    ```
-  }];
-
-  let parameters = (ins DefaultValuedParameter<"unsigned", "0">:$addressSpace);
-  let assemblyFormat = [{
-    (`<` $addressSpace^ `>`)?
-  }];
-
-  let skipDefaultBuilders = 1;
-  let builders = [
-    TypeBuilder<(ins CArg<"unsigned", "0">:$addressSpace), [{
-      return $_get($_ctxt, addressSpace);
-    }]>
-  ];
-}
-
 //===----------------------------------------------------------------------===//
 // LLVMFixedVectorType
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/Ptr/CMakeLists.txt b/mlir/include/mlir/Dialect/Ptr/CMakeLists.txt
new file mode 100644
index 00000000000000..f33061b2d87cff
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(IR)
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/Ptr/IR/CMakeLists.txt
new file mode 100644
index 00000000000000..2562d7e6e6e40d
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_mlir_dialect(PtrOps ptr)
+add_mlir_doc(PtrOps PtrOps Dialects/ -gen-op-doc)
+
+set(LLVM_TARGET_DEFINITIONS MemorySpaceInterfaces.td)
+mlir_tablegen(MemorySpaceInterfaces.h.inc -gen-op-interface-decls)
+mlir_tablegen(MemorySpaceInterfaces.cpp.inc -gen-op-interface-defs)
+mlir_tablegen(MemorySpaceAttrInterfaces.h.inc -gen-attr-interface-decls)
+mlir_tablegen(MemorySpaceAttrInterfaces.cpp.inc -gen-attr-interface-defs)
+add_public_tablegen_target(MLIRPtrMemorySpaceInterfacesIncGen)
+
+set(LLVM_TARGET_DEFINITIONS PtrInterfaces.td)
+mlir_tablegen(PtrInterfaces.h.inc -gen-op-interface-decls)
+mlir_tablegen(PtrInterfaces.cpp.inc -gen-op-interface-defs)
+add_public_tablegen_target(MLIRPtrInterfacesIncGen)
+
+set(LLVM_TARGET_DEFINITIONS PtrOps.td)
+mlir_tablegen(PtrOpsEnums.h.inc -gen-enum-decls)
+mlir_tablegen(PtrOpsEnums.cpp.inc -gen-enum-defs)
+add_public_tablegen_target(MLIRPtrOpsEnumsGen)
+
+set(LLVM_TARGET_DEFINITIONS PtrOps.td)
+mlir_tablegen(PtrOpsAttrs.h.inc -gen-attrdef-decls -attrdefs-dialect=ptr)
+mlir_tablegen(PtrOpsAttrs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=ptr)
+add_public_tablegen_target(MLIRPtrOpsAttributesIncGen)
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/MemoryModel.h b/mlir/include/mlir/Dialect/Ptr/IR/MemoryModel.h
new file mode 100644
index 00000000000000..7913fa64e5b8d8
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/MemoryModel.h
@@ -0,0 +1,161 @@
+//===-- MemoryModel.h - ptr dialect memory model  ---------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ptr's dialect memory model class and related
+// interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_PTR_IR_MEMORYMODEL_H
+#define MLIR_DIALECT_PTR_IR_MEMORYMODEL_H
+
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/OpDefinition.h"
+
+namespace mlir {
+class Operation;
+namespace ptr {
+/// This method checks if it's valid to perform an `addrspacecast` op in the
+/// memory space.
+/// Compatible types are:
+/// Vectors of rank 1, or scalars of `ptr` type.
+LogicalResult isValidAddrSpaceCastImpl(Type tgt, Type src,
+                                       Operation *diagnosticOp);
+
+/// This method checks if it's valid to perform a `ptrtoint` or `inttoptr` op in
+/// the memory space.
+/// Compatible types are:
+/// IntLikeTy: Vectors of rank 1, or scalars of integer types or `index` type.
+/// PtrLikeTy: Vectors of rank 1, or scalars of `ptr` type.
+LogicalResult isValidPtrIntCastImpl(Type intLikeTy, Type ptrLikeTy,
+                                    Operation *diagnosticOp);
+
+enum class AtomicBinOp : uint64_t;
+enum class AtomicOrdering : uint64_t;
+} // namespace ptr
+} // namespace mlir
+
+#include "mlir/Dialect/Ptr/IR/MemorySpaceAttrInterfaces.h.inc"
+
+namespace mlir {
+namespace ptr {
+/// This class wraps the `MemorySpaceAttrInterface` interface, providing a safe
+/// mechanism to specify the default behavior assumed by the ptr dialect.
+class MemoryModel {
+public:
+  MemoryModel() = default;
+  MemoryModel(std::nullptr_t) {}
+  MemoryModel(MemorySpaceAttrInterface memorySpace)
+      : memorySpaceAttr(memorySpace), memorySpace(memorySpace) {}
+  MemoryModel(Attribute memorySpace)
+      : memorySpaceAttr(memorySpace),
+        memorySpace(dyn_cast_or_null<MemorySpaceAttrInterface>(memorySpace)) {}
+
+  operator Attribute() const { return memorySpaceAttr; }
+  operator MemorySpaceAttrInterface() const { return memorySpace; }
+  bool operator==(const MemoryModel &memSpace) const {
+    return memSpace.memorySpaceAttr == memorySpaceAttr;
+  }
+
+  /// Returns the underlying memory space.
+  Attribute getUnderlyingSpace() const { return memorySpaceAttr; }
+
+  /// Returns true if the underlying memory space is null.
+  bool isDefaultModel() const { return memorySpace == nullptr; }
+
+  /// Returns the memory space as an integer, or 0 if using the default model.
+  unsigned getAddressSpace() const {
+    if (memorySpace)
+      return memorySpace.getAddressSpace();
+    if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(memorySpaceAttr))
+      return intAttr.getInt();
+    return 0;
+  }
+
+  /// Returns the default memory space as an attribute, or nullptr if using the
+  /// default model.
+  Attribute getDefaultMemorySpace() const {
+    return memorySpace ? memorySpace.getDefaultMemorySpace() : nullptr;
+  }
+
+  /// This method checks if it's valid to load a value from the memory space
+  /// with a specific type, alignment, and atomic ordering. The default model
+  /// assumes all values are loadable.
+  LogicalResult isValidLoad(Type type, AtomicOrdering ordering,
+                            IntegerAttr alignment,
+                            Operation *diagnosticOp = nullptr) const {
+    return memorySpace ? memorySpace.isValidLoad(type, ordering, alignment,
+                                                 diagnosticOp)
+                       : success();
+  }
+
+  /// This method checks if it's valid to store a value in the memory space with
+  /// a specific type, alignment, and atomic ordering. The default model assumes
+  /// all values are loadable.
+  LogicalResult isValidStore(Type type, AtomicOrdering ordering,
+                             IntegerAttr alignment,
+                             Operation *diagnosticOp = nullptr) const {
+    return memorySpace ? memorySpace.isValidStore(type, ordering, alignment,
+                                                  diagnosticOp)
+                       : success();
+  }
+
+  /// This method checks if it's valid to perform an atomic operation in the
+  /// memory space with a specific type, alignment, and atomic ordering.
+  LogicalResult isValidAtomicOp(AtomicBinOp op, Type type,
+                                AtomicOrdering ordering, IntegerAttr alignment,
+                                Operation *diagnosticOp = nullptr) const {
+    return memorySpace ? memorySpace.isValidAtomicOp(op, type, ordering,
+                                                     alignment, diagnosticOp)
+                       : success();
+  }
+
+  /// This method checks if it's valid to perform an atomic operation in the
+  /// memory space with a specific type, alignment, and atomic ordering.
+  LogicalResult isValidAtomicXchg(Type type, AtomicOrdering successOrdering,
+                                  AtomicOrdering failureOrdering,
+                                  IntegerAttr alignment,
+                                  Operation *diagnosticOp = nullptr) const {
+    return memorySpace ? memorySpace.isValidAtomicXchg(type, successOrdering,
+                                                       failureOrdering,
+                                                       alignment, diagnosticOp)
+                       : success();
+  }
+
+  /// This method checks if it's valid to perform an `addrspacecast` op in the
+  /// memory space.
+  LogicalResult isValidAddrSpaceCast(Type tgt, Type src,
+                                     Operation *diagnosticOp = nullptr) const {
+    return memorySpace
+               ? memorySpace.isValidAddrSpaceCast(tgt, src, diagnosticOp)
+               : isValidAddrSpaceCastImpl(tgt, src, diagnosticOp);
+  }
+
+  /// This method checks if it's valid to perform a `ptrtoint` or `inttoptr` op
+  /// in the memory space.
+  LogicalResult isValidPtrIntCast(Type intLikeTy, Type ptrLikeTy,
+                                  Operation *diagnosticOp = nullptr) const {
+    return memorySpace
+               ? memorySpace.isValidPtrIntCast(intLikeTy, ptrLikeTy,
+                                               diagnosticOp)
+               : isValidPtrIntCastImpl(intLikeTy, ptrLikeTy, diagnosticOp);
+  }
+
+protected:
+  /// Underlying memory space.
+  Attribute memorySpaceAttr{};
+  /// Memory space.
+  MemorySpaceAttrInterface memorySpace{};
+};
+} // namespace ptr
+} // namespace mlir
+
+#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h.inc"
+
+#endif // MLIR_DIALECT_PTR_IR_MEMORYMODEL_H
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td b/mlir/include/mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td
new file mode 100644
index 00000000000000..96e793cea31282
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td
@@ -0,0 +1,182 @@
+//===-- MemorySpaceInterfaces.td - Memory space interfaces ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines memory space attribute interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef PTR_MEMORYSPACEINTERFACES
+#define PTR_MEMORYSPACEINTERFACES
+
+include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/OpBase.td"
+
+//===----------------------------------------------------------------------===//
+// Memory space attribute interface.
+//===----------------------------------------------------------------------===//
+
+def MemorySpaceAttrInterface : AttrInterface<"MemorySpaceAttrInterface"> {
+  let description = [{
+    This interface defines a common API for interacting with the memory model of
+    a memory space and the operations in the pointer dialect, giving proper
+    semantical meaning to the ops.
+
+    Furthermore, this interface allows concepts such as read-only memory to be
+    adequately modeled and enforced.
+  }];
+  let cppNamespace = "::mlir::ptr";
+  let methods = [
+    InterfaceMethod<
+      /*desc=*/        [{
+        Returns the dialect implementing the memory space.
+      }],
+      /*returnType=*/  "::mlir::Dialect*",
+      /*methodName=*/  "getMemorySpaceDialect",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{ return nullptr; }]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        Returns the default memory space as an attribute.
+      }],
+      /*returnType=*/  "::mlir::Attribute",
+      /*methodName=*/  "getDefaultMemorySpace",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        Returns the memory space as an integer, or 0 if using the default model.
+      }],
+      /*returnType=*/  "unsigned",
+      /*methodName=*/  "getAddressSpace",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{ return 0; }]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        This method checks if it's valid to load a value from the memory space
+        with a specific type, alignment, and atomic ordering.
+        If `diagnosticOp` is non-null then the method might emit diagnostics.
+      }],
+      /*returnType=*/  "::mlir::LogicalResult",
+      /*methodName=*/  "isValidLoad",
+      /*args=*/        (ins "::mlir::Type":$type,
+                            "::mlir::ptr::AtomicOrdering":$ordering,
+                            "::mlir::IntegerAttr":$alignment,
+                            "::mlir::Operation*":$diagnosticOp),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        This method checks if it's valid to store a value in the memory space
+        with a specific type, alignment, and atomic ordering.
+        If `diagnosticOp` is non-null then the method might emit diagnostics.
+      }],
+      /*returnType=*/  "::mlir::LogicalResult",
+      /*methodName=*/  "isValidStore",
+      /*args=*/        (ins "::mlir::Type":$type,
+                            "::mlir::ptr::AtomicOrdering":$ordering,
+                            "::mlir::IntegerAttr":$alignment,
+                            "::mlir::Operation*":$diagnosticOp),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        This method checks if it's valid to perform an atomic operation in the
+        memory space with a specific type, alignment, and atomic ordering.
+        If `diagnosticOp` is non-null then the method might emit diagnostics.
+      }],
+      /*returnType=*/  "::mlir::LogicalResult",
+      /*methodName=*/  "isValidAtomicOp",
+      /*args=*/        (ins "::mlir::ptr::AtomicBinOp":$op,
+                            "::mlir::Type":$type,
+                            "::mlir::ptr::AtomicOrdering":$ordering,
+                            "::mlir::IntegerAttr":$alignment,
+                            "::mlir::Operation*":$diagnosticOp),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        This method checks if it's valid to perform an atomic exchange operation
+        in the memory space with a specific type, alignment, and atomic
+        orderings.
+        If `diagnosticOp` is non-null then the method might emit diagnostics.
+      }],
+      /*returnType=*/  "::mlir::LogicalResult",
+      /*methodName=*/  "isValidAtomicXchg",
+      /*args=*/        (ins "::mlir::Type":$type,
+                            "::mlir::ptr::AtomicOrdering":$successOrdering,
+                            "::mlir::ptr::AtomicOrdering":$failureOrdering,
+                            "::mlir::IntegerAttr":$alignment,
+                            "::mlir::Operation*":$diagnosticOp),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        This method checks if it's valid to perform an `addrspacecast` op
+        in the memory space.
+        Both types are expected to be vectors of rank 1, or scalars of `ptr`
+        type.
+        If `diagnosticOp` is non-null then the method might emit diagnostics.
+      }],
+      /*returnType=*/  "::mlir::LogicalResult",
+      /*methodName=*/  "isValidAddrSpaceCast",
+      /*args=*/        (ins "::mlir::Type":$tgt,
+                            "::mlir::Type":$src,
+                            "::mlir::Operation*":$diagnosticOp),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+    InterfaceMethod<
+      /*desc=*/        [{
+        This method checks if it's valid to perform a `ptrtoint` or `inttoptr`
+        op in the memory space. `CastValidity::InvalidSourceType` always refers
+        to the 'ptr-like' type and `CastValidity::InvalidTargetType` always
+        refers to the `int-like` type.
+        The first type is expected to be integer-like, while the second must be a
+        ptr-like type.
+        If `diagnosticOp` is non-null then the method might emit diagnostics.
+      }],
+      /*returnType=*/  "::mlir::LogicalResult",
+      /*methodName=*/  "isValidPtrIntCast",
+      /*args=*/        (ins "::mlir::Type":$intLikeTy,
+                            "::mlir::Type":$ptrLikeTy,
+                            "::mlir::Operation*":$diagnosticOp),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+    >,
+  ];
+}
+
+def MemoryModelOpInterface : OpInterface<"MemoryModelOpInterface"> {
+  let description = [{
+    An interface for operations with a memory model.
+  }];
+
+  let cppNamespace = "::mlir::ptr";
+
+  let methods = [
+    InterfaceMethod<
+      /*desc=*/        "Returns the memory model of the op.",
+      /*returnType=*/  "MemoryModel",
+      /*methodName=*/  "getMemoryModel",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{}]
+      >,
+  ];
+}
+#endif // PTR_MEMORYSPACEINTERFACES
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.h b/mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.h
new file mode 100644
index 00000000000000..019ba71d74eacc
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.h
@@ -0,0 +1,41 @@
+//===- PtrAttrs.h - Pointer dialect attributes ------------------*- C++ -*-===//
+//
+// This file is licensed 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the Ptr dialect attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_PTR_IR_PTRATTRS_H
+#define MLIR_DIALECT_PTR_IR_PTRATTRS_H
+
+#include "mlir/IR/OpImplementation.h"
+
+namespace mlir {
+namespace ptr {
+/// Base class for Ptr attributes participating in the TBAA graph.
+class TBAANodeAttr : public Attribute {
+public:
+  using Attribute::Attribute;
+
+  /// Support LLVM type casting.
+  static bool classof(Attribute attr);
+
+  /// Required by DenseMapInfo to create empty and tombstone key.
+  static TBAANodeAttr getFromOpaquePointer(const void *pointer) {
+    return TBAANodeAttr(reinterpret_cast<const ImplType *>(pointer));
+  }
+};
+} // namespace ptr
+} // namespace mlir
+
+#include "mlir/Dialect/Ptr/IR/PtrOpsEnums.h.inc"
+
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/Ptr/IR/PtrOpsAttrs.h.inc"
+
+#endif // MLIR_DIALECT_PTR_IR_PTRATTRS_H
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.td b/mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.td
new file mode 100644
index 00000000000000..b9496a4152f11a
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.td
@@ -0,0 +1,292 @@
+//===-- PtrAttrDefs.td - Ptr Attributes definition file ----*- tablegen -*-===//
+//
+// 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 PTR_ATTRDEFS
+#define PTR_ATTRDEFS
+
+include "mlir/Dialect/Ptr/IR/PtrDialect.td"
+include "mlir/IR/AttrTypeBase.td"
+
+// All of the attributes will extend this class.
+class Ptr_Attr<string name, string attrMnemonic,
+                list<Trait> traits = [],
+                string baseCppClass = "::mlir::Attribute">
+    : AttrDef<Ptr_Dialect, name, traits, baseCppClass> {
+  let mnemonic = attrMnemonic;
+}
+
+//===----------------------------------------------------------------------===//
+// AliasScopeDomainAttr
+//===----------------------------------------------------------------------===//
+
+def Ptr_AliasScopeDomainAttr : Ptr_Attr<"AliasScopeDomain",
+                                        "alias_scope_domain"> {
+  let parameters = (ins
+    "DistinctAttr":$id,
+    OptionalParameter<"StringAttr">:$description
+  );
+
+  let builders = [
+    AttrBuilder<(ins CArg<"StringAttr", "{}">:$description), [{
+      return $_get($_ctxt,
+                   DistinctAttr::create(UnitAttr::get($_ctxt)), description);
+    }]>
+  ];
+
+  let summary = "Ptr dialect alias scope domain metadata";
+
+  let description = [{
+    Defines a domain that may be associated with an alias scope.
+
+    See the following link for more details:
+    https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// AliasScopeAttr
+//===----------------------------------------------------------------------===//
+
+def Ptr_AliasScopeAttr : Ptr_Attr<"AliasScope", "alias_scope"> {
+  let parameters = (ins
+    "DistinctAttr":$id,
+    "AliasScopeDomainAttr":$domain,
+    OptionalParameter<"StringAttr">:$description
+  );
+
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "AliasScopeDomainAttr":$domain,
+      CArg<"StringAttr", "{}">:$description
+    ), [{
+      MLIRContext *ctx = domain.getContext();
+      return $_get(ctx, DistinctAttr::create(UnitAttr::get(ctx)), domain, description);
+    }]>
+  ];
+
+  let description = [{
+    Defines an alias scope that can be attached to a memory-accessing operation.
+    Such scopes can be used in combination with `noalias` metadata to indicate
+    that sets of memory-affecting operations in one scope do not alias with
+    memory-affecting operations in another scope.
+
+    Example:
+    ```mlir
+    #domain = #ptr.alias_scope_domain<id = distinct[1]<>, description = "Optional domain description">
+    #scope1 = #ptr.alias_scope<id = distinct[2]<>, domain = #domain>
+    #scope2 = #ptr.alias_scope<id = distinct[3]<>, domain = #domain, description = "Optional scope description">
+    ptr.func @foo(%ptr1 : !ptr.ptr) {
+        %c0 = llvm.mlir.constant(0 : i32) : i32
+        %c4 = llvm.mlir.constant(4 : i32) : i32
+        %1 = ptr.ptrtoint %ptr1 : !ptr.ptr to i32
+        %2 = llvm.add %1, %c1 : i32
+        %ptr2 = ptr.inttoptr %2 : i32 to !ptr.ptr
+        ptr.store %c0, %ptr1 { alias_scopes = [#scope1], ptr.noalias = [#scope2] } : i32, !ptr.ptr
+        ptr.store %c4, %ptr2 { alias_scopes = [#scope2], ptr.noalias = [#scope1] } : i32, !ptr.ptr
+        llvm.return
+    }
+    ```
+
+    See the following link for more details:
+    https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
+  }];
+
+  let summary = "Ptr dialect alias scope";
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+def Ptr_AliasScopeArrayAttr
+    : TypedArrayAttrBase<Ptr_AliasScopeAttr,
+                         Ptr_AliasScopeAttr.summary # " array"> {
+  let constBuilderCall = ?;
+}
+
+//===----------------------------------------------------------------------===//
+// AccessGroupAttr
+//===----------------------------------------------------------------------===//
+
+def Ptr_AccessGroupAttr : Ptr_Attr<"AccessGroup", "access_group"> {
+
+  let parameters = (ins "DistinctAttr":$id);
+
+  let builders = [
+    AttrBuilder<(ins), [{
+      return $_get($_ctxt, DistinctAttr::create(UnitAttr::get($_ctxt)));
+    }]>
+  ];
+
+  let summary = "Ptr dialect access group metadata";
+
+  let description = [{
+    Defines an access group metadata that can be set on any instruction
+    that potentially accesses memory via the `AccessGroupOpInterface` or on
+    branch instructions in the loop latch block via the `parallelAccesses`
+    parameter of `LLVM::LoopAnnotationAttr`.
+
+    See the following link for more details:
+    https://llvm.org/docs/LangRef.html#llvm-access-group-metadata
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+def Ptr_AccessGroupArrayAttr
+    : TypedArrayAttrBase<Ptr_AccessGroupAttr,
+                         Ptr_AccessGroupAttr.summary # " array"> {
+  let constBuilderCall = ?;
+}
+
+//===----------------------------------------------------------------------===//
+// TBAARootAttr
+//===----------------------------------------------------------------------===//
+
+def Ptr_TBAARootAttr : Ptr_Attr<"TBAARoot", "tbaa_root", [], "TBAANodeAttr"> {
+  let parameters = (ins OptionalParameter<"StringAttr">:$id);
+
+  let summary = "Ptr dialect TBAA root metadata";
+  let description = [{
+    Defines a TBAA root node.
+
+    Example:
+    ```mlir
+    #cpp_root = #ptr.tbaa_root<identity = "Simple C/C++ TBAA">
+    #other_root = #ptr.tbaa_root
+    ```
+
+    See the following link for more details:
+    https://llvm.org/docs/LangRef.html#tbaa-metadata
+  }];
+
+  let assemblyFormat = "(`<` struct(params)^ `>`)?";
+}
+
+//===----------------------------------------------------------------------===//
+// TBAATypeDescriptorAttr
+//===----------------------------------------------------------------------===//
+
+def Ptr_TBAAMemberAttr : Ptr_Attr<"TBAAMember", "tbaa_member"> {
+  let parameters = (ins
+    "TBAANodeAttr":$typeDesc,
+    "int64_t":$offset
+  );
+
+  let builders = [
+    AttrBuilderWithInferredContext<(ins "TBAANodeAttr":$typeDesc,
+                                        "int64_t":$offset), [{
+      return $_get(typeDesc.getContext(), typeDesc, offset);
+    }]>
+  ];
+
+  let assemblyFormat = "`<` params `>`";
+}
+
+def Ptr_TBAAMemberAttrArray : ArrayRefParameter<"TBAAMemberAttr"> {
+  let printer = [{
+    $_printer << '{';
+    llvm::interleaveComma($_self, $_printer, [&](TBAAMemberAttr attr) {
+        $_printer.printStrippedAttrOrType(attr);
+    });
+    $_printer << '}';
+  }];
+
+  let parser = [{
+    [&]() -> FailureOr<SmallVector<TBAAMemberAttr>> {
+        using Result = SmallVector<TBAAMemberAttr>;
+        if ($_parser.parseLBrace())
+            return failure();
+        FailureOr<Result> result = FieldParser<Result>::parse($_parser);
+        if (failed(result))
+            return failure();
+        if ($_parser.parseRBrace())
+            return failure();
+        return result;
+    }()
+  }];
+}
+
+def Ptr_TBAATypeDescriptorAttr : Ptr_Attr<"TBAATypeDescriptor",
+    "tbaa_type_desc", [], "TBAANodeAttr"> {
+  let parameters = (ins
+    StringRefParameter<>:$id,
+    Ptr_TBAAMemberAttrArray:$members
+  );
+
+  let summary = "Ptr dialect TBAA type metadata";
+
+  let description = [{
+    Defines a TBAA node describing a type.
+
+    Example:
+    ```mlir
+    #tbaa_root = #ptr.tbaa_root<identity = "Simple C/C++ TBAA">
+    #tbaa_type_desc1 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
+    #tbaa_type_desc2 = #ptr.tbaa_type_desc<id = "long long", members = {<#tbaa_root, 0>}>
+    #tbaa_type_desc3 = #ptr.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc2, 0>, <#tbaa_type_desc2, 8>}>
+    #tbaa_type_desc4 = #ptr.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc1, 0>}>
+    #tbaa_type_desc5 = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc4, 0>, <#tbaa_type_desc4, 4>}>
+    ```
+
+    See the following link for more details:
+    https://llvm.org/docs/LangRef.html#tbaa-metadata
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// TBAATagAttr
+//===----------------------------------------------------------------------===//
+
+def Ptr_TBAATagAttr : Ptr_Attr<"TBAATag", "tbaa_tag"> {
+  let parameters = (ins
+    "TBAATypeDescriptorAttr":$base_type,
+    "TBAATypeDescriptorAttr":$access_type,
+    "int64_t":$offset,
+    DefaultValuedParameter<"bool", "false">:$constant
+  );
+
+  let builders = [
+    AttrBuilderWithInferredContext<(ins "TBAATypeDescriptorAttr":$baseType,
+                                        "TBAATypeDescriptorAttr":$accessType,
+                                        "int64_t":$offset), [{
+      return $_get(baseType.getContext(), baseType, accessType, offset,
+                    /*constant=*/false);
+    }]>
+  ];
+
+  let summary = "Ptr dialect TBAA tag metadata";
+
+  let description = [{
+    Defines a TBAA node describing a memory access.
+
+    Example:
+    ```mlir
+    #tbaa_root = #ptr.tbaa_root<identity = "Simple C/C++ TBAA">
+    #tbaa_type_desc1 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
+    #tbaa_type_desc2 = #ptr.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc1, 0>}>
+    #tbaa_type_desc3 = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc4, 0>, <#tbaa_type_desc4, 4>}>
+    #tbaa_tag = #ptr.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc2, offset = 0, constant = true>
+    ```
+
+    See the following link for more details:
+    https://llvm.org/docs/LangRef.html#tbaa-metadata
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+def Ptr_TBAATagArrayAttr
+    : TypedArrayAttrBase<Ptr_TBAATagAttr,
+                         Ptr_TBAATagAttr.summary # " array"> {
+  let constBuilderCall = ?;
+}
+
+#endif // PTR_ATTRDEFS
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.h b/mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.h
new file mode 100644
index 00000000000000..1e91ce60821d4b
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.h
@@ -0,0 +1,20 @@
+//===- PointerDialect.h - Pointer dialect -----------------------*- C++ -*-===//
+//
+// This file is licensed 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Ptr dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_PTR_IR_PTRDIALECT_H
+#define MLIR_DIALECT_PTR_IR_PTRDIALECT_H
+
+#include "mlir/IR/Dialect.h"
+
+#include "mlir/Dialect/Ptr/IR/PtrOpsDialect.h.inc"
+
+#endif // MLIR_DIALECT_PTR_IR_PTRDIALECT_H
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.td b/mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.td
new file mode 100644
index 00000000000000..13647622bb1e7b
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.td
@@ -0,0 +1,89 @@
+//===- PointerDialect.td - Pointer dialect -----------------*- tablegen -*-===//
+//
+// This file is licensed 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 PTR_DIALECT
+#define PTR_DIALECT
+
+include "mlir/Interfaces/DataLayoutInterfaces.td"
+include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/BuiltinTypeInterfaces.td"
+include "mlir/IR/AsmInterfaces.td"
+include "mlir/IR/OpBase.td"
+
+//===----------------------------------------------------------------------===//
+// Pointer dialect definition.
+//===----------------------------------------------------------------------===//
+
+def Ptr_Dialect : Dialect {
+  let name = "ptr";
+  let summary = "Pointer dialect";
+  let cppNamespace = "::mlir::ptr";
+  let useDefaultTypePrinterParser = 1;
+  let useDefaultAttributePrinterParser = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer type definitions
+//===----------------------------------------------------------------------===//
+
+class Ptr_Type<string name, string typeMnemonic, list<Trait> traits = []>
+    : TypeDef<Ptr_Dialect, name, traits> {
+  let mnemonic = typeMnemonic;
+}
+
+def Ptr_PtrType : Ptr_Type<"Ptr", "ptr", [
+    MemRefElementTypeInterface,
+    DeclareTypeInterfaceMethods<DataLayoutTypeInterface, [
+      "areCompatible", "getIndexBitwidth", "verifyEntries"]>,
+    DeclareTypeInterfaceMethods<TypeAsmAliasTypeInterface, [
+      "getAliasDialect"]>
+  ]> {
+  let summary = "pointer type";
+  let description = [{
+    The `ptr` type is an opaque pointer type. This type typically represents
+    a reference to an object in memory. Pointers are optionally parameterized
+    by a memory space.
+    Syntax:
+
+    ```mlir
+    pointer ::= `ptr` (`<` memory-space `>`)?
+    memory-space ::= attribute-value
+    ```
+  }];
+  let parameters = (ins OptionalParameter<"Attribute">:$memorySpace);
+  let assemblyFormat = "(`<` $memorySpace^ `>`)?";
+  let builders = [
+    TypeBuilder<(ins CArg<"Attribute", "nullptr">:$addressSpace), [{
+      return $_get($_ctxt, addressSpace);
+    }]>,
+    TypeBuilder<(ins CArg<"unsigned">:$addressSpace), [{
+      return $_get($_ctxt, IntegerAttr::get(IntegerType::get($_ctxt, 32),
+                                            addressSpace));
+    }]>
+  ];
+  let skipDefaultBuilders = 1;
+  let extraClassDeclaration = [{
+    /// Returns the default memory space.
+    Attribute getDefaultMemorySpace() const;
+
+    /// Returns the memory space as an unsigned number.
+    int64_t getAddressSpace() const;
+
+    /// Returns the memory space attribute wrapped in the `MemoryModel` class.
+    MemoryModel getMemoryModel() const;
+  }];
+}
+
+//===----------------------------------------------------------------------===//
+// Base address operation definition.
+//===----------------------------------------------------------------------===//
+
+class Pointer_Op<string mnemonic, list<Trait> traits = []> :
+        Op<Ptr_Dialect, mnemonic, traits>;
+
+#endif // PTR_DIALECT
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrEnums.td b/mlir/include/mlir/Dialect/Ptr/IR/PtrEnums.td
new file mode 100644
index 00000000000000..3a921e4de08d8d
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrEnums.td
@@ -0,0 +1,69 @@
+//===-- PtrEnums.td - Ptr dialect enumerations -------------*- tablegen -*-===//
+//
+// 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 PTR_ENUMS
+#define PTR_ENUMS
+
+include "mlir/IR/EnumAttr.td"
+
+//===----------------------------------------------------------------------===//
+// Atomic binary op enum attribute
+//===----------------------------------------------------------------------===//
+
+def AtomicBinOpXchg : I64EnumAttrCase<"xchg", 0, "xchg">;
+def AtomicBinOpAdd  : I64EnumAttrCase<"add", 1, "add">;
+def AtomicBinOpSub  : I64EnumAttrCase<"sub", 2, "sub">;
+def AtomicBinOpAnd  : I64EnumAttrCase<"_and", 3, "_and">;
+def AtomicBinOpNand : I64EnumAttrCase<"nand", 4, "nand">;
+def AtomicBinOpOr   : I64EnumAttrCase<"_or", 5, "_or">;
+def AtomicBinOpXor  : I64EnumAttrCase<"_xor", 6, "_xor">;
+def AtomicBinOpMax  : I64EnumAttrCase<"max", 7, "max">;
+def AtomicBinOpMin  : I64EnumAttrCase<"min", 8, "min">;
+def AtomicBinOpUMax : I64EnumAttrCase<"umax", 9, "umax">;
+def AtomicBinOpUMin : I64EnumAttrCase<"umin", 10, "umin">;
+def AtomicBinOpFAdd : I64EnumAttrCase<"fadd", 11, "fadd">;
+def AtomicBinOpFSub : I64EnumAttrCase<"fsub", 12, "fsub">;
+def AtomicBinOpFMax : I64EnumAttrCase<"fmax", 13, "fmax">;
+def AtomicBinOpFMin : I64EnumAttrCase<"fmin", 14, "fmin">;
+def AtomicBinOpUIncWrap : I64EnumAttrCase<"uinc_wrap", 15, "uinc_wrap">;
+def AtomicBinOpUDecWrap : I64EnumAttrCase<"udec_wrap", 16, "udec_wrap">;
+
+def AtomicBinOp : I64EnumAttr<
+    "AtomicBinOp",
+    "ptr.atomicrmw binary operations",
+    [AtomicBinOpXchg, AtomicBinOpAdd, AtomicBinOpSub, AtomicBinOpAnd,
+     AtomicBinOpNand, AtomicBinOpOr, AtomicBinOpXor, AtomicBinOpMax,
+     AtomicBinOpMin, AtomicBinOpUMax, AtomicBinOpUMin, AtomicBinOpFAdd,
+     AtomicBinOpFSub, AtomicBinOpFMax, AtomicBinOpFMin, AtomicBinOpUIncWrap,
+     AtomicBinOpUDecWrap]> {
+  let cppNamespace = "::mlir::ptr";
+}
+
+//===----------------------------------------------------------------------===//
+// Atomic ordering enum attribute
+//===----------------------------------------------------------------------===//
+
+def AtomicOrderingNotAtomic : I64EnumAttrCase<"not_atomic", 0, "not_atomic">;
+def AtomicOrderingUnordered : I64EnumAttrCase<"unordered", 1, "unordered">;
+def AtomicOrderingMonotonic : I64EnumAttrCase<"monotonic", 2, "monotonic">;
+def AtomicOrderingAcquire   : I64EnumAttrCase<"acquire", 3, "acquire">;
+def AtomicOrderingRelease   : I64EnumAttrCase<"release", 4, "release">;
+def AtomicOrderingAcqRel    : I64EnumAttrCase<"acq_rel", 5, "acq_rel">;
+def AtomicOrderingSeqCst    : I64EnumAttrCase<"seq_cst", 6, "seq_cst">;
+
+def AtomicOrdering : I64EnumAttr<
+    "AtomicOrdering",
+    "Atomic ordering for LLVM's memory model",
+    [AtomicOrderingNotAtomic, AtomicOrderingUnordered, AtomicOrderingMonotonic,
+     AtomicOrderingAcquire, AtomicOrderingRelease, AtomicOrderingAcqRel,
+     AtomicOrderingSeqCst
+    ]> {
+  let cppNamespace = "::mlir::ptr";
+}
+
+#endif // PTR_ENUMS
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.h b/mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.h
new file mode 100644
index 00000000000000..668f9077481fd9
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.h
@@ -0,0 +1,34 @@
+//===- PtrInterfaces.h - Ptr Interfaces -------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines op interfaces for the Ptr dialect in MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_PTR_IR_PTRINTERFACES_H
+#define MLIR_DIALECT_PTR_IR_PTRINTERFACES_H
+
+#include "mlir/Dialect/Ptr/IR/PtrAttrs.h"
+
+namespace mlir {
+namespace ptr {
+namespace detail {
+/// Verifies the access groups attribute of memory operations that implement the
+/// access group interface.
+LogicalResult verifyAccessGroupOpInterface(Operation *op);
+
+/// Verifies the alias analysis attributes of memory operations that implement
+/// the alias analysis interface.
+LogicalResult verifyAliasAnalysisOpInterface(Operation *op);
+} // namespace detail
+} // namespace ptr
+} // namespace mlir
+
+#include "mlir/Dialect/Ptr/IR/PtrInterfaces.h.inc"
+
+#endif // MLIR_DIALECT_PTR_IR_PTRINTERFACES_H
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.td b/mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.td
new file mode 100644
index 00000000000000..d8062ed2726ffe
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrInterfaces.td
@@ -0,0 +1,152 @@
+//===-- PtrInterfaces.td - Ptr dialect interfaces ----------*- tablegen -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ptr dialect interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef PTR_INTERFACES
+#define PTR_INTERFACES
+
+include "mlir/IR/OpBase.td"
+
+//===----------------------------------------------------------------------===//
+// Access group interface.
+//===----------------------------------------------------------------------===//
+
+def AccessGroupOpInterface : OpInterface<"AccessGroupOpInterface"> {
+  let description = [{
+    An interface for memory operations that can carry access groups metadata.
+    It provides setters and getters for the operation's access groups attribute.
+    The default implementations of the interface methods expect the operation
+    to have an attribute of type ArrayAttr named access_groups.
+  }];
+
+  let cppNamespace = "::mlir::ptr";
+  let verify = [{ return detail::verifyAccessGroupOpInterface($_op); }];
+
+  let methods = [
+    InterfaceMethod<
+      /*desc=*/        "Returns the access groups attribute or nullptr",
+      /*returnType=*/  "ArrayAttr",
+      /*methodName=*/  "getAccessGroupsOrNull",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        return op.getAccessGroupsAttr();
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Sets the access groups attribute",
+      /*returnType=*/  "void",
+      /*methodName=*/  "setAccessGroups",
+      /*args=*/        (ins "const ArrayAttr":$attr),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        op.setAccessGroupsAttr(attr);
+      }]
+      >
+  ];
+}
+
+//===----------------------------------------------------------------------===//
+// Alias analysis interface.
+//===----------------------------------------------------------------------===//
+
+def AliasAnalysisOpInterface : OpInterface<"AliasAnalysisOpInterface"> {
+  let description = [{
+    An interface for memory operations that can carry alias analysis metadata.
+    It provides setters and getters for the operation's alias analysis
+    attributes. The default implementations of the interface methods expect
+    the operation to have attributes of type ArrayAttr named alias_scopes,
+    noalias_scopes, and tbaa.
+  }];
+
+  let cppNamespace = "::mlir::ptr";
+  let verify = [{ return detail::verifyAliasAnalysisOpInterface($_op); }];
+
+  let methods = [
+    InterfaceMethod<
+      /*desc=*/        "Returns the alias scopes attribute or nullptr",
+      /*returnType=*/  "ArrayAttr",
+      /*methodName=*/  "getAliasScopesOrNull",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        return op.getAliasScopesAttr();
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Sets the alias scopes attribute",
+      /*returnType=*/  "void",
+      /*methodName=*/  "setAliasScopes",
+      /*args=*/        (ins "const ArrayAttr":$attr),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        op.setAliasScopesAttr(attr);
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Returns the noalias scopes attribute or nullptr",
+      /*returnType=*/  "ArrayAttr",
+      /*methodName=*/  "getNoAliasScopesOrNull",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        return op.getNoaliasScopesAttr();
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Sets the noalias scopes attribute",
+      /*returnType=*/  "void",
+      /*methodName=*/  "setNoAliasScopes",
+      /*args=*/        (ins "const ArrayAttr":$attr),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        op.setNoaliasScopesAttr(attr);
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Returns the tbaa attribute or nullptr",
+      /*returnType=*/  "ArrayAttr",
+      /*methodName=*/  "getTBAATagsOrNull",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        return op.getTbaaAttr();
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Sets the tbaa attribute",
+      /*returnType=*/  "void",
+      /*methodName=*/  "setTBAATags",
+      /*args=*/        (ins "const ArrayAttr":$attr),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        op.setTbaaAttr(attr);
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Returns a list of all pointer operands accessed by the "
+                       "operation",
+      /*returnType=*/  "::llvm::SmallVector<::mlir::Value>",
+      /*methodName=*/  "getAccessedOperands",
+      /*args=*/        (ins)
+      >
+  ];
+}
+
+#endif // PTR_MEMORYSPACEINTERFACES
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrOps.h b/mlir/include/mlir/Dialect/Ptr/IR/PtrOps.h
new file mode 100644
index 00000000000000..a05e29a395df31
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrOps.h
@@ -0,0 +1,28 @@
+//===- PointerDialect.h - Pointer dialect -----------------------*- C++ -*-===//
+//
+// This file is licensed 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Pointer dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_PTR_IR_PTROPS_H
+#define MLIR_DIALECT_PTR_IR_PTROPS_H
+
+#include "mlir/Bytecode/BytecodeOpInterface.h"
+#include "mlir/Dialect/Ptr/IR/PtrAttrs.h"
+#include "mlir/Dialect/Ptr/IR/PtrDialect.h"
+#include "mlir/Dialect/Ptr/IR/PtrInterfaces.h"
+#include "mlir/Dialect/Ptr/IR/PtrTypes.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/Interfaces/MemorySlotInterfaces.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+
+#define GET_OP_CLASSES
+#include "mlir/Dialect/Ptr/IR/PtrOps.h.inc"
+
+#endif // MLIR_DIALECT_PTR_IR_PTROPS_H
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td b/mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td
new file mode 100644
index 00000000000000..ac789a99cf2a93
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td
@@ -0,0 +1,411 @@
+//===- PointerOps.td - Pointer dialect ops -----------------*- tablegen -*-===//
+//
+// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://ptr.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef PTR_OPS
+#define PTR_OPS
+
+include "mlir/Dialect/Ptr/IR/PtrDialect.td"
+include "mlir/Dialect/Ptr/IR/PtrEnums.td"
+include "mlir/Dialect/Ptr/IR/PtrAttrs.td"
+include "mlir/Dialect/Ptr/IR/PtrInterfaces.td"
+include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td"
+include "mlir/IR/OpAsmInterface.td"
+include "mlir/Interfaces/MemorySlotInterfaces.td"
+include "mlir/Interfaces/SideEffectInterfaces.td"
+include "mlir/IR/EnumAttr.td"
+
+//===----------------------------------------------------------------------===//
+// PtrAddOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_PtrAddOp : Pointer_Op<"ptradd", [
+    Pure, AllTypesMatch<["base", "result"]>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Pointer-index add operation";
+  let description = [{
+    The `ptradd` operation adds an `address` and an integer or index to
+    produce a new address.
+
+    Example:
+    ```mlir
+    %addr = ptr.ptradd %addr : !ptr.ptr<3 : i32>, %c10 : i32
+    ```
+  }];
+
+  let arguments = (ins Ptr_PtrType:$base, AnySignlessIntegerOrIndex:$offset);
+  let results = (outs Ptr_PtrType:$result);
+  let assemblyFormat = [{
+    $base custom<PtrType>(type($base)) `,` $offset
+    custom<IntType>(type($offset)) attr-dict
+  }];
+}
+
+//===----------------------------------------------------------------------===//
+// AddrSpaceCastOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_AddrSpaceCastOp : Pointer_Op<"addrspacecast", [
+    Pure,
+    DeclareOpInterfaceMethods<PromotableOpInterface>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Address space cast operation";
+  let description = [{
+    The `addrspacecast` operation casts pointers between memory spaces.
+
+    Example:
+    ```mlir
+    %ptr = ptr.addrspacecast %addr : !ptr.ptr to !ptr.ptr<1 : i32>
+    ```
+  }];
+  let arguments = (ins AnyType:$arg);
+  let results = (outs AnyType:$res);
+  let assemblyFormat = "$arg attr-dict `:` type($arg) `to` type($res)";
+  let hasVerifier = 1;
+  let hasFolder = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// AtomicRMWOp
+//===----------------------------------------------------------------------===//
+
+def PtrAtomicRMWType : AnyTypeOf<[AnyFloat, Ptr_PtrType, AnySignlessInteger]>;
+def Ptr_AtomicRMWOp : Pointer_Op<"atomicrmw", [
+    TypesMatchWith<"result #0 and operand #1 have the same type",
+                    "val", "res", "$_self">,
+    DeclareOpInterfaceMethods<AccessGroupOpInterface>,
+    DeclareOpInterfaceMethods<AliasAnalysisOpInterface>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Atomic read-modify-write operation";
+  let description = [{
+    The `atomicrmw` operation provides a way to perform a read-modify-write
+    sequence that is free from data races. The `bin_op` enumeration specifies
+    the modification to perform. The `val` operand represents the new value to
+    be applied during the modification. The `ptr` operand represents the
+    pointer that the read and write will be performed against.
+    The result represents the latest value that was stored.
+
+    Examples:
+    ```mlir
+      %old = ptr.atomicrmw volatile add %ptr, %val acq_rel `:` !ptr.ptr , i32
+    ```
+  }];
+  let arguments = (ins AtomicBinOp:$bin_op,
+                       Ptr_PtrType:$ptr,
+                       PtrAtomicRMWType:$val,
+                       AtomicOrdering:$ordering,
+                       OptionalAttr<StrAttr>:$syncscope,
+                       OptionalAttr<I64Attr>:$alignment,
+                       UnitAttr:$volatile_,
+                       OptionalAttr<Ptr_AccessGroupArrayAttr>:$access_groups,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$alias_scopes,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$noalias_scopes,
+                       OptionalAttr<Ptr_TBAATagArrayAttr>:$tbaa);
+  let results = (outs PtrAtomicRMWType:$res);
+  let builders = [
+    OpBuilder<(ins "ptr::AtomicBinOp":$binOp, "Value":$ptr, "Value":$val,
+      "ptr::AtomicOrdering":$ordering,
+      CArg<"StringRef", "StringRef()">:$syncscope,
+      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile
+    )>
+  ];
+  let assemblyFormat = [{
+    (`volatile` $volatile_^)? $bin_op $ptr `,` $val
+    (`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict `:`
+    qualified(type($ptr)) `,` type($val)
+  }];
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// AtomicCmpXchgOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_AtomicCmpXchgType : AnyTypeOf<[AnySignlessInteger, Ptr_PtrType]>;
+def Ptr_AtomicCmpXchgOp : Pointer_Op<"cmpxchg", [
+    AllTypesMatch<["val", "cmp", "res"]>,
+    DeclareOpInterfaceMethods<AccessGroupOpInterface>,
+    DeclareOpInterfaceMethods<AliasAnalysisOpInterface>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Atomic compare exchange operation";
+  let description = [{
+    The`cmpxchg` instruction is used to atomically modify memory. It loads a
+    value in memory and compares it to a given value. If they are equal, it
+    tries to store a new value into the memory.
+
+    Examples:
+    ```mlir
+      %res, %status = ptr.cmpxchg %ptr, %cmp, %val acq_rel acq_rel : !ptr.ptr, i32
+    ```
+  }];
+  let arguments = (ins Ptr_PtrType:$ptr,
+                       Ptr_AtomicCmpXchgType:$cmp,
+                       Ptr_AtomicCmpXchgType:$val,
+                       AtomicOrdering:$success_ordering,
+                       AtomicOrdering:$failure_ordering,
+                       OptionalAttr<StrAttr>:$syncscope,
+                       OptionalAttr<I64Attr>:$alignment,
+                       UnitAttr:$weak,
+                       UnitAttr:$volatile_,
+                       OptionalAttr<Ptr_AccessGroupArrayAttr>:$access_groups,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$alias_scopes,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$noalias_scopes,
+                       OptionalAttr<Ptr_TBAATagArrayAttr>:$tbaa);
+  let results = (outs Ptr_AtomicCmpXchgType:$res, I1:$status);
+  let builders = [
+    OpBuilder<(ins "Value":$ptr, "Value":$cmp, "Value":$val,
+      "ptr::AtomicOrdering":$successOrdering,
+      "ptr::AtomicOrdering":$failureOrdering,
+      CArg<"StringRef", "StringRef()">:$syncscope,
+      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isWeak,
+      CArg<"bool", "false">:$isVolatile
+    )>
+  ];
+  let assemblyFormat = [{
+    (`weak` $weak^)? (`volatile` $volatile_^)? $ptr `,` $cmp `,` $val
+    (`syncscope` `(` $syncscope^ `)`)? $success_ordering $failure_ordering
+    attr-dict `:` qualified(type($ptr)) `,` type($val)
+  }];
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// ConstantOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_ConstantOp : Pointer_Op<"constant", [
+    ConstantLike, Pure,
+    DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Pointer constant operation";
+  let description = [{
+    The `ptr.constant` operation produces a pointer-typed SSA value equal to
+    some index constant.
+
+    Example:
+
+    ```mlir
+    %ptr = ptr.constant 0
+    %ptr = ptr.constant 1 : !ptr.ptr<3 : i32>
+    ```
+  }];
+  let arguments = (ins IndexAttr:$value);
+  let results = (outs Ptr_PtrType:$result);
+  let builders = [
+    OpBuilder<(ins "int64_t":$value, CArg<"Attribute", "nullptr">:$addressSpace)>
+  ];
+  let assemblyFormat = "attr-dict $value custom<PtrType>(type($result))";
+  let hasFolder = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// LoadOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_LoadOp : Pointer_Op<"load", [
+    DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
+    DeclareOpInterfaceMethods<PromotableMemOpInterface>,
+    DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>,
+    DeclareOpInterfaceMethods<AccessGroupOpInterface>,
+    DeclareOpInterfaceMethods<AliasAnalysisOpInterface>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Load operation";
+  let description = [{
+    The `load` operation is used to read from memory. A load may be marked as
+    atomic, volatile, and/or nontemporal, and takes a number of optional
+    attributes that specify aliasing information.
+
+    An atomic load only supports a limited set of pointer, integer, and
+    floating point types, and requires an explicit alignment.
+
+    Examples:
+    ```mlir
+    // A volatile load of a float variable.
+    %0 = ptr.load volatile %ptr : !ptr.ptr -> f32
+
+    // A nontemporal load of a float variable.
+    %0 = ptr.load %ptr {nontemporal} : !ptr.ptr -> f32
+
+    // An atomic load of an integer variable.
+    %0 = ptr.load %ptr atomic monotonic {alignment = 8 : i64}
+        : !ptr.ptr -> i64
+    ```
+  }];
+  let arguments = (ins Ptr_PtrType:$addr,
+                       OptionalAttr<I64Attr>:$alignment,
+                       UnitAttr:$volatile_,
+                       UnitAttr:$nontemporal,
+                       UnitAttr:$invariant,
+                       DefaultValuedAttr<
+                         AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering,
+                       OptionalAttr<StrAttr>:$syncscope,
+                       OptionalAttr<Ptr_AccessGroupArrayAttr>:$access_groups,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$alias_scopes,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$noalias_scopes,
+                       OptionalAttr<Ptr_TBAATagArrayAttr>:$tbaa);
+  let results = (outs AnyType:$res);
+  let builders = [
+    OpBuilder<(ins "Type":$type, "Value":$addr,
+      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
+      CArg<"bool", "false">:$isNonTemporal, CArg<"bool", "false">:$isInvariant,
+      CArg<"AtomicOrdering", "AtomicOrdering::not_atomic">:$ordering,
+      CArg<"StringRef", "StringRef()">:$syncscope)>
+  ];
+  let assemblyFormat = [{
+    (`volatile` $volatile_^)? $addr
+    (`atomic` (`syncscope` `(` $syncscope^ `)`)? $ordering^)?
+    (`invariant` $invariant^)?
+    attr-dict `:` qualified(type($addr)) `->` type($res)
+  }];
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// StoreOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_StoreOp : Pointer_Op<"store", [
+    DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
+    DeclareOpInterfaceMethods<PromotableMemOpInterface>,
+    DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>,
+    DeclareOpInterfaceMethods<AccessGroupOpInterface>,
+    DeclareOpInterfaceMethods<AliasAnalysisOpInterface>,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Store operation";
+  let description = [{
+    The `store` operation is used to write to memory. A store may be marked as
+    atomic, volatile, and/or nontemporal, and takes a number of optional
+    attributes that specify aliasing information.
+
+    An atomic store only supports a limited set of pointer, integer, and
+    floating point types, and requires an explicit alignment.
+
+    Examples:
+    ```mlir
+    // A volatile store of a float variable.
+    ptr.store volatile %val, %ptr : f32, !ptr.ptr
+
+    // A nontemporal store of a float variable.
+    ptr.store %val, %ptr {nontemporal} : f32, !ptr.ptr
+
+    // An atomic store of an integer variable.
+    ptr.store %val, %ptr atomic monotonic {alignment = 8 : i64}
+        : i64, !ptr.ptr
+    ```
+  }];
+  let arguments = (ins AnyType:$value,
+                       Ptr_PtrType:$addr,
+                       OptionalAttr<I64Attr>:$alignment,
+                       UnitAttr:$volatile_,
+                       UnitAttr:$nontemporal,
+                       DefaultValuedAttr<
+                         AtomicOrdering, "ptr::AtomicOrdering::not_atomic">:$ordering,
+                       OptionalAttr<StrAttr>:$syncscope,
+                       OptionalAttr<Ptr_AccessGroupArrayAttr>:$access_groups,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$alias_scopes,
+                       OptionalAttr<Ptr_AliasScopeArrayAttr>:$noalias_scopes,
+                       OptionalAttr<Ptr_TBAATagArrayAttr>:$tbaa);
+  let builders = [
+    OpBuilder<(ins "Value":$value, "Value":$addr,
+      CArg<"unsigned", "0">:$alignment, CArg<"bool", "false">:$isVolatile,
+      CArg<"bool", "false">:$isNonTemporal,
+      CArg<"ptr::AtomicOrdering", "ptr::AtomicOrdering::not_atomic">:$ordering,
+      CArg<"StringRef", "StringRef()">:$syncscope)>
+  ];
+  let assemblyFormat = [{
+    (`volatile` $volatile_^)? $value `,` $addr
+    (`atomic` (`syncscope` `(` $syncscope^ `)`)? $ordering^)?
+    attr-dict `:` type($value) `,` qualified(type($addr))
+  }];
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// IntToPtrOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_IntToPtrOp : Pointer_Op<"inttoptr", [
+    Pure,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Integer to a pointer operation";
+  let description = [{
+    The `inttoptr` operation casts an int or index value to a pointer.
+
+    Example:
+    ```mlir
+    %ptr = ptr.inttoptr %int : i32 to !ptr.ptr<1 : i32>
+    ```
+  }];
+  let arguments = (ins AnyType:$arg);
+  let results = (outs AnyType:$res);
+  let assemblyFormat = "$arg attr-dict `:` type($arg) `to` type($res)";
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// PtrToIntOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_PtrToIntOp : Pointer_Op<"ptrtoint", [
+    Pure,
+    DeclareOpInterfaceMethods<MemoryModelOpInterface>
+  ]> {
+  let summary = "Pointer to an integer operation";
+  let description = [{
+    The `ptrtoint` operation casts a pointer value to an int or index.
+
+    Example:
+    ```mlir
+    %int = ptr.ptrtoint %ptr : !ptr.ptr<1 : i32> to i32
+    ```
+  }];
+  let arguments = (ins AnyType:$arg);
+  let results = (outs AnyType:$res);
+  let assemblyFormat = "$arg attr-dict `:` type($arg) `to` type($res)";
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// TypeOffsetOp
+//===----------------------------------------------------------------------===//
+
+def Ptr_TypeOffsetOp : Pointer_Op<"type_offset", [ConstantLike, Pure]> {
+  let summary = "Type offset constant operation";
+  let description = [{
+    The `type_offset` operation produces an int or index-typed SSA value
+    equal to a target-specific constant representing the offset of a single
+    element of the given type. The default return type is `index`.
+    Example:
+
+    ```mlir
+    %0 = ptr.type_offset f32
+    %1 = ptr.type_offset memref<12 x f64> : i32
+    ```
+  }];
+
+  let arguments = (ins TypeAttr:$baseType);
+  let results = (outs AnySignlessIntegerOrIndex:$result);
+  let builders = [
+    OpBuilder<(ins "TypeAttr":$baseType, CArg<"Type", "nullptr">:$resultTy)>
+  ];
+  let assemblyFormat = [{
+     attr-dict $baseType custom<IntType>(type($result))
+  }];
+  let hasFolder = 1;
+}
+
+#endif // PTR_OPS
diff --git a/mlir/include/mlir/Dialect/Ptr/IR/PtrTypes.h b/mlir/include/mlir/Dialect/Ptr/IR/PtrTypes.h
new file mode 100644
index 00000000000000..868d4389193e25
--- /dev/null
+++ b/mlir/include/mlir/Dialect/Ptr/IR/PtrTypes.h
@@ -0,0 +1,39 @@
+//===- PointerTypes.h - Pointer types ---------------------------*- C++ -*-===//
+//
+// This file is licensed 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Pointer dialect types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_PTR_IR_PTRTYPES_H
+#define MLIR_DIALECT_PTR_IR_PTRTYPES_H
+
+#include "mlir/Dialect/Ptr/IR/MemoryModel.h"
+#include "mlir/IR/AsmInterfaces.h"
+#include "mlir/IR/Types.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+
+namespace mlir {
+namespace ptr {
+/// The positions of different values in the data layout entry for pointers.
+enum class PtrDLEntryPos { Size = 0, Abi = 1, Preferred = 2, Index = 3 };
+
+/// Returns the value that corresponds to named position `pos` from the
+/// data layout entry `attr` assuming it's a dense integer elements attribute.
+/// Returns `std::nullopt` if `pos` is not present in the entry.
+/// Currently only `PtrDLEntryPos::Index` is optional, and all other positions
+/// may be assumed to be present.
+std::optional<uint64_t> extractPointerSpecValue(Attribute attr,
+                                                PtrDLEntryPos pos);
+} // namespace ptr
+} // namespace mlir
+
+#define GET_TYPEDEF_CLASSES
+#include "mlir/Dialect/Ptr/IR/PtrOpsTypes.h.inc"
+
+#endif // MLIR_DIALECT_PTR_IR_PTRTYPES_H
diff --git a/mlir/include/mlir/IR/AsmInterfaces.h b/mlir/include/mlir/IR/AsmInterfaces.h
new file mode 100644
index 00000000000000..00c4ecf58867d3
--- /dev/null
+++ b/mlir/include/mlir/IR/AsmInterfaces.h
@@ -0,0 +1,19 @@
+//===- AsmInterfaces.h - Asm Interfaces -------------------------*- C++ -*-===//
+//
+// 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_IR_ASMINTERFACES_H
+#define MLIR_IR_ASMINTERFACES_H
+
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Types.h"
+
+#include "mlir/IR/AsmAttrInterfaces.h.inc"
+
+#include "mlir/IR/AsmTypeInterfaces.h.inc"
+
+#endif // MLIR_IR_ASMINTERFACES_H
\ No newline at end of file
diff --git a/mlir/include/mlir/IR/AsmInterfaces.td b/mlir/include/mlir/IR/AsmInterfaces.td
new file mode 100644
index 00000000000000..88f8d37a86f68c
--- /dev/null
+++ b/mlir/include/mlir/IR/AsmInterfaces.td
@@ -0,0 +1,60 @@
+//===- AsmInterfaces.td - Asm Interfaces -------------------*- tablegen -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains interfaces and other utilities for interacting with the
+// AsmParser and AsmPrinter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_IR_ASMINTERFACES_TD
+#define MLIR_IR_ASMINTERFACES_TD
+
+include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/OpBase.td"
+
+//===----------------------------------------------------------------------===//
+// AttrAsmAliasAttrInterface
+//===----------------------------------------------------------------------===//
+
+def AttrAsmAliasAttrInterface : AttrInterface<"AttrAsmAliasAttrInterface"> {
+  let cppNamespace = "::mlir";
+  let description = [{
+    This interface allows aliasing an attribute between dialects, allowing
+    custom printing of an attribute by an external dialect.
+  }];
+  let methods = [
+    InterfaceMethod<[{
+        Returns the dialect responsible for printing and parsing the attribute
+        instance.
+      }],
+      "Dialect*", "getAliasDialect", (ins), [{}], [{}]
+    >
+  ];
+}
+
+//===----------------------------------------------------------------------===//
+// TypeAsmAliasTypeInterface
+//===----------------------------------------------------------------------===//
+
+def TypeAsmAliasTypeInterface : TypeInterface<"TypeAsmAliasTypeInterface"> {
+  let cppNamespace = "::mlir";
+  let description = [{
+    This interface allows aliasing a type between dialects, allowing custom
+    printing of a type by an external dialect.
+  }];
+  let methods = [
+    InterfaceMethod<[{
+        Returns the dialect responsible for printing and parsing the type
+        instance.
+      }],
+      "Dialect*", "getAliasDialect", (ins), [{}], [{}]
+    >
+  ];
+}
+
+#endif // MLIR_IR_ASMINTERFACES_TD
diff --git a/mlir/include/mlir/IR/CMakeLists.txt b/mlir/include/mlir/IR/CMakeLists.txt
index 04a57d26a068d5..d10a1bec682bc2 100644
--- a/mlir/include/mlir/IR/CMakeLists.txt
+++ b/mlir/include/mlir/IR/CMakeLists.txt
@@ -2,6 +2,13 @@ add_mlir_interface(OpAsmInterface)
 add_mlir_interface(SymbolInterfaces)
 add_mlir_interface(RegionKindInterface)
 
+set(LLVM_TARGET_DEFINITIONS AsmInterfaces.td)
+mlir_tablegen(AsmAttrInterfaces.h.inc -gen-attr-interface-decls)
+mlir_tablegen(AsmAttrInterfaces.cpp.inc -gen-attr-interface-defs)
+mlir_tablegen(AsmTypeInterfaces.h.inc -gen-type-interface-decls)
+mlir_tablegen(AsmTypeInterfaces.cpp.inc -gen-type-interface-defs)
+add_public_tablegen_target(MLIRAsmInterfacesIncGen)
+
 set(LLVM_TARGET_DEFINITIONS BuiltinAttributes.td)
 mlir_tablegen(BuiltinAttributes.h.inc -gen-attrdef-decls)
 mlir_tablegen(BuiltinAttributes.cpp.inc -gen-attrdef-defs)
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index 5333d7446df5ca..5176618578d872 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -1715,7 +1715,10 @@ class OpAsmDialectInterface
     OverridableAlias,
     /// An alias was provided and it should be used
     /// (no other hooks will be checked).
-    FinalAlias
+    FinalAlias,
+    /// A dialect alias was provided and it will be used
+    /// (no other hooks will be checked).
+    DialectAlias
   };
 
   /// Hooks for getting an alias identifier alias for a given symbol, that is
@@ -1729,6 +1732,29 @@ class OpAsmDialectInterface
     return AliasResult::NoAlias;
   }
 
+  /// Hooks for parsing a dialect alias. The method returns success if the
+  /// dialect has an alias for the symbol, otherwise it must return failure.
+  /// If there was an error during parsing, this method should return success
+  /// and set the attribute to null.
+  virtual LogicalResult parseDialectAlias(DialectAsmParser &parser,
+                                          Attribute &attr, Type type) const {
+    return failure();
+  }
+  virtual LogicalResult parseDialectAlias(DialectAsmParser &parser,
+                                          Type &type) const {
+    return failure();
+  }
+  /// Hooks for printing a dialect alias. The method returns success if the
+  /// dialect has an alias for the symbol, otherwise it must return failure.
+  virtual LogicalResult printDialectAlias(DialectAsmPrinter &printer,
+                                          Attribute attr) const {
+    return failure();
+  }
+  virtual LogicalResult printDialectAlias(DialectAsmPrinter &printer,
+                                          Type type) const {
+    return failure();
+  }
+
   //===--------------------------------------------------------------------===//
   // Resources
   //===--------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/InitAllDialects.h b/mlir/include/mlir/InitAllDialects.h
index c558dc53cc7fac..b0cbb720519edd 100644
--- a/mlir/include/mlir/InitAllDialects.h
+++ b/mlir/include/mlir/InitAllDialects.h
@@ -61,6 +61,7 @@
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/Dialect/PDL/IR/PDL.h"
 #include "mlir/Dialect/PDLInterp/IR/PDLInterp.h"
+#include "mlir/Dialect/Ptr/IR/PtrDialect.h"
 #include "mlir/Dialect/Quant/QuantOps.h"
 #include "mlir/Dialect/SCF/IR/SCF.h"
 #include "mlir/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.h"
@@ -131,6 +132,7 @@ inline void registerAllDialects(DialectRegistry &registry) {
                   omp::OpenMPDialect,
                   pdl::PDLDialect,
                   pdl_interp::PDLInterpDialect,
+                  ptr::PtrDialect,
                   quant::QuantizationDialect,
                   ROCDL::ROCDLDialect,
                   scf::SCFDialect,
diff --git a/mlir/include/mlir/Interfaces/MemorySlotInterfaces.td b/mlir/include/mlir/Interfaces/MemorySlotInterfaces.td
index e10e2d4e104c3e..af120eb059aebf 100644
--- a/mlir/include/mlir/Interfaces/MemorySlotInterfaces.td
+++ b/mlir/include/mlir/Interfaces/MemorySlotInterfaces.td
@@ -229,6 +229,27 @@ def PromotableOpInterface : OpInterface<"PromotableOpInterface"> {
       (ins "const ::llvm::SmallPtrSetImpl<mlir::OpOperand *> &":$blockingUses,
            "::mlir::RewriterBase &":$rewriter)
     >,
+    InterfaceMethod<[{
+        Checks whether the operation requires visiting the mutated
+        definitions by a store operation.
+      }], "bool", "requiresVisitingMutatedDefs", (ins), [{}],
+      [{ return false; }]
+    >,
+    InterfaceMethod<[{
+        Visits all the mutated definitions by a store operation.
+
+        This method will only be called after all blocking issues haven been
+        scheduled for removal and if `requiresVisitingMutatedDefs` returned
+        true.
+
+        The rewriter is located after the promotable operation on call. All IR
+        mutations must happen through the rewriter. During the transformation,
+        *no operation should be deleted*.
+      }],
+      "void", "visitMutatedDefs",
+      (ins "::llvm::ArrayRef<std::pair<::mlir::Operation*, ::mlir::Value>>":$mutatedDefs,
+           "::mlir::RewriterBase &":$rewriter), [{}], [{ return; }]
+    >,
   ];
 }
 
diff --git a/mlir/include/mlir/Target/LLVMIR/Dialect/All.h b/mlir/include/mlir/Target/LLVMIR/Dialect/All.h
index de9d5872cc4546..7c7977cce7a55a 100644
--- a/mlir/include/mlir/Target/LLVMIR/Dialect/All.h
+++ b/mlir/include/mlir/Target/LLVMIR/Dialect/All.h
@@ -26,6 +26,8 @@
 #include "mlir/Target/LLVMIR/Dialect/NVVM/NVVMToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h"
+#include "mlir/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.h"
+#include "mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/SPIRV/SPIRVToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/VCIX/VCIXToLLVMIRTranslation.h"
@@ -47,6 +49,7 @@ static inline void registerAllToLLVMIRTranslations(DialectRegistry &registry) {
   registerNVVMDialectTranslation(registry);
   registerOpenACCDialectTranslation(registry);
   registerOpenMPDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   registerROCDLDialectTranslation(registry);
   registerSPIRVDialectTranslation(registry);
   registerVCIXDialectTranslation(registry);
@@ -65,6 +68,7 @@ registerAllGPUToLLVMIRTranslations(DialectRegistry &registry) {
   registerGPUDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
   registerNVVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   registerROCDLDialectTranslation(registry);
   registerSPIRVDialectTranslation(registry);
 
@@ -77,6 +81,7 @@ registerAllGPUToLLVMIRTranslations(DialectRegistry &registry) {
 static inline void
 registerAllFromLLVMIRTranslations(DialectRegistry &registry) {
   registerLLVMDialectImport(registry);
+  registerPtrDialectImport(registry);
   registerNVVMDialectImport(registry);
 }
 } // namespace mlir
diff --git a/mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.h b/mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.h
new file mode 100644
index 00000000000000..65591600875fe4
--- /dev/null
+++ b/mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.h
@@ -0,0 +1,31 @@
+//===- LLVMIRToPtrTranslation.h - LLVM IR to Ptr Dialect --------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides registration calls for LLVM IR to Ptr dialect translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_TARGET_LLVMIR_DIALECT_PTR_LLVMIRTOPTRTRANSLATION_H
+#define MLIR_TARGET_LLVMIR_DIALECT_PTR_LLVMIRTOPTRTRANSLATION_H
+
+namespace mlir {
+
+class DialectRegistry;
+class MLIRContext;
+
+/// Registers the Ptr dialect and its import from LLVM IR in the given
+/// registry.
+void registerPtrDialectImport(DialectRegistry &registry);
+
+/// Registers the Ptr dialect and its import from LLVM IR with the given
+/// context.
+void registerPtrDialectImport(MLIRContext &context);
+
+} // namespace mlir
+
+#endif // MLIR_TARGET_LLVMIR_DIALECT_PTR_LLVMIRTOPTRTRANSLATION_H
diff --git a/mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h b/mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h
new file mode 100644
index 00000000000000..5dc1b0e45995ca
--- /dev/null
+++ b/mlir/include/mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h
@@ -0,0 +1,31 @@
+//===- PtrToLLVMIRTranslation.h - Ptr Dialect to LLVM IR --------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides registration calls for Ptr dialect to LLVM IR translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_TARGET_LLVMIR_DIALECT_PTR_PTRTOLLVMIRTRANSLATION_H
+#define MLIR_TARGET_LLVMIR_DIALECT_PTR_PTRTOLLVMIRTRANSLATION_H
+
+namespace mlir {
+
+class DialectRegistry;
+class MLIRContext;
+
+/// Register the Ptr dialect and the translation from it to the LLVM IR in
+/// the given registry;
+void registerPtrDialectTranslation(DialectRegistry &registry);
+
+/// Register the Ptr dialect and the translation from it in the registry
+/// associated with the given context.
+void registerPtrDialectTranslation(MLIRContext &context);
+
+} // namespace mlir
+
+#endif // MLIR_TARGET_LLVMIR_DIALECT_PTR_PTRTOLLVMIRTRANSLATION_H
diff --git a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
index 9f8da83ae9c205..1bd81fcd9400cb 100644
--- a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
+++ b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
@@ -52,6 +52,15 @@ class LLVMImportDialectInterface
     return failure();
   }
 
+  /// Hook for derived dialect interfaces to implement the import of
+  /// instructions into MLIR.
+  virtual LogicalResult
+  convertInstruction(OpBuilder &builder, llvm::Instruction *inst,
+                     ArrayRef<llvm::Value *> llvmOperands,
+                     LLVM::ModuleImport &moduleImport) const {
+    return failure();
+  }
+
   /// Hook for derived dialect interfaces to implement the import of metadata
   /// into MLIR. Attaches the converted metadata kind and node to the provided
   /// operation.
@@ -66,6 +75,11 @@ class LLVMImportDialectInterface
   /// returns the list of supported intrinsic identifiers.
   virtual ArrayRef<unsigned> getSupportedIntrinsics() const { return {}; }
 
+  /// Hook for derived dialect interfaces to publish the supported instructions.
+  /// As every LLVM IR instructions has a unique integer identifier, the
+  /// function returns the list of supported instructions identifiers.
+  virtual ArrayRef<unsigned> getSupportedInstructions() const { return {}; }
+
   /// Hook for derived dialect interfaces to publish the supported metadata
   /// kinds. As every metadata kind has a unique integer identifier, the
   /// function returns the list of supported metadata identifiers.
@@ -100,9 +114,27 @@ class LLVMImportInterface
                           *it, iface.getDialect()->getNamespace(),
                           intrinsicToDialect.lookup(*it)->getNamespace()));
       }
+      const auto *instIt =
+          llvm::find_if(iface.getSupportedInstructions(), [&](unsigned id) {
+            return instructionToDialect.count(id);
+          });
+      if (instIt != iface.getSupportedInstructions().end()) {
+        return emitError(
+            UnknownLoc::get(iface.getContext()),
+            llvm::formatv(
+                "expected unique conversion for instruction ({0}), but "
+                "got conflicting {1} and {2} conversions",
+                *it, iface.getDialect()->getNamespace(),
+                instructionToDialect.lookup(*it)
+                    ->getDialect()
+                    ->getNamespace()));
+      }
       // Add a mapping for all supported intrinsic identifiers.
       for (unsigned id : iface.getSupportedIntrinsics())
         intrinsicToDialect[id] = iface.getDialect();
+      // Add a mapping for all supported instruction identifiers.
+      for (unsigned id : iface.getSupportedInstructions())
+        instructionToDialect[id] = &iface;
       // Add a mapping for all supported metadata kinds.
       for (unsigned kind : iface.getSupportedMetadata())
         metadataToDialect[kind].push_back(iface.getDialect());
@@ -132,6 +164,26 @@ class LLVMImportInterface
     return intrinsicToDialect.count(id);
   }
 
+  /// Converts the LLVM instruction to an MLIR operation if a conversion exists.
+  /// Returns failure otherwise.
+  LogicalResult convertInstruction(OpBuilder &builder, llvm::Instruction *inst,
+                                   ArrayRef<llvm::Value *> llvmOperands,
+                                   LLVM::ModuleImport &moduleImport) const {
+    // Lookup the dialect interface for the given instruction.
+    const LLVMImportDialectInterface *iface =
+        instructionToDialect.lookup(inst->getOpcode());
+    if (!iface)
+      return failure();
+
+    return iface->convertInstruction(builder, inst, llvmOperands, moduleImport);
+  }
+
+  /// Returns true if the given LLVM IR instruction is convertible to an MLIR
+  /// operation.
+  bool isConvertibleInstruction(unsigned id) {
+    return instructionToDialect.count(id);
+  }
+
   /// Attaches the given LLVM metadata to the imported operation if a conversion
   /// to one or more MLIR dialect attributes exists and succeeds. Returns
   /// success if at least one of the conversions is successful and failure if
@@ -166,6 +218,7 @@ class LLVMImportInterface
 
 private:
   DenseMap<unsigned, Dialect *> intrinsicToDialect;
+  DenseMap<unsigned, const LLVMImportDialectInterface *> instructionToDialect;
   DenseMap<unsigned, SmallVector<Dialect *, 1>> metadataToDialect;
 };
 
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index b551eb937cfe8d..f8864fb01a196a 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -75,14 +75,22 @@ class ModuleImport {
   /// Provides write-once access to store the MLIR value corresponding to the
   /// given LLVM value.
   Value &mapValue(llvm::Value *value) {
-    Value &mlir = valueMapping[value];
+    Value &mlir = valueMapping[value].first;
     assert(mlir == nullptr &&
            "attempting to map a value that is already mapped");
     return mlir;
   }
+  std::pair<Value, Operation *> &mapOp(llvm::Value *value) {
+    auto &mlir = valueMapping[value];
+    assert(mlir.first == nullptr &&
+           "attempting to map a value that is already mapped");
+    return mlir;
+  }
 
   /// Returns the MLIR value mapped to the given LLVM value.
-  Value lookupValue(llvm::Value *value) { return valueMapping.lookup(value); }
+  Value lookupValue(llvm::Value *value) {
+    return valueMapping.lookup(value).first;
+  }
 
   /// Stores a mapping between an LLVM instruction and the imported MLIR
   /// operation if the operation returns no result. Asserts if the operation
@@ -107,9 +115,10 @@ class ModuleImport {
   /// Returns the MLIR operation mapped to the given LLVM instruction. Queries
   /// valueMapping and noResultOpMapping to support operations with and without
   /// result.
-  Operation *lookupOperation(llvm::Instruction *inst) {
-    if (Value value = lookupValue(inst))
-      return value.getDefiningOp();
+  Operation *lookupOperation(llvm::Instruction *inst, bool getOp = false) {
+    if (std::pair<Value, Operation *> value = valueMapping.lookup(inst);
+        value.first)
+      return getOp && value.second ? value.second : value.first.getDefiningOp();
     return noResultOpMapping.lookup(inst);
   }
 
@@ -376,7 +385,7 @@ class ModuleImport {
   /// Function-local mapping between original and imported block.
   DenseMap<llvm::BasicBlock *, Block *> blockMapping;
   /// Function-local mapping between original and imported values.
-  DenseMap<llvm::Value *, Value> valueMapping;
+  DenseMap<llvm::Value *, std::pair<Value, Operation *>> valueMapping;
   /// Function-local mapping between original instructions and imported
   /// operations for all operations that return no result. All operations that
   /// return a result have a valueMapping entry instead.
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 310a43e0de96b3..d610f63dfe9a54 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -36,6 +36,10 @@ namespace mlir {
 class Attribute;
 class Block;
 class Location;
+namespace ptr {
+class AliasScopeAttr;
+class AliasScopeDomainAttr;
+} // namespace ptr
 
 namespace LLVM {
 
@@ -43,9 +47,8 @@ namespace detail {
 class DebugTranslation;
 class LoopAnnotationTranslation;
 } // namespace detail
-
-class AliasScopeAttr;
-class AliasScopeDomainAttr;
+using AliasScopeAttr = ::mlir::ptr::AliasScopeAttr;
+using AliasScopeDomainAttr = ::mlir::ptr::AliasScopeDomainAttr;
 class DINodeAttr;
 class LLVMFuncOp;
 class ComdatSelectorOp;
diff --git a/mlir/lib/AsmParser/DialectSymbolParser.cpp b/mlir/lib/AsmParser/DialectSymbolParser.cpp
index 80cce7e6ae43f5..9261ef2fb3eb95 100644
--- a/mlir/lib/AsmParser/DialectSymbolParser.cpp
+++ b/mlir/lib/AsmParser/DialectSymbolParser.cpp
@@ -269,6 +269,12 @@ Attribute Parser::parseExtendedAttr(Type type) {
 
           // Parse the attribute.
           CustomDialectAsmParser customParser(symbolData, *this);
+          if (auto iface = dyn_cast<OpAsmDialectInterface>(dialect)) {
+            Attribute attr{};
+            if (succeeded(iface->parseDialectAlias(customParser, attr, type)))
+              return attr;
+            resetToken(symbolData.data());
+          }
           Attribute attr = dialect->parseAttribute(customParser, attrType);
           resetToken(curLexerPos);
           return attr;
@@ -310,6 +316,12 @@ Type Parser::parseExtendedType() {
 
           // Parse the type.
           CustomDialectAsmParser customParser(symbolData, *this);
+          if (auto iface = dyn_cast<OpAsmDialectInterface>(dialect)) {
+            Type type{};
+            if (succeeded(iface->parseDialectAlias(customParser, type)))
+              return type;
+            resetToken(symbolData.data());
+          }
           Type type = dialect->parseType(customParser);
           resetToken(curLexerPos);
           return type;
diff --git a/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp b/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp
index 77603739137614..fa5a16b476da08 100644
--- a/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp
+++ b/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp
@@ -1072,6 +1072,7 @@ void ConvertAsyncToLLVMPass::runOnOperation() {
   ConversionTarget target(*ctx);
   target.addLegalOp<arith::ConstantOp, func::ConstantOp,
                     UnrealizedConversionCastOp>();
+  target.addLegalDialect<ptr::PtrDialect>();
   target.addLegalDialect<LLVM::LLVMDialect>();
 
   // All operations from Async dialect must be lowered to the runtime API and
diff --git a/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp b/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp
index 6135117348a5b8..ab71c81989fd3c 100644
--- a/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp
+++ b/mlir/lib/Conversion/ConvertToLLVM/ConvertToLLVMPass.cpp
@@ -75,6 +75,7 @@ class ConvertToLLVMPass
   LogicalResult initialize(MLIRContext *context) final {
     RewritePatternSet tempPatterns(context);
     auto target = std::make_shared<ConversionTarget>(*context);
+    target->addLegalDialect<ptr::PtrDialect>();
     target->addLegalDialect<LLVM::LLVMDialect>();
     auto typeConverter = std::make_shared<LLVMTypeConverter>(context);
 
diff --git a/mlir/lib/Conversion/GPUCommon/GPUToLLVMConversion.cpp b/mlir/lib/Conversion/GPUCommon/GPUToLLVMConversion.cpp
index 78d4e806246872..8a437febf84728 100644
--- a/mlir/lib/Conversion/GPUCommon/GPUToLLVMConversion.cpp
+++ b/mlir/lib/Conversion/GPUCommon/GPUToLLVMConversion.cpp
@@ -592,6 +592,7 @@ void GpuToLLVMConversionPass::runOnOperation() {
   options.useBarePtrCallConv = hostBarePtrCallConv;
   RewritePatternSet patterns(context);
   ConversionTarget target(*context);
+  target.addLegalDialect<ptr::PtrDialect>();
   target.addLegalDialect<LLVM::LLVMDialect>();
   LLVMTypeConverter converter(context, options);
 
diff --git a/mlir/lib/Conversion/LLVMCommon/ConversionTarget.cpp b/mlir/lib/Conversion/LLVMCommon/ConversionTarget.cpp
index 56b4bd7d30a104..2fde4c1cd9e2c0 100644
--- a/mlir/lib/Conversion/LLVMCommon/ConversionTarget.cpp
+++ b/mlir/lib/Conversion/LLVMCommon/ConversionTarget.cpp
@@ -13,6 +13,7 @@ using namespace mlir;
 
 mlir::LLVMConversionTarget::LLVMConversionTarget(MLIRContext &ctx)
     : ConversionTarget(ctx) {
+  this->addLegalDialect<ptr::PtrDialect>();
   this->addLegalDialect<LLVM::LLVMDialect>();
   this->addLegalOp<UnrealizedConversionCastOp>();
 }
diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
index 2dc42f0a85e669..e15688a7d52f27 100644
--- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
+++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
@@ -449,17 +449,18 @@ struct GenericAtomicRMWOpLowering
     auto cmpxchg = rewriter.create<LLVM::AtomicCmpXchgOp>(
         loc, dataPtr, loopArgument, result, successOrdering, failureOrdering);
     // Extract the %new_loaded and %ok values from the pair.
-    Value newLoaded = rewriter.create<LLVM::ExtractValueOp>(loc, cmpxchg, 0);
-    Value ok = rewriter.create<LLVM::ExtractValueOp>(loc, cmpxchg, 1);
+    // Value newLoaded = rewriter.create<LLVM::ExtractValueOp>(loc, cmpxchg, 0);
+    // Value ok = rewriter.create<LLVM::ExtractValueOp>(loc, cmpxchg, 1);
 
     // Conditionally branch to the end or back to the loop depending on %ok.
-    rewriter.create<LLVM::CondBrOp>(loc, ok, endBlock, ArrayRef<Value>(),
-                                    loopBlock, newLoaded);
+    rewriter.create<LLVM::CondBrOp>(loc, cmpxchg.getStatus(), endBlock,
+                                    ArrayRef<Value>(), loopBlock,
+                                    cmpxchg.getRes());
 
     rewriter.setInsertionPointToEnd(endBlock);
 
     // The 'result' of the atomic_rmw op is the newly loaded value.
-    rewriter.replaceOp(atomicOp, {newLoaded});
+    rewriter.replaceOp(atomicOp, {cmpxchg.getRes()});
 
     return success();
   }
diff --git a/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp b/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
index 9b5d19ebd783a9..841c695b7050f2 100644
--- a/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
+++ b/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
@@ -469,6 +469,7 @@ struct ConvertNVGPUToNVVMPass
     });
     populateNVGPUToNVVMConversionPatterns(converter, patterns);
     LLVMConversionTarget target(getContext());
+    target.addLegalDialect<ptr::PtrDialect>();
     target.addLegalDialect<::mlir::LLVM::LLVMDialect>();
     target.addLegalDialect<::mlir::arith::ArithDialect>();
     target.addLegalDialect<::mlir::memref::MemRefDialect>();
diff --git a/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp b/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
index 7f91367ad427a2..ea3a4fe5c691ed 100644
--- a/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
+++ b/mlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
@@ -507,7 +507,7 @@ struct ParallelOpLowering : public OpRewritePattern<scf::ParallelOp> {
 static LogicalResult applyPatterns(ModuleOp module, unsigned numThreads) {
   ConversionTarget target(*module.getContext());
   target.addIllegalOp<scf::ReduceOp, scf::ReduceReturnOp, scf::ParallelOp>();
-  target.addLegalDialect<omp::OpenMPDialect, LLVM::LLVMDialect,
+  target.addLegalDialect<omp::OpenMPDialect, ptr::PtrDialect, LLVM::LLVMDialect,
                          memref::MemRefDialect>();
 
   RewritePatternSet patterns(module.getContext());
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp b/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp
index 0e9eb9799c3e0b..5a472c78b66d4e 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp
@@ -312,6 +312,7 @@ class LowerHostCodeToLLVM
     populateSPIRVToLLVMTypeConversion(typeConverter);
 
     ConversionTarget target(*context);
+    target.addLegalDialect<ptr::PtrDialect>();
     target.addLegalDialect<LLVM::LLVMDialect>();
     if (failed(applyPartialConversion(module, target, std::move(patterns))))
       signalPassFailure();
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVMPass.cpp b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVMPass.cpp
index 38091e449c56ee..adc69e418f4ef0 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVMPass.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVMPass.cpp
@@ -59,6 +59,7 @@ void ConvertSPIRVToLLVMPass::runOnOperation() {
   ConversionTarget target(*context);
   target.addIllegalDialect<spirv::SPIRVDialect>();
   target.addLegalDialect<LLVM::LLVMDialect>();
+  target.addLegalDialect<ptr::PtrDialect>();
 
   if (clientAPI != spirv::ClientAPI::OpenCL &&
       clientAPI != spirv::ClientAPI::Unknown)
diff --git a/mlir/lib/Dialect/CMakeLists.txt b/mlir/lib/Dialect/CMakeLists.txt
index b1ba5a3bc8817d..6fa8a610e196c4 100644
--- a/mlir/lib/Dialect/CMakeLists.txt
+++ b/mlir/lib/Dialect/CMakeLists.txt
@@ -28,6 +28,7 @@ add_subdirectory(OpenACCMPCommon)
 add_subdirectory(OpenMP)
 add_subdirectory(PDL)
 add_subdirectory(PDLInterp)
+add_subdirectory(Ptr)
 add_subdirectory(Quant)
 add_subdirectory(SCF)
 add_subdirectory(Shape)
diff --git a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
index 392065b859ee54..282baf8075a07a 100644
--- a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
@@ -35,6 +35,7 @@ add_mlir_dialect_library(MLIRLLVMDialect
   MLIRFunctionInterfaces
   MLIRInferTypeOpInterface
   MLIRIR
+  MLIRPtrDialect
   MLIRMemorySlotInterfaces
   MLIRSideEffectInterfaces
   MLIRSupport
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index a44e83313c9c1f..cd55e1b7fc19cc 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -51,6 +51,159 @@ void LLVMDialect::registerAttributes() {
       >();
 }
 
+//===----------------------------------------------------------------------===//
+// AddressSpaceAttr
+//===----------------------------------------------------------------------===//
+
+static bool isLoadableType(Type type) {
+  return /*LLVM_PrimitiveType*/ (
+             LLVM::isCompatibleOuterType(type) &&
+             !isa<LLVM::LLVMVoidType, LLVM::LLVMFunctionType>(type)) &&
+         /*LLVM_OpaqueStruct*/
+         !(isa<LLVM::LLVMStructType>(type) &&
+           cast<LLVM::LLVMStructType>(type).isOpaque()) &&
+         /*LLVM_AnyTargetExt*/
+         !(isa<LLVM::LLVMTargetExtType>(type) &&
+           !cast<LLVM::LLVMTargetExtType>(type).supportsMemOps());
+}
+
+/// Returns true if the given type is supported by atomic operations. All
+/// integer and float types with limited bit width are supported. Additionally,
+/// depending on the operation pointers may be supported as well.
+static bool isTypeCompatibleWithAtomicOp(Type type) {
+  if (llvm::isa<LLVMPointerType>(type))
+    return true;
+
+  std::optional<unsigned> bitWidth;
+  if (auto floatType = llvm::dyn_cast<FloatType>(type)) {
+    if (!isCompatibleFloatingPointType(type))
+      return false;
+    bitWidth = floatType.getWidth();
+  }
+  if (auto integerType = llvm::dyn_cast<IntegerType>(type))
+    bitWidth = integerType.getWidth();
+  // The type is neither an integer, float, or pointer type.
+  if (!bitWidth)
+    return false;
+  return *bitWidth == 8 || *bitWidth == 16 || *bitWidth == 32 ||
+         *bitWidth == 64;
+}
+
+Dialect *AddressSpaceAttr::getMemorySpaceDialect() const {
+  return &getDialect();
+}
+
+Attribute AddressSpaceAttr::getDefaultMemorySpace() const {
+  return AddressSpaceAttr::get(getContext(), 0);
+}
+
+unsigned AddressSpaceAttr::getAddressSpace() const { return getAs(); }
+
+LogicalResult AddressSpaceAttr::isValidLoad(Type type,
+                                            mlir::ptr::AtomicOrdering ordering,
+                                            IntegerAttr alignment,
+                                            Operation *diagnosticOp) const {
+  if (!isLoadableType(type))
+    return diagnosticOp ? diagnosticOp->emitError(
+                              "type must be LLVM type with size, but got ")
+                              << type
+                        : failure();
+  if (ordering != ptr::AtomicOrdering::not_atomic &&
+      !isTypeCompatibleWithAtomicOp(type))
+    return diagnosticOp ? diagnosticOp->emitError("unsupported type ")
+                              << type << " for atomic access"
+                        : failure();
+  return success();
+}
+
+LogicalResult AddressSpaceAttr::isValidStore(Type type,
+                                             mlir::ptr::AtomicOrdering ordering,
+                                             IntegerAttr alignment,
+                                             Operation *diagnosticOp) const {
+  if (!isLoadableType(type))
+    return diagnosticOp ? diagnosticOp->emitError(
+                              "type must be LLVM type with size, but got ")
+                              << type
+                        : failure();
+  if (ordering != ptr::AtomicOrdering::not_atomic &&
+      !isTypeCompatibleWithAtomicOp(type))
+    return diagnosticOp ? diagnosticOp->emitError("unsupported type ")
+                              << type << " for atomic access"
+                        : failure();
+  return success();
+}
+
+LogicalResult AddressSpaceAttr::isValidAtomicOp(
+    mlir::ptr::AtomicBinOp binOp, Type type, mlir::ptr::AtomicOrdering ordering,
+    IntegerAttr alignment, Operation *diagnosticOp) const {
+  if (binOp == ptr::AtomicBinOp::fadd || binOp == ptr::AtomicBinOp::fsub ||
+      binOp == ptr::AtomicBinOp::fmin || binOp == ptr::AtomicBinOp::fmax) {
+    if (!mlir::LLVM::isCompatibleFloatingPointType(type))
+      return diagnosticOp ? diagnosticOp->emitError(
+                                "expected LLVM IR floating point type")
+                          : failure();
+  } else if (binOp == ptr::AtomicBinOp::xchg) {
+    if (!isTypeCompatibleWithAtomicOp(type))
+      return diagnosticOp ? diagnosticOp->emitError(
+                                "unexpected LLVM IR type for 'xchg' bin_op")
+                          : failure();
+  } else {
+    auto intType = llvm::dyn_cast<IntegerType>(type);
+    unsigned intBitWidth = intType ? intType.getWidth() : 0;
+    if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
+        intBitWidth != 64)
+      return diagnosticOp
+                 ? diagnosticOp->emitError("expected LLVM IR integer type")
+                 : failure();
+  }
+  return success();
+}
+
+LogicalResult AddressSpaceAttr::isValidAtomicXchg(
+    Type type, mlir::ptr::AtomicOrdering successOrdering,
+    mlir::ptr::AtomicOrdering failureOrdering, IntegerAttr alignment,
+    Operation *diagnosticOp) const {
+  if (!isLoadableType(type))
+    return diagnosticOp ? diagnosticOp->emitError(
+                              "type must be LLVM type with size, but got ")
+                              << type
+                        : failure();
+  if (!isTypeCompatibleWithAtomicOp(type))
+    return diagnosticOp ? diagnosticOp->emitError("unexpected LLVM IR type")
+                        : failure();
+  return success();
+}
+
+template <typename Ty>
+static bool isScalarOrVectorOf(Type ty) {
+  return isa<Ty>(ty) || (LLVM::isCompatibleVectorType(ty) &&
+                         isa<Ty>(LLVM::getVectorElementType(ty)));
+}
+
+LogicalResult
+AddressSpaceAttr::isValidAddrSpaceCast(Type tgt, Type src,
+                                       Operation *diagnosticOp) const {
+  if (!isScalarOrVectorOf<LLVMPointerType>(tgt))
+    return diagnosticOp ? diagnosticOp->emitError("invalid ptr-like operand")
+                        : failure();
+  if (!isScalarOrVectorOf<LLVMPointerType>(src))
+    return diagnosticOp ? diagnosticOp->emitError("invalid ptr-like operand")
+                        : failure();
+  return success();
+}
+
+LogicalResult
+AddressSpaceAttr::isValidPtrIntCast(Type intLikeTy, Type ptrLikeTy,
+                                    Operation *diagnosticOp) const {
+  if (!isScalarOrVectorOf<IntegerType>(intLikeTy))
+    return diagnosticOp ? diagnosticOp->emitError("invalid int-like type")
+                        : failure();
+  if (!isScalarOrVectorOf<LLVMPointerType>(ptrLikeTy))
+    return diagnosticOp ? diagnosticOp->emitError("invalid ptr-like type")
+                        : failure();
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // DINodeAttr
 //===----------------------------------------------------------------------===//
@@ -91,14 +244,6 @@ bool DITypeAttr::classof(Attribute attr) {
                    DIDerivedTypeAttr, DISubroutineTypeAttr>(attr);
 }
 
-//===----------------------------------------------------------------------===//
-// TBAANodeAttr
-//===----------------------------------------------------------------------===//
-
-bool TBAANodeAttr::classof(Attribute attr) {
-  return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
-}
-
 //===----------------------------------------------------------------------===//
 // MemoryEffectsAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 3ba6ac6ccc8142..b8d3a4a3ddd546 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -17,6 +17,7 @@
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/Ptr/IR/PtrDialect.h"
 #include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/BuiltinTypes.h"
@@ -45,6 +46,12 @@ using namespace mlir::LLVM;
 using mlir::LLVM::cconv::getMaxEnumValForCConv;
 using mlir::LLVM::linkage::getMaxEnumValForLinkage;
 
+static ParseResult parseAtomicOrdering(OpAsmParser &parser,
+                                       ptr::AtomicOrderingAttr &attr);
+
+static void printAtomicOrdering(OpAsmPrinter &p, Operation *op,
+                                ptr::AtomicOrderingAttr attr);
+
 #include "mlir/Dialect/LLVMIR/LLVMOpsDialect.cpp.inc"
 
 static constexpr const char kElemTypeAttrName[] = "elem_type";
@@ -750,127 +757,6 @@ Type GEPOp::getResultPtrElementType() {
   return selectedType;
 }
 
-//===----------------------------------------------------------------------===//
-// LoadOp
-//===----------------------------------------------------------------------===//
-
-void LoadOp::getEffects(
-    SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
-        &effects) {
-  effects.emplace_back(MemoryEffects::Read::get(), getAddr());
-  // Volatile operations can have target-specific read-write effects on
-  // memory besides the one referred to by the pointer operand.
-  // Similarly, atomic operations that are monotonic or stricter cause
-  // synchronization that from a language point-of-view, are arbitrary
-  // read-writes into memory.
-  if (getVolatile_() || (getOrdering() != AtomicOrdering::not_atomic &&
-                         getOrdering() != AtomicOrdering::unordered)) {
-    effects.emplace_back(MemoryEffects::Write::get());
-    effects.emplace_back(MemoryEffects::Read::get());
-  }
-}
-
-/// Returns true if the given type is supported by atomic operations. All
-/// integer and float types with limited bit width are supported. Additionally,
-/// depending on the operation pointers may be supported as well.
-static bool isTypeCompatibleWithAtomicOp(Type type, bool isPointerTypeAllowed) {
-  if (llvm::isa<LLVMPointerType>(type))
-    return isPointerTypeAllowed;
-
-  std::optional<unsigned> bitWidth;
-  if (auto floatType = llvm::dyn_cast<FloatType>(type)) {
-    if (!isCompatibleFloatingPointType(type))
-      return false;
-    bitWidth = floatType.getWidth();
-  }
-  if (auto integerType = llvm::dyn_cast<IntegerType>(type))
-    bitWidth = integerType.getWidth();
-  // The type is neither an integer, float, or pointer type.
-  if (!bitWidth)
-    return false;
-  return *bitWidth == 8 || *bitWidth == 16 || *bitWidth == 32 ||
-         *bitWidth == 64;
-}
-
-/// Verifies the attributes and the type of atomic memory access operations.
-template <typename OpTy>
-LogicalResult verifyAtomicMemOp(OpTy memOp, Type valueType,
-                                ArrayRef<AtomicOrdering> unsupportedOrderings) {
-  if (memOp.getOrdering() != AtomicOrdering::not_atomic) {
-    if (!isTypeCompatibleWithAtomicOp(valueType,
-                                      /*isPointerTypeAllowed=*/true))
-      return memOp.emitOpError("unsupported type ")
-             << valueType << " for atomic access";
-    if (llvm::is_contained(unsupportedOrderings, memOp.getOrdering()))
-      return memOp.emitOpError("unsupported ordering '")
-             << stringifyAtomicOrdering(memOp.getOrdering()) << "'";
-    if (!memOp.getAlignment())
-      return memOp.emitOpError("expected alignment for atomic access");
-    return success();
-  }
-  if (memOp.getSyncscope())
-    return memOp.emitOpError(
-        "expected syncscope to be null for non-atomic access");
-  return success();
-}
-
-LogicalResult LoadOp::verify() {
-  Type valueType = getResult().getType();
-  return verifyAtomicMemOp(*this, valueType,
-                           {AtomicOrdering::release, AtomicOrdering::acq_rel});
-}
-
-void LoadOp::build(OpBuilder &builder, OperationState &state, Type type,
-                   Value addr, unsigned alignment, bool isVolatile,
-                   bool isNonTemporal, bool isInvariant,
-                   AtomicOrdering ordering, StringRef syncscope) {
-  build(builder, state, type, addr,
-        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
-        isNonTemporal, isInvariant, ordering,
-        syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
-        /*access_groups=*/nullptr,
-        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
-        /*tbaa=*/nullptr);
-}
-
-//===----------------------------------------------------------------------===//
-// StoreOp
-//===----------------------------------------------------------------------===//
-
-void StoreOp::getEffects(
-    SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
-        &effects) {
-  effects.emplace_back(MemoryEffects::Write::get(), getAddr());
-  // Volatile operations can have target-specific read-write effects on
-  // memory besides the one referred to by the pointer operand.
-  // Similarly, atomic operations that are monotonic or stricter cause
-  // synchronization that from a language point-of-view, are arbitrary
-  // read-writes into memory.
-  if (getVolatile_() || (getOrdering() != AtomicOrdering::not_atomic &&
-                         getOrdering() != AtomicOrdering::unordered)) {
-    effects.emplace_back(MemoryEffects::Write::get());
-    effects.emplace_back(MemoryEffects::Read::get());
-  }
-}
-
-LogicalResult StoreOp::verify() {
-  Type valueType = getValue().getType();
-  return verifyAtomicMemOp(*this, valueType,
-                           {AtomicOrdering::acquire, AtomicOrdering::acq_rel});
-}
-
-void StoreOp::build(OpBuilder &builder, OperationState &state, Value value,
-                    Value addr, unsigned alignment, bool isVolatile,
-                    bool isNonTemporal, AtomicOrdering ordering,
-                    StringRef syncscope) {
-  build(builder, state, value, addr,
-        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
-        isNonTemporal, ordering,
-        syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
-        /*access_groups=*/nullptr,
-        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
-}
-
 //===----------------------------------------------------------------------===//
 // CallOp
 //===----------------------------------------------------------------------===//
@@ -2600,93 +2486,39 @@ ConstantOp LLVM::ConstantOp::materialize(OpBuilder &builder, Attribute value,
 OpFoldResult LLVM::ConstantOp::fold(FoldAdaptor) { return getValue(); }
 
 //===----------------------------------------------------------------------===//
-// AtomicRMWOp
+// FenceOp
 //===----------------------------------------------------------------------===//
 
-void AtomicRMWOp::build(OpBuilder &builder, OperationState &state,
-                        AtomicBinOp binOp, Value ptr, Value val,
-                        AtomicOrdering ordering, StringRef syncscope,
-                        unsigned alignment, bool isVolatile) {
-  build(builder, state, val.getType(), binOp, ptr, val, ordering,
-        !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
-        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
-        /*access_groups=*/nullptr,
-        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
-}
-
-LogicalResult AtomicRMWOp::verify() {
-  auto valType = getVal().getType();
-  if (getBinOp() == AtomicBinOp::fadd || getBinOp() == AtomicBinOp::fsub ||
-      getBinOp() == AtomicBinOp::fmin || getBinOp() == AtomicBinOp::fmax) {
-    if (!mlir::LLVM::isCompatibleFloatingPointType(valType))
-      return emitOpError("expected LLVM IR floating point type");
-  } else if (getBinOp() == AtomicBinOp::xchg) {
-    if (!isTypeCompatibleWithAtomicOp(valType, /*isPointerTypeAllowed=*/true))
-      return emitOpError("unexpected LLVM IR type for 'xchg' bin_op");
-  } else {
-    auto intType = llvm::dyn_cast<IntegerType>(valType);
-    unsigned intBitWidth = intType ? intType.getWidth() : 0;
-    if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 &&
-        intBitWidth != 64)
-      return emitOpError("expected LLVM IR integer type");
-  }
-
-  if (static_cast<unsigned>(getOrdering()) <
-      static_cast<unsigned>(AtomicOrdering::monotonic))
-    return emitOpError() << "expected at least '"
-                         << stringifyAtomicOrdering(AtomicOrdering::monotonic)
-                         << "' ordering";
-
+static ParseResult parseAtomicOrdering(OpAsmParser &parser,
+                                       ptr::AtomicOrderingAttr &attr) {
+  StringRef orderingStr;
+  auto loc = parser.getCurrentLocation();
+  if (failed(parser.parseOptionalKeyword(
+          &orderingStr, {"not_atomic", "unordered", "monotonic", "acquire",
+                         "release", "acq_rel", "seq_cst"}))) {
+    return parser.emitError(
+        loc, "expected string or keyword containing one of the following "
+             "enum values for attribute 'ordering' [not_atomic, unordered, "
+             "monotonic, acquire, release, acq_rel, seq_cst]");
+  }
+  auto ordering = ptr::symbolizeAtomicOrdering(orderingStr);
+  if (!ordering)
+    return parser.emitError(loc, "invalid ")
+           << "ordering attribute specification: \"" << orderingStr << '"';
+  attr =
+      ptr::AtomicOrderingAttr::get(parser.getBuilder().getContext(), *ordering);
   return success();
 }
 
-//===----------------------------------------------------------------------===//
-// AtomicCmpXchgOp
-//===----------------------------------------------------------------------===//
-
-/// Returns an LLVM struct type that contains a value type and a boolean type.
-static LLVMStructType getValAndBoolStructType(Type valType) {
-  auto boolType = IntegerType::get(valType.getContext(), 1);
-  return LLVMStructType::getLiteral(valType.getContext(), {valType, boolType});
-}
-
-void AtomicCmpXchgOp::build(OpBuilder &builder, OperationState &state,
-                            Value ptr, Value cmp, Value val,
-                            AtomicOrdering successOrdering,
-                            AtomicOrdering failureOrdering, StringRef syncscope,
-                            unsigned alignment, bool isWeak, bool isVolatile) {
-  build(builder, state, getValAndBoolStructType(val.getType()), ptr, cmp, val,
-        successOrdering, failureOrdering,
-        !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
-        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isWeak,
-        isVolatile, /*access_groups=*/nullptr,
-        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
+static void printAtomicOrdering(OpAsmPrinter &p, Operation *op,
+                                ptr::AtomicOrderingAttr attr) {
+  p << attr.getValue();
 }
 
-LogicalResult AtomicCmpXchgOp::verify() {
-  auto ptrType = llvm::cast<LLVM::LLVMPointerType>(getPtr().getType());
-  if (!ptrType)
-    return emitOpError("expected LLVM IR pointer type for operand #0");
-  auto valType = getVal().getType();
-  if (!isTypeCompatibleWithAtomicOp(valType,
-                                    /*isPointerTypeAllowed=*/true))
-    return emitOpError("unexpected LLVM IR type");
-  if (getSuccessOrdering() < AtomicOrdering::monotonic ||
-      getFailureOrdering() < AtomicOrdering::monotonic)
-    return emitOpError("ordering must be at least 'monotonic'");
-  if (getFailureOrdering() == AtomicOrdering::release ||
-      getFailureOrdering() == AtomicOrdering::acq_rel)
-    return emitOpError("failure ordering cannot be 'release' or 'acq_rel'");
-  return success();
-}
-
-//===----------------------------------------------------------------------===//
-// FenceOp
-//===----------------------------------------------------------------------===//
-
 void FenceOp::build(OpBuilder &builder, OperationState &state,
                     AtomicOrdering ordering, StringRef syncscope) {
-  build(builder, state, ordering,
+  build(builder, state,
+        ptr::AtomicOrderingAttr::get(builder.getContext(), ordering),
         syncscope.empty() ? nullptr : builder.getStringAttr(syncscope));
 }
 
@@ -2803,26 +2635,11 @@ LogicalResult LLVM::BitcastOp::verify() {
   // 'llvm.addrspacecast' must be used for this purpose instead.
   if (resultType.getAddressSpace() != sourceType.getAddressSpace())
     return emitOpError("cannot cast pointers of different address spaces, "
-                       "use 'llvm.addrspacecast' instead");
+                       "use 'ptr.addrspacecast' instead");
 
   return success();
 }
 
-//===----------------------------------------------------------------------===//
-// Folder for LLVM::AddrSpaceCastOp
-//===----------------------------------------------------------------------===//
-
-OpFoldResult LLVM::AddrSpaceCastOp::fold(FoldAdaptor adaptor) {
-  // addrcast(x : T0, T0) -> x
-  if (getArg().getType() == getType())
-    return getArg();
-  // addrcast(addrcast(x : T0, T1), T0) -> x
-  if (auto prev = getArg().getDefiningOp<AddrSpaceCastOp>())
-    if (prev.getArg().getType() == getType())
-      return prev.getArg();
-  return {};
-}
-
 //===----------------------------------------------------------------------===//
 // Folder for LLVM::GEPOp
 //===----------------------------------------------------------------------===//
@@ -2945,6 +2762,24 @@ struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface {
         })
         .Default([](Attribute) { return AliasResult::NoAlias; });
   }
+
+  AliasResult getAlias(Type type, raw_ostream &os) const override {
+    return TypeSwitch<Type, AliasResult>(type)
+        .Case<LLVMPointerType>(
+            [&](LLVMPointerType type) { return AliasResult::DialectAlias; })
+        .Default([](Type) { return AliasResult::NoAlias; });
+  }
+
+  LogicalResult printDialectAlias(DialectAsmPrinter &printer,
+                                  Type type) const override {
+    return TypeSwitch<Type, LogicalResult>(type)
+        .Case<LLVMPointerType>([&](LLVMPointerType type) {
+          printer << "ptr";
+          type.print(printer);
+          return success();
+        })
+        .Default([](Type) { return failure(); });
+  }
 };
 } // namespace
 
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp
index 4a6154ea6d3004..4366897f84cb68 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp
@@ -13,6 +13,7 @@
 
 #include "LLVMInlining.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/Ptr/IR/PtrInterfaces.h"
 #include "mlir/IR/Matchers.h"
 #include "mlir/Interfaces/DataLayoutInterfaces.h"
 #include "mlir/Transforms/InliningUtils.h"
@@ -188,7 +189,7 @@ deepCloneAliasScopes(iterator_range<Region::iterator> inlinedBlocks) {
 
   for (Block &block : inlinedBlocks) {
     for (Operation &op : block) {
-      if (auto aliasInterface = dyn_cast<LLVM::AliasAnalysisOpInterface>(op)) {
+      if (auto aliasInterface = dyn_cast<ptr::AliasAnalysisOpInterface>(op)) {
         aliasInterface.setAliasScopes(
             convertScopeList(aliasInterface.getAliasScopesOrNull()));
         aliasInterface.setNoAliasScopes(
@@ -358,7 +359,7 @@ static void createNewAliasScopesFromNoAliasParameter(
   // it is definitely based on and definitely not based on.
   for (Block &inlinedBlock : inlinedBlocks) {
     for (auto aliasInterface :
-         inlinedBlock.getOps<LLVM::AliasAnalysisOpInterface>()) {
+         inlinedBlock.getOps<ptr::AliasAnalysisOpInterface>()) {
 
       // Collect the pointer arguments affected by the alias scopes.
       SmallVector<Value> pointerArgs = aliasInterface.getAccessedOperands();
@@ -458,7 +459,7 @@ static void createNewAliasScopesFromNoAliasParameter(
 static void
 appendCallOpAliasScopes(Operation *call,
                         iterator_range<Region::iterator> inlinedBlocks) {
-  auto callAliasInterface = dyn_cast<LLVM::AliasAnalysisOpInterface>(call);
+  auto callAliasInterface = dyn_cast<ptr::AliasAnalysisOpInterface>(call);
   if (!callAliasInterface)
     return;
 
@@ -472,7 +473,7 @@ appendCallOpAliasScopes(Operation *call,
   // Simply append the call op's alias and noalias scopes to any operation
   // implementing AliasAnalysisOpInterface.
   for (Block &block : inlinedBlocks) {
-    for (auto aliasInterface : block.getOps<LLVM::AliasAnalysisOpInterface>()) {
+    for (auto aliasInterface : block.getOps<ptr::AliasAnalysisOpInterface>()) {
       if (aliasScopes)
         aliasInterface.setAliasScopes(concatArrayAttr(
             aliasInterface.getAliasScopesOrNull(), aliasScopes));
@@ -496,7 +497,7 @@ static void handleAliasScopes(Operation *call,
 /// operation.
 static void handleAccessGroups(Operation *call,
                                iterator_range<Region::iterator> inlinedBlocks) {
-  auto callAccessGroupInterface = dyn_cast<LLVM::AccessGroupOpInterface>(call);
+  auto callAccessGroupInterface = dyn_cast<ptr::AccessGroupOpInterface>(call);
   if (!callAccessGroupInterface)
     return;
 
@@ -508,7 +509,7 @@ static void handleAccessGroups(Operation *call,
   // AccessGroupOpInterface.
   for (Block &block : inlinedBlocks)
     for (auto accessGroupOpInterface :
-         block.getOps<LLVM::AccessGroupOpInterface>())
+         block.getOps<ptr::AccessGroupOpInterface>())
       accessGroupOpInterface.setAccessGroups(concatArrayAttr(
           accessGroupOpInterface.getAccessGroupsOrNull(), accessGroups));
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp
index cff16afc73af3f..36f47ad36bec0a 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMInterfaces.cpp
@@ -26,58 +26,6 @@ static LogicalResult isArrayOf(Operation *op, ArrayAttr array) {
   return success();
 }
 
-//===----------------------------------------------------------------------===//
-// AccessGroupOpInterface
-//===----------------------------------------------------------------------===//
-
-LogicalResult mlir::LLVM::detail::verifyAccessGroupOpInterface(Operation *op) {
-  auto iface = cast<AccessGroupOpInterface>(op);
-  ArrayAttr accessGroups = iface.getAccessGroupsOrNull();
-  if (!accessGroups)
-    return success();
-
-  return isArrayOf<AccessGroupAttr>(op, accessGroups);
-}
-
-//===----------------------------------------------------------------------===//
-// AliasAnalysisOpInterface
-//===----------------------------------------------------------------------===//
-
-LogicalResult
-mlir::LLVM::detail::verifyAliasAnalysisOpInterface(Operation *op) {
-  auto iface = cast<AliasAnalysisOpInterface>(op);
-
-  if (auto aliasScopes = iface.getAliasScopesOrNull())
-    if (failed(isArrayOf<AliasScopeAttr>(op, aliasScopes)))
-      return failure();
-
-  if (auto noAliasScopes = iface.getNoAliasScopesOrNull())
-    if (failed(isArrayOf<AliasScopeAttr>(op, noAliasScopes)))
-      return failure();
-
-  ArrayAttr tags = iface.getTBAATagsOrNull();
-  if (!tags)
-    return success();
-
-  return isArrayOf<TBAATagAttr>(op, tags);
-}
-
-SmallVector<Value> mlir::LLVM::AtomicCmpXchgOp::getAccessedOperands() {
-  return {getPtr()};
-}
-
-SmallVector<Value> mlir::LLVM::AtomicRMWOp::getAccessedOperands() {
-  return {getPtr()};
-}
-
-SmallVector<Value> mlir::LLVM::LoadOp::getAccessedOperands() {
-  return {getAddr()};
-}
-
-SmallVector<Value> mlir::LLVM::StoreOp::getAccessedOperands() {
-  return {getAddr()};
-}
-
 SmallVector<Value> mlir::LLVM::MemcpyOp::getAccessedOperands() {
   return {getDst(), getSrc()};
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp
index f171bf7cc4bec3..a548c78b6f4372 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp
@@ -100,189 +100,6 @@ void LLVM::AllocaOp::handleDestructuringComplete(
   rewriter.eraseOp(*this);
 }
 
-//===----------------------------------------------------------------------===//
-// Interfaces for LoadOp/StoreOp
-//===----------------------------------------------------------------------===//
-
-bool LLVM::LoadOp::loadsFrom(const MemorySlot &slot) {
-  return getAddr() == slot.ptr;
-}
-
-bool LLVM::LoadOp::storesTo(const MemorySlot &slot) { return false; }
-
-Value LLVM::LoadOp::getStored(const MemorySlot &slot, RewriterBase &rewriter) {
-  llvm_unreachable("getStored should not be called on LoadOp");
-}
-
-bool LLVM::StoreOp::loadsFrom(const MemorySlot &slot) { return false; }
-
-bool LLVM::StoreOp::storesTo(const MemorySlot &slot) {
-  return getAddr() == slot.ptr;
-}
-
-Value LLVM::StoreOp::getStored(const MemorySlot &slot, RewriterBase &rewriter) {
-  return getValue();
-}
-
-bool LLVM::LoadOp::canUsesBeRemoved(
-    const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
-    SmallVectorImpl<OpOperand *> &newBlockingUses,
-    const DataLayout &dataLayout) {
-  if (blockingUses.size() != 1)
-    return false;
-  Value blockingUse = (*blockingUses.begin())->get();
-  // If the blocking use is the slot ptr itself, there will be enough
-  // context to reconstruct the result of the load at removal time, so it can
-  // be removed (provided it loads the exact stored value and is not
-  // volatile).
-  return blockingUse == slot.ptr && getAddr() == slot.ptr &&
-         getResult().getType() == slot.elemType && !getVolatile_();
-}
-
-DeletionKind LLVM::LoadOp::removeBlockingUses(
-    const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
-    RewriterBase &rewriter, Value reachingDefinition) {
-  // `canUsesBeRemoved` checked this blocking use must be the loaded slot
-  // pointer.
-  rewriter.replaceAllUsesWith(getResult(), reachingDefinition);
-  return DeletionKind::Delete;
-}
-
-bool LLVM::StoreOp::canUsesBeRemoved(
-    const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
-    SmallVectorImpl<OpOperand *> &newBlockingUses,
-    const DataLayout &dataLayout) {
-  if (blockingUses.size() != 1)
-    return false;
-  Value blockingUse = (*blockingUses.begin())->get();
-  // If the blocking use is the slot ptr itself, dropping the store is
-  // fine, provided we are currently promoting its target value. Don't allow a
-  // store OF the slot pointer, only INTO the slot pointer.
-  return blockingUse == slot.ptr && getAddr() == slot.ptr &&
-         getValue() != slot.ptr && getValue().getType() == slot.elemType &&
-         !getVolatile_();
-}
-
-DeletionKind LLVM::StoreOp::removeBlockingUses(
-    const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
-    RewriterBase &rewriter, Value reachingDefinition) {
-  // `canUsesBeRemoved` checked this blocking use must be the stored slot
-  // pointer.
-  for (Operation *user : slot.ptr.getUsers())
-    if (auto declareOp = dyn_cast<LLVM::DbgDeclareOp>(user))
-      rewriter.create<LLVM::DbgValueOp>(declareOp->getLoc(), getValue(),
-                                        declareOp.getVarInfo(),
-                                        declareOp.getLocationExpr());
-  return DeletionKind::Delete;
-}
-
-/// Checks if `slot` can be accessed through the provided access type.
-static bool isValidAccessType(const MemorySlot &slot, Type accessType,
-                              const DataLayout &dataLayout) {
-  return dataLayout.getTypeSize(accessType) <=
-         dataLayout.getTypeSize(slot.elemType);
-}
-
-LogicalResult LLVM::LoadOp::ensureOnlySafeAccesses(
-    const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
-    const DataLayout &dataLayout) {
-  return success(getAddr() != slot.ptr ||
-                 isValidAccessType(slot, getType(), dataLayout));
-}
-
-LogicalResult LLVM::StoreOp::ensureOnlySafeAccesses(
-    const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
-    const DataLayout &dataLayout) {
-  return success(getAddr() != slot.ptr ||
-                 isValidAccessType(slot, getValue().getType(), dataLayout));
-}
-
-/// Returns the subslot's type at the requested index.
-static Type getTypeAtIndex(const DestructurableMemorySlot &slot,
-                           Attribute index) {
-  auto subelementIndexMap =
-      slot.elemType.cast<DestructurableTypeInterface>().getSubelementIndexMap();
-  if (!subelementIndexMap)
-    return {};
-  assert(!subelementIndexMap->empty());
-
-  // Note: Returns a null-type when no entry was found.
-  return subelementIndexMap->lookup(index);
-}
-
-bool LLVM::LoadOp::canRewire(const DestructurableMemorySlot &slot,
-                             SmallPtrSetImpl<Attribute> &usedIndices,
-                             SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
-                             const DataLayout &dataLayout) {
-  if (getVolatile_())
-    return false;
-
-  // A load always accesses the first element of the destructured slot.
-  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
-  Type subslotType = getTypeAtIndex(slot, index);
-  if (!subslotType)
-    return false;
-
-  // The access can only be replaced when the subslot is read within its bounds.
-  if (dataLayout.getTypeSize(getType()) > dataLayout.getTypeSize(subslotType))
-    return false;
-
-  usedIndices.insert(index);
-  return true;
-}
-
-DeletionKind LLVM::LoadOp::rewire(const DestructurableMemorySlot &slot,
-                                  DenseMap<Attribute, MemorySlot> &subslots,
-                                  RewriterBase &rewriter,
-                                  const DataLayout &dataLayout) {
-  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
-  auto it = subslots.find(index);
-  assert(it != subslots.end());
-
-  rewriter.modifyOpInPlace(
-      *this, [&]() { getAddrMutable().set(it->getSecond().ptr); });
-  return DeletionKind::Keep;
-}
-
-bool LLVM::StoreOp::canRewire(const DestructurableMemorySlot &slot,
-                              SmallPtrSetImpl<Attribute> &usedIndices,
-                              SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
-                              const DataLayout &dataLayout) {
-  if (getVolatile_())
-    return false;
-
-  // Storing the pointer to memory cannot be dealt with.
-  if (getValue() == slot.ptr)
-    return false;
-
-  // A store always accesses the first element of the destructured slot.
-  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
-  Type subslotType = getTypeAtIndex(slot, index);
-  if (!subslotType)
-    return false;
-
-  // The access can only be replaced when the subslot is read within its bounds.
-  if (dataLayout.getTypeSize(getValue().getType()) >
-      dataLayout.getTypeSize(subslotType))
-    return false;
-
-  usedIndices.insert(index);
-  return true;
-}
-
-DeletionKind LLVM::StoreOp::rewire(const DestructurableMemorySlot &slot,
-                                   DenseMap<Attribute, MemorySlot> &subslots,
-                                   RewriterBase &rewriter,
-                                   const DataLayout &dataLayout) {
-  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
-  auto it = subslots.find(index);
-  assert(it != subslots.end());
-
-  rewriter.modifyOpInPlace(
-      *this, [&]() { getAddrMutable().set(it->getSecond().ptr); });
-  return DeletionKind::Keep;
-}
-
 //===----------------------------------------------------------------------===//
 // Interfaces for discardable OPs
 //===----------------------------------------------------------------------===//
@@ -308,18 +125,6 @@ DeletionKind LLVM::BitcastOp::removeBlockingUses(
   return DeletionKind::Delete;
 }
 
-bool LLVM::AddrSpaceCastOp::canUsesBeRemoved(
-    const SmallPtrSetImpl<OpOperand *> &blockingUses,
-    SmallVectorImpl<OpOperand *> &newBlockingUses,
-    const DataLayout &dataLayout) {
-  return forwardToUsers(*this, newBlockingUses);
-}
-
-DeletionKind LLVM::AddrSpaceCastOp::removeBlockingUses(
-    const SmallPtrSetImpl<OpOperand *> &blockingUses, RewriterBase &rewriter) {
-  return DeletionKind::Delete;
-}
-
 bool LLVM::LifetimeStartOp::canUsesBeRemoved(
     const SmallPtrSetImpl<OpOperand *> &blockingUses,
     SmallVectorImpl<OpOperand *> &newBlockingUses,
@@ -380,6 +185,18 @@ DeletionKind LLVM::DbgDeclareOp::removeBlockingUses(
   return DeletionKind::Delete;
 }
 
+bool LLVM::DbgDeclareOp::requiresVisitingMutatedDefs() { return true; }
+
+void LLVM::DbgDeclareOp::visitMutatedDefs(
+    ArrayRef<std::pair<Operation *, Value>> definitions,
+    RewriterBase &rewriter) {
+  for (auto [op, value] : definitions) {
+    rewriter.setInsertionPointAfter(op);
+    rewriter.create<LLVM::DbgValueOp>(getLoc(), value, getVarInfo(),
+                                      getLocationExpr());
+  }
+}
+
 bool LLVM::DbgValueOp::canUsesBeRemoved(
     const SmallPtrSetImpl<OpOperand *> &blockingUses,
     SmallVectorImpl<OpOperand *> &newBlockingUses,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
index 630187f220a4ba..90ee6bfed8f774 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
@@ -254,162 +254,42 @@ LLVMFunctionType::verify(function_ref<InFlightDiagnostic()> emitError,
 }
 
 //===----------------------------------------------------------------------===//
-// DataLayoutTypeInterface
-
-constexpr const static uint64_t kDefaultPointerSizeBits = 64;
-constexpr const static uint64_t kDefaultPointerAlignment = 8;
-
-std::optional<uint64_t> mlir::LLVM::extractPointerSpecValue(Attribute attr,
-                                                            PtrDLEntryPos pos) {
-  auto spec = cast<DenseIntElementsAttr>(attr);
-  auto idx = static_cast<int64_t>(pos);
-  if (idx >= spec.size())
-    return std::nullopt;
-  return spec.getValues<uint64_t>()[idx];
-}
+// LLVMPointerType
+//===----------------------------------------------------------------------===//
 
-/// Returns the part of the data layout entry that corresponds to `pos` for the
-/// given `type` by interpreting the list of entries `params`. For the pointer
-/// type in the default address space, returns the default value if the entries
-/// do not provide a custom one, for other address spaces returns std::nullopt.
-static std::optional<uint64_t>
-getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type,
-                          PtrDLEntryPos pos) {
-  // First, look for the entry for the pointer in the current address space.
-  Attribute currentEntry;
-  for (DataLayoutEntryInterface entry : params) {
-    if (!entry.isTypeEntry())
-      continue;
-    if (cast<LLVMPointerType>(entry.getKey().get<Type>()).getAddressSpace() ==
-        type.getAddressSpace()) {
-      currentEntry = entry.getValue();
-      break;
+mlir::ptr::PtrType LLVMPointerType::get(MLIRContext *context,
+                                        unsigned addressSpace) {
+  return ptr::PtrType::get(context,
+                           AddressSpaceAttr::get(context, addressSpace));
+}
+
+Type LLVMPointerType::parse(AsmParser &odsParser) {
+  FailureOr<unsigned> addressSpace;
+  // Parse literal '<'
+  if (!odsParser.parseOptionalLess()) {
+    if (failed(addressSpace = FieldParser<unsigned>::parse(odsParser))) {
+      odsParser.emitError(odsParser.getCurrentLocation(),
+                          "failed to parse LLVMPtrType parameter 'memorySpace' "
+                          "which is to be a `unsigned`");
+      return {};
     }
+    // Parse literal '>'
+    if (odsParser.parseGreater())
+      return {};
   }
-  if (currentEntry) {
-    std::optional<uint64_t> value = extractPointerSpecValue(currentEntry, pos);
-    // If the optional `PtrDLEntryPos::Index` entry is not available, use the
-    // pointer size as the index bitwidth.
-    if (!value && pos == PtrDLEntryPos::Index)
-      value = extractPointerSpecValue(currentEntry, PtrDLEntryPos::Size);
-    bool isSizeOrIndex =
-        pos == PtrDLEntryPos::Size || pos == PtrDLEntryPos::Index;
-    return *value / (isSizeOrIndex ? 1 : kBitsInByte);
-  }
-
-  // If not found, and this is the pointer to the default memory space, assume
-  // 64-bit pointers.
-  if (type.getAddressSpace() == 0) {
-    bool isSizeOrIndex =
-        pos == PtrDLEntryPos::Size || pos == PtrDLEntryPos::Index;
-    return isSizeOrIndex ? kDefaultPointerSizeBits : kDefaultPointerAlignment;
-  }
-
-  return std::nullopt;
-}
-
-llvm::TypeSize
-LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout,
-                                   DataLayoutEntryListRef params) const {
-  if (std::optional<uint64_t> size =
-          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Size))
-    return llvm::TypeSize::getFixed(*size);
-
-  // For other memory spaces, use the size of the pointer to the default memory
-  // space.
-  return dataLayout.getTypeSizeInBits(get(getContext()));
-}
-
-uint64_t LLVMPointerType::getABIAlignment(const DataLayout &dataLayout,
-                                          DataLayoutEntryListRef params) const {
-  if (std::optional<uint64_t> alignment =
-          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Abi))
-    return *alignment;
-
-  return dataLayout.getTypeABIAlignment(get(getContext()));
-}
-
-uint64_t
-LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout,
-                                       DataLayoutEntryListRef params) const {
-  if (std::optional<uint64_t> alignment =
-          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Preferred))
-    return *alignment;
-
-  return dataLayout.getTypePreferredAlignment(get(getContext()));
-}
-
-std::optional<uint64_t>
-LLVMPointerType::getIndexBitwidth(const DataLayout &dataLayout,
-                                  DataLayoutEntryListRef params) const {
-  if (std::optional<uint64_t> indexBitwidth =
-          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Index))
-    return *indexBitwidth;
-
-  return dataLayout.getTypeIndexBitwidth(get(getContext()));
+  return LLVMPointerType::get(odsParser.getContext(), addressSpace.value_or(0));
 }
 
-bool LLVMPointerType::areCompatible(DataLayoutEntryListRef oldLayout,
-                                    DataLayoutEntryListRef newLayout) const {
-  for (DataLayoutEntryInterface newEntry : newLayout) {
-    if (!newEntry.isTypeEntry())
-      continue;
-    uint64_t size = kDefaultPointerSizeBits;
-    uint64_t abi = kDefaultPointerAlignment;
-    auto newType = llvm::cast<LLVMPointerType>(newEntry.getKey().get<Type>());
-    const auto *it =
-        llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
-          if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
-            return llvm::cast<LLVMPointerType>(type).getAddressSpace() ==
-                   newType.getAddressSpace();
-          }
-          return false;
-        });
-    if (it == oldLayout.end()) {
-      llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
-        if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
-          return llvm::cast<LLVMPointerType>(type).getAddressSpace() == 0;
-        }
-        return false;
-      });
-    }
-    if (it != oldLayout.end()) {
-      size = *extractPointerSpecValue(*it, PtrDLEntryPos::Size);
-      abi = *extractPointerSpecValue(*it, PtrDLEntryPos::Abi);
-    }
-
-    Attribute newSpec = llvm::cast<DenseIntElementsAttr>(newEntry.getValue());
-    uint64_t newSize = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Size);
-    uint64_t newAbi = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Abi);
-    if (size != newSize || abi < newAbi || abi % newAbi != 0)
-      return false;
-  }
-  return true;
+void LLVMPointerType::print(AsmPrinter &odsPrinter) const {
+  if (unsigned as = getAddressSpace(); as != 0)
+    odsPrinter << "<" << as << ">";
 }
 
-LogicalResult LLVMPointerType::verifyEntries(DataLayoutEntryListRef entries,
-                                             Location loc) const {
-  for (DataLayoutEntryInterface entry : entries) {
-    if (!entry.isTypeEntry())
-      continue;
-    auto key = entry.getKey().get<Type>();
-    auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
-    if (!values || (values.size() != 3 && values.size() != 4)) {
-      return emitError(loc)
-             << "expected layout attribute for " << key
-             << " to be a dense integer elements attribute with 3 or 4 "
-                "elements";
-    }
-    if (!values.getElementType().isInteger(64))
-      return emitError(loc) << "expected i64 parameters for " << key;
-
-    if (extractPointerSpecValue(values, PtrDLEntryPos::Abi) >
-        extractPointerSpecValue(values, PtrDLEntryPos::Preferred)) {
-      return emitError(loc) << "preferred alignment is expected to be at least "
-                               "as large as ABI alignment";
-    }
-  }
-  return success();
+bool mlir::LLVM::isLLVMPointerType(Type type) {
+  if (auto ptrTy = mlir::dyn_cast<ptr::PtrType>(type))
+    return ptrTy.getMemorySpace() &&
+           mlir::isa<AddressSpaceAttr>(ptrTy.getMemorySpace());
+  return false;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index c09a3403f9a3e3..2f7fcbecd0b947 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -38,7 +38,7 @@ struct MemRefPointerLikeModel
 
 struct LLVMPointerPointerLikeModel
     : public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
-                                            LLVM::LLVMPointerType> {
+                                            ptr::PtrType> {
   Type getElementType(Type pointer) const { return Type(); }
 };
 } // namespace
@@ -65,8 +65,7 @@ void OpenACCDialect::initialize() {
   // the other dialects. This is probably better than having dialects like LLVM
   // and memref be dependent on OpenACC.
   MemRefType::attachInterface<MemRefPointerLikeModel>(*getContext());
-  LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
-      *getContext());
+  ptr::PtrType::attachInterface<LLVMPointerPointerLikeModel>(*getContext());
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index bf5875071e0dc4..52ef81b8e1a390 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -52,7 +52,7 @@ struct MemRefPointerLikeModel
 
 struct LLVMPointerPointerLikeModel
     : public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
-                                            LLVM::LLVMPointerType> {
+                                            ptr::PtrType> {
   Type getElementType(Type pointer) const { return Type(); }
 };
 
@@ -82,8 +82,7 @@ void OpenMPDialect::initialize() {
 
   addInterface<OpenMPDialectFoldInterface>();
   MemRefType::attachInterface<MemRefPointerLikeModel>(*getContext());
-  LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
-      *getContext());
+  ptr::PtrType::attachInterface<LLVMPointerPointerLikeModel>(*getContext());
 
   // Attach default offload module interface to module op to access
   // offload functionality through
diff --git a/mlir/lib/Dialect/Ptr/CMakeLists.txt b/mlir/lib/Dialect/Ptr/CMakeLists.txt
new file mode 100644
index 00000000000000..f33061b2d87cff
--- /dev/null
+++ b/mlir/lib/Dialect/Ptr/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(IR)
diff --git a/mlir/lib/Dialect/Ptr/IR/CMakeLists.txt b/mlir/lib/Dialect/Ptr/IR/CMakeLists.txt
new file mode 100644
index 00000000000000..739e9aeefbb5f0
--- /dev/null
+++ b/mlir/lib/Dialect/Ptr/IR/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_mlir_dialect_library(
+  MLIRPtrDialect
+  PtrTypes.cpp
+  PtrDialect.cpp
+  PtrMemorySlot.cpp
+  ADDITIONAL_HEADER_DIRS
+  ${PROJECT_SOURCE_DIR}/mlir/Dialect/Pointer
+  DEPENDS
+  MLIRPtrOpsIncGen
+  MLIRPtrOpsEnumsGen
+  MLIRPtrOpsAttributesIncGen
+  MLIRPtrMemorySpaceInterfacesIncGen
+  LINK_LIBS
+  PUBLIC
+  MLIRIR
+  MLIRDataLayoutInterfaces
+  MLIRMemorySlotInterfaces
+)
diff --git a/mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp b/mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp
new file mode 100644
index 00000000000000..190ff35af522ec
--- /dev/null
+++ b/mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp
@@ -0,0 +1,524 @@
+//===- PtrDialect.cpp - Pointer dialect ---------------------*- C++ -*-===//
+//
+// This file is licensed 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Pointer dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Ptr/IR/PtrOps.h"
+#include "mlir/IR/DialectImplementation.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Transforms/InliningUtils.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+using namespace mlir;
+using namespace mlir::ptr;
+
+//===----------------------------------------------------------------------===//
+// Pointer dialect
+//===----------------------------------------------------------------------===//
+
+namespace {
+/// This class defines the interface for handling inlining for ptr
+/// dialect operations.
+struct PtrInlinerInterface : public DialectInlinerInterface {
+  using DialectInlinerInterface::DialectInlinerInterface;
+
+  /// All ptr dialect ops can be inlined.
+  bool isLegalToInline(Operation *, Region *, bool, IRMapping &) const final {
+    return true;
+  }
+};
+} // namespace
+
+void PtrDialect::initialize() {
+  addOperations<
+#define GET_OP_LIST
+#include "mlir/Dialect/Ptr/IR/PtrOps.cpp.inc"
+      >();
+  addTypes<
+#define GET_TYPEDEF_LIST
+#include "mlir/Dialect/Ptr/IR/PtrOpsTypes.cpp.inc"
+      >();
+  addAttributes<
+#define GET_ATTRDEF_LIST
+#include "mlir/Dialect/Ptr/IR/PtrOpsAttrs.cpp.inc"
+      >();
+  addInterfaces<PtrInlinerInterface>();
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer API.
+//===----------------------------------------------------------------------===//
+
+// Returns the underlying ptr-type or null.
+static PtrType getUnderlyingPtrType(Type ty) {
+  Type elemTy = ty;
+  if (auto vecTy = dyn_cast<VectorType>(ty))
+    elemTy = vecTy.getElementType();
+  return dyn_cast<PtrType>(elemTy);
+}
+
+// Returns a pair containing:
+// The underlying type of a vector or the type itself if it's not a vector.
+// The number of elements in the vector or an error code if the type is not
+// supported.
+static std::pair<Type, int64_t> getVecOrScalarInfo(Type ty) {
+  if (auto vecTy = dyn_cast<VectorType>(ty)) {
+    auto elemTy = vecTy.getElementType();
+    // Vectors of rank greater than one or with scalable dimensions are not
+    // supported.
+    if (vecTy.getRank() != 1)
+      return {elemTy, -1};
+    else if (vecTy.getScalableDims()[0])
+      return {elemTy, -2};
+    return {elemTy, vecTy.getShape()[0]};
+  }
+  // `ty` is a scalar type.
+  return {ty, 0};
+}
+
+LogicalResult mlir::ptr::isValidAddrSpaceCastImpl(Type tgt, Type src,
+                                                  Operation *op) {
+  std::pair<Type, int64_t> tgtInfo = getVecOrScalarInfo(tgt);
+  std::pair<Type, int64_t> srcInfo = getVecOrScalarInfo(src);
+  if (!isa<PtrType>(tgtInfo.first) || !isa<PtrType>(srcInfo.first))
+    return op ? op->emitError("invalid ptr-like operand") : failure();
+  // Check shape validity.
+  if (tgtInfo.second == -1 || srcInfo.second == -1)
+    return op ? op->emitError("vectors of rank != 1 are not supported")
+              : failure();
+  if (tgtInfo.second == -2 || srcInfo.second == -2)
+    return op ? op->emitError(
+                    "vectors with scalable dimensions are not supported")
+              : failure();
+  if (tgtInfo.second != srcInfo.second)
+    return op ? op->emitError("incompatible operand shapes") : failure();
+  return success();
+}
+
+LogicalResult mlir::ptr::isValidPtrIntCastImpl(Type intLikeTy, Type ptrLikeTy,
+                                               Operation *op) {
+  // Check int-like type.
+  std::pair<Type, int64_t> intInfo = getVecOrScalarInfo(intLikeTy);
+  if (!intInfo.first.isSignlessIntOrIndex())
+    /// The int-like operand is invalid.
+    return op ? op->emitError("invalid int-like type") : failure();
+  // Check ptr-like type.
+  std::pair<Type, int64_t> ptrInfo = getVecOrScalarInfo(ptrLikeTy);
+  if (!isa<PtrType>(ptrInfo.first))
+    /// The pointer-like operand is invalid.
+    return op ? op->emitError("invalid ptr-like type") : failure();
+  // Check shape validity.
+  if (intInfo.second == -1 || ptrInfo.second == -1)
+    return op ? op->emitError("vectors of rank != 1 are not supported")
+              : failure();
+  if (intInfo.second == -2 || ptrInfo.second == -2)
+    return op ? op->emitError(
+                    "vectors with scalable dimensions are not supported")
+              : failure();
+  if (intInfo.second != ptrInfo.second)
+    return op ? op->emitError("incompatible operand shapes") : failure();
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer operations.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ParseResult parsePtrType(OpAsmParser &parser, Type &ty) {
+  if (succeeded(parser.parseOptionalColon()) && parser.parseType(ty))
+    return parser.emitError(parser.getNameLoc(), "expected a type");
+  if (!ty)
+    ty = parser.getBuilder().getType<PtrType>();
+  return success();
+}
+void printPtrType(OpAsmPrinter &p, Operation *op, PtrType ty) {
+  if (ty.getMemorySpace() != nullptr)
+    p << " : " << ty;
+}
+
+ParseResult parseIntType(OpAsmParser &parser, Type &ty) {
+  if (succeeded(parser.parseOptionalColon()) && parser.parseType(ty))
+    return parser.emitError(parser.getNameLoc(), "expected a type");
+  if (!ty)
+    ty = parser.getBuilder().getIndexType();
+  return success();
+}
+void printIntType(OpAsmPrinter &p, Operation *op, Type ty) {
+  if (!ty.isIndex())
+    p << " : " << ty;
+}
+
+/// Verifies the attributes and the type of atomic memory access operations.
+template <typename OpTy>
+LogicalResult verifyAtomicMemOp(OpTy memOp, Type valueType,
+                                ArrayRef<AtomicOrdering> unsupportedOrderings) {
+  if (memOp.getOrdering() != AtomicOrdering::not_atomic) {
+    if (llvm::is_contained(unsupportedOrderings, memOp.getOrdering()))
+      return memOp.emitError("unsupported ordering '")
+             << stringifyAtomicOrdering(memOp.getOrdering()) << "'";
+    if (!memOp.getAlignment())
+      return memOp.emitError("expected alignment for atomic access");
+    return success();
+  }
+  if (memOp.getSyncscope())
+    return memOp.emitError(
+        "expected syncscope to be null for non-atomic access");
+  return success();
+}
+} // namespace
+
+//===----------------------------------------------------------------------===//
+// AtomicRMWOp
+//===----------------------------------------------------------------------===//
+
+void AtomicRMWOp::build(OpBuilder &builder, OperationState &state,
+                        AtomicBinOp binOp, Value ptr, Value val,
+                        AtomicOrdering ordering, StringRef syncscope,
+                        unsigned alignment, bool isVolatile) {
+  build(builder, state, val.getType(), binOp, ptr, val, ordering,
+        !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
+        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
+        /*access_groups=*/nullptr,
+        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
+        /*tbaa=*/nullptr);
+}
+
+SmallVector<Value> AtomicRMWOp::getAccessedOperands() { return {getPtr()}; }
+
+MemoryModel AtomicRMWOp::getMemoryModel() {
+  return getPtr().getType().getMemoryModel();
+}
+
+LogicalResult AtomicRMWOp::verify() {
+  Type valueType = getVal().getType();
+  if (failed(getMemoryModel().isValidAtomicOp(getBinOp(), valueType,
+                                              getOrdering(), getAlignmentAttr(),
+                                              getOperation())))
+    return failure();
+  if (static_cast<unsigned>(getOrdering()) <
+      static_cast<unsigned>(AtomicOrdering::monotonic))
+    return emitError() << "expected at least '"
+                       << stringifyAtomicOrdering(AtomicOrdering::monotonic)
+                       << "' ordering";
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AtomicCmpXchgOp
+//===----------------------------------------------------------------------===//
+
+void AtomicCmpXchgOp::build(OpBuilder &builder, OperationState &state,
+                            Value ptr, Value cmp, Value val,
+                            AtomicOrdering successOrdering,
+                            AtomicOrdering failureOrdering, StringRef syncscope,
+                            unsigned alignment, bool isWeak, bool isVolatile) {
+  build(builder, state, val.getType(), builder.getI1Type(), ptr, cmp, val,
+        successOrdering, failureOrdering,
+        !syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
+        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isWeak,
+        isVolatile, /*access_groups=*/nullptr,
+        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
+}
+
+SmallVector<Value> AtomicCmpXchgOp::getAccessedOperands() { return {getPtr()}; }
+
+MemoryModel AtomicCmpXchgOp::getMemoryModel() {
+  return getPtr().getType().getMemoryModel();
+}
+
+LogicalResult AtomicCmpXchgOp::verify() {
+  Type valueType = getVal().getType();
+  if (failed(getMemoryModel().isValidAtomicXchg(
+          valueType, getSuccessOrdering(), getFailureOrdering(),
+          getAlignmentAttr(), getOperation())))
+    return failure();
+  if (getSuccessOrdering() < AtomicOrdering::monotonic ||
+      getFailureOrdering() < AtomicOrdering::monotonic)
+    return emitError("ordering must be at least 'monotonic'");
+  if (getFailureOrdering() == AtomicOrdering::release ||
+      getFailureOrdering() == AtomicOrdering::acq_rel)
+    return emitError("failure ordering cannot be 'release' or 'acq_rel'");
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// LoadOp
+//===----------------------------------------------------------------------===//
+
+void LoadOp::build(OpBuilder &builder, OperationState &state, Type type,
+                   Value addr, unsigned alignment, bool isVolatile,
+                   bool isNonTemporal, bool isInvariant,
+                   AtomicOrdering ordering, StringRef syncscope) {
+  build(builder, state, type, addr,
+        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
+        isNonTemporal, isInvariant, ordering,
+        syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
+        /*access_groups=*/nullptr,
+        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
+        /*tbaa=*/nullptr);
+}
+
+void LoadOp::getEffects(
+    SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
+        &effects) {
+  effects.emplace_back(MemoryEffects::Read::get(), getAddr());
+  // Volatile operations can have target-specific read-write effects on
+  // memory besides the one referred to by the pointer operand.
+  // Similarly, atomic operations that are monotonic or stricter cause
+  // synchronization that from a language point-of-view, are arbitrary
+  // read-writes into memory.
+  if (getVolatile_() || (getOrdering() != AtomicOrdering::not_atomic &&
+                         getOrdering() != AtomicOrdering::unordered)) {
+    effects.emplace_back(MemoryEffects::Write::get());
+    effects.emplace_back(MemoryEffects::Read::get());
+  }
+}
+
+MemoryModel LoadOp::getMemoryModel() {
+  return getAddr().getType().getMemoryModel();
+}
+
+SmallVector<Value> LoadOp::getAccessedOperands() { return {getAddr()}; }
+
+LogicalResult LoadOp::verify() {
+  Type valueType = getRes().getType();
+  if (failed(getMemoryModel().isValidLoad(valueType, getOrdering(),
+                                          getAlignmentAttr(), getOperation())))
+    return failure();
+  return verifyAtomicMemOp(*this, valueType,
+                           {AtomicOrdering::release, AtomicOrdering::acq_rel});
+}
+
+//===----------------------------------------------------------------------===//
+// StoreOp
+//===----------------------------------------------------------------------===//
+
+void StoreOp::build(OpBuilder &builder, OperationState &state, Value value,
+                    Value addr, unsigned alignment, bool isVolatile,
+                    bool isNonTemporal, AtomicOrdering ordering,
+                    StringRef syncscope) {
+  build(builder, state, value, addr,
+        alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
+        isNonTemporal, ordering,
+        syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
+        /*access_groups=*/nullptr,
+        /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
+        /*tbaa=*/nullptr);
+}
+
+SmallVector<Value> StoreOp::getAccessedOperands() { return {getAddr()}; }
+
+void StoreOp::getEffects(
+    SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
+        &effects) {
+  effects.emplace_back(MemoryEffects::Write::get(), getAddr());
+  // Volatile operations can have target-specific read-write effects on
+  // memory besides the one referred to by the pointer operand.
+  // Similarly, atomic operations that are monotonic or stricter cause
+  // synchronization that from a language point-of-view, are arbitrary
+  // read-writes into memory.
+  if (getVolatile_() || (getOrdering() != AtomicOrdering::not_atomic &&
+                         getOrdering() != AtomicOrdering::unordered)) {
+    effects.emplace_back(MemoryEffects::Write::get());
+    effects.emplace_back(MemoryEffects::Read::get());
+  }
+}
+
+MemoryModel StoreOp::getMemoryModel() {
+  return getAddr().getType().getMemoryModel();
+}
+
+LogicalResult StoreOp::verify() {
+  Type valueType = getValue().getType();
+  if (failed(getMemoryModel().isValidStore(valueType, getOrdering(),
+                                           getAlignmentAttr(), getOperation())))
+    return failure();
+  return verifyAtomicMemOp(*this, valueType,
+                           {AtomicOrdering::acquire, AtomicOrdering::acq_rel});
+}
+
+//===----------------------------------------------------------------------===//
+// AddrSpaceCastOp
+//===----------------------------------------------------------------------===//
+
+MemoryModel AddrSpaceCastOp::getMemoryModel() {
+  if (auto ptrTy = getUnderlyingPtrType(getArg().getType()))
+    return ptrTy.getMemoryModel();
+  return MemoryModel();
+}
+
+OpFoldResult AddrSpaceCastOp::fold(FoldAdaptor adaptor) {
+  // addrcast(x : T0, T0) -> x
+  if (getArg().getType() == getType())
+    return getArg();
+  // addrcast(addrcast(x : T0, T1), T0) -> x
+  if (auto prev = getArg().getDefiningOp<AddrSpaceCastOp>())
+    if (prev.getArg().getType() == getType())
+      return prev.getArg();
+  return {};
+}
+
+LogicalResult AddrSpaceCastOp::verify() {
+  return getMemoryModel().isValidAddrSpaceCast(
+      getRes().getType(), getArg().getType(), getOperation());
+}
+
+//===----------------------------------------------------------------------===//
+// IntToPtrOp
+//===----------------------------------------------------------------------===//
+
+MemoryModel IntToPtrOp::getMemoryModel() {
+  if (auto ptrTy = getUnderlyingPtrType(getRes().getType()))
+    return ptrTy.getMemoryModel();
+  return MemoryModel();
+}
+
+LogicalResult IntToPtrOp::verify() {
+  return getMemoryModel().isValidPtrIntCast(getArg().getType(),
+                                            getRes().getType(), getOperation());
+}
+
+//===----------------------------------------------------------------------===//
+// PtrToIntOp
+//===----------------------------------------------------------------------===//
+
+MemoryModel PtrToIntOp::getMemoryModel() {
+  if (auto ptrTy = getUnderlyingPtrType(getArg().getType()))
+    return MemoryModel(ptrTy.getMemoryModel());
+  return MemoryModel();
+}
+
+LogicalResult PtrToIntOp::verify() {
+  return getMemoryModel().isValidPtrIntCast(getRes().getType(),
+                                            getArg().getType(), getOperation());
+}
+
+//===----------------------------------------------------------------------===//
+// Constant Op
+//===----------------------------------------------------------------------===//
+
+void ConstantOp::build(OpBuilder &odsBuilder, OperationState &odsState,
+                       int64_t value, Attribute addressSpace) {
+  build(odsBuilder, odsState, odsBuilder.getType<PtrType>(addressSpace),
+        odsBuilder.getIndexAttr(value));
+}
+
+void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
+  SmallString<32> buffer;
+  llvm::raw_svector_ostream name(buffer);
+  name << "ptr" << getValueAttr().getValue();
+  setNameFn(getResult(), name.str());
+}
+
+OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
+  return adaptor.getValueAttr();
+}
+
+MemoryModel ConstantOp::getMemoryModel() {
+  return getResult().getType().getMemoryModel();
+}
+
+//===----------------------------------------------------------------------===//
+// TypeOffset Op
+//===----------------------------------------------------------------------===//
+
+OpFoldResult TypeOffsetOp::fold(FoldAdaptor adaptor) {
+  return adaptor.getBaseTypeAttr();
+}
+
+//===----------------------------------------------------------------------===//
+// PtrAdd Op
+//===----------------------------------------------------------------------===//
+
+MemoryModel PtrAddOp::getMemoryModel() {
+  return getResult().getType().getMemoryModel();
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer attributes
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// TBAANodeAttr
+//===----------------------------------------------------------------------===//
+
+bool TBAANodeAttr::classof(Attribute attr) {
+  return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr);
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer interfaces
+//===----------------------------------------------------------------------===//
+
+/// Verifies that all elements of `array` are instances of `Attr`.
+template <class AttrT>
+static LogicalResult isArrayOf(Operation *op, ArrayAttr array) {
+  for (Attribute iter : array)
+    if (!isa<AttrT>(iter))
+      return op->emitError("expected op to return array of ")
+             << AttrT::getMnemonic() << " attributes";
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AccessGroupOpInterface
+//===----------------------------------------------------------------------===//
+
+LogicalResult mlir::ptr::detail::verifyAccessGroupOpInterface(Operation *op) {
+  auto iface = cast<AccessGroupOpInterface>(op);
+  ArrayAttr accessGroups = iface.getAccessGroupsOrNull();
+  if (!accessGroups)
+    return success();
+
+  return isArrayOf<AccessGroupAttr>(op, accessGroups);
+}
+
+//===----------------------------------------------------------------------===//
+// AliasAnalysisOpInterface
+//===----------------------------------------------------------------------===//
+
+LogicalResult mlir::ptr::detail::verifyAliasAnalysisOpInterface(Operation *op) {
+  auto iface = cast<AliasAnalysisOpInterface>(op);
+
+  if (auto aliasScopes = iface.getAliasScopesOrNull())
+    if (failed(isArrayOf<AliasScopeAttr>(op, aliasScopes)))
+      return failure();
+
+  if (auto noAliasScopes = iface.getNoAliasScopesOrNull())
+    if (failed(isArrayOf<AliasScopeAttr>(op, noAliasScopes)))
+      return failure();
+
+  ArrayAttr tags = iface.getTBAATagsOrNull();
+  if (!tags)
+    return success();
+
+  return isArrayOf<TBAATagAttr>(op, tags);
+}
+
+#include "mlir/Dialect/Ptr/IR/PtrOpsDialect.cpp.inc"
+
+#include "mlir/Dialect/Ptr/IR/PtrInterfaces.cpp.inc"
+
+#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.cpp.inc"
+
+#include "mlir/Dialect/Ptr/IR/MemorySpaceAttrInterfaces.cpp.inc"
+
+#include "mlir/Dialect/Ptr/IR/PtrOpsEnums.cpp.inc"
+
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/Ptr/IR/PtrOpsAttrs.cpp.inc"
+
+#define GET_TYPEDEF_CLASSES
+#include "mlir/Dialect/Ptr/IR/PtrOpsTypes.cpp.inc"
+
+#define GET_OP_CLASSES
+#include "mlir/Dialect/Ptr/IR/PtrOps.cpp.inc"
diff --git a/mlir/lib/Dialect/Ptr/IR/PtrMemorySlot.cpp b/mlir/lib/Dialect/Ptr/IR/PtrMemorySlot.cpp
new file mode 100644
index 00000000000000..54608b8422214a
--- /dev/null
+++ b/mlir/lib/Dialect/Ptr/IR/PtrMemorySlot.cpp
@@ -0,0 +1,233 @@
+//===- LLVMMemorySlot.cpp - MemorySlot interfaces ---------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements MemorySlot-related interfaces for LLVM dialect
+// operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Ptr/IR/PtrOps.h"
+#include "mlir/IR/DialectImplementation.h"
+#include "mlir/IR/Matchers.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "mlir/Interfaces/MemorySlotInterfaces.h"
+#include "mlir/Transforms/InliningUtils.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+using namespace mlir;
+using namespace mlir::ptr;
+
+namespace {
+/// Checks if `slot` can be accessed through the provided access type.
+bool isValidAccessType(const MemorySlot &slot, Type accessType,
+                       const DataLayout &dataLayout) {
+  return dataLayout.getTypeSize(accessType) <=
+         dataLayout.getTypeSize(slot.elemType);
+}
+
+/// Returns the subslot's type at the requested index.
+Type getTypeAtIndex(const DestructurableMemorySlot &slot, Attribute index) {
+  auto subelementIndexMap =
+      slot.elemType.cast<DestructurableTypeInterface>().getSubelementIndexMap();
+  if (!subelementIndexMap)
+    return {};
+  assert(!subelementIndexMap->empty());
+
+  // Note: Returns a null-type when no entry was found.
+  return subelementIndexMap->lookup(index);
+}
+
+/// Conditions the deletion of the operation to the removal of all its uses.
+bool forwardToUsers(Operation *op,
+                    SmallVectorImpl<OpOperand *> &newBlockingUses) {
+  for (Value result : op->getResults())
+    for (OpOperand &use : result.getUses())
+      newBlockingUses.push_back(&use);
+  return true;
+}
+} // namespace
+
+//===----------------------------------------------------------------------===//
+// AddrSpaceCastOp
+//===----------------------------------------------------------------------===//
+
+bool AddrSpaceCastOp::canUsesBeRemoved(
+    const SmallPtrSetImpl<OpOperand *> &blockingUses,
+    SmallVectorImpl<OpOperand *> &newBlockingUses,
+    const ::mlir::DataLayout &dataLayout) {
+  return forwardToUsers(*this, newBlockingUses);
+}
+
+DeletionKind AddrSpaceCastOp::removeBlockingUses(
+    const SmallPtrSetImpl<OpOperand *> &blockingUses, RewriterBase &rewriter) {
+  return DeletionKind::Delete;
+}
+
+//===----------------------------------------------------------------------===//
+// LoadOp
+//===----------------------------------------------------------------------===//
+
+Value ptr::LoadOp::getStored(const MemorySlot &slot, RewriterBase &rewriter) {
+  llvm_unreachable("getStored should not be called on LoadOp");
+}
+
+bool ptr::LoadOp::loadsFrom(const MemorySlot &slot) {
+  return getAddr() == slot.ptr;
+}
+
+bool ptr::LoadOp::storesTo(const MemorySlot &slot) { return false; }
+
+bool LoadOp::canUsesBeRemoved(const MemorySlot &slot,
+                              const SmallPtrSetImpl<OpOperand *> &blockingUses,
+                              SmallVectorImpl<OpOperand *> &newBlockingUses,
+                              const ::mlir::DataLayout &datalayout) {
+  if (blockingUses.size() != 1)
+    return false;
+  Value blockingUse = (*blockingUses.begin())->get();
+  // If the blocking use is the slot ptr itself, there will be enough
+  // context to reconstruct the result of the load at removal time, so it can
+  // be removed (provided it loads the exact stored value and is not
+  // volatile).
+  return blockingUse == slot.ptr && getAddr() == slot.ptr &&
+         getResult().getType() == slot.elemType && !getVolatile_();
+}
+
+DeletionKind
+LoadOp::removeBlockingUses(const MemorySlot &slot,
+                           const SmallPtrSetImpl<OpOperand *> &blockingUses,
+                           RewriterBase &rewriter, Value reachingDefinition) {
+  // `canUsesBeRemoved` checked this blocking use must be the loaded slot
+  // pointer.
+  rewriter.replaceAllUsesWith(getResult(), reachingDefinition);
+  return DeletionKind::Delete;
+}
+
+LogicalResult
+LoadOp::ensureOnlySafeAccesses(const MemorySlot &slot,
+                               SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
+                               const ::mlir::DataLayout &dataLayout) {
+  return success(getAddr() != slot.ptr ||
+                 isValidAccessType(slot, getType(), dataLayout));
+}
+
+bool LoadOp::canRewire(const DestructurableMemorySlot &slot,
+                       SmallPtrSetImpl<Attribute> &usedIndices,
+                       SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
+                       const DataLayout &dataLayout) {
+  if (getVolatile_())
+    return false;
+
+  // A load always accesses the first element of the destructured slot.
+  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
+  Type subslotType = getTypeAtIndex(slot, index);
+  if (!subslotType)
+    return false;
+
+  // The access can only be replaced when the subslot is read within its bounds.
+  if (dataLayout.getTypeSize(getType()) > dataLayout.getTypeSize(subslotType))
+    return false;
+
+  usedIndices.insert(index);
+  return true;
+}
+
+DeletionKind LoadOp::rewire(const DestructurableMemorySlot &slot,
+                            DenseMap<Attribute, MemorySlot> &subslots,
+                            RewriterBase &rewriter,
+                            const DataLayout &dataLayout) {
+  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
+  auto it = subslots.find(index);
+  assert(it != subslots.end());
+
+  rewriter.modifyOpInPlace(
+      *this, [&]() { getAddrMutable().set(it->getSecond().ptr); });
+  return DeletionKind::Keep;
+}
+
+//===----------------------------------------------------------------------===//
+// StoreOp
+//===----------------------------------------------------------------------===//
+
+bool StoreOp::loadsFrom(const MemorySlot &slot) { return false; }
+
+bool StoreOp::storesTo(const MemorySlot &slot) { return getAddr() == slot.ptr; }
+
+Value StoreOp::getStored(const MemorySlot &slot, RewriterBase &rewriter) {
+  return getValue();
+}
+
+bool StoreOp::canUsesBeRemoved(const MemorySlot &slot,
+                               const SmallPtrSetImpl<OpOperand *> &blockingUses,
+                               SmallVectorImpl<OpOperand *> &newBlockingUses,
+                               const ::mlir::DataLayout &datalayout) {
+  if (blockingUses.size() != 1)
+    return false;
+  Value blockingUse = (*blockingUses.begin())->get();
+  // If the blocking use is the slot ptr itself, dropping the store is
+  // fine, provided we are currently promoting its target value. Don't allow a
+  // store OF the slot pointer, only INTO the slot pointer.
+  return blockingUse == slot.ptr && getAddr() == slot.ptr &&
+         getValue() != slot.ptr && getValue().getType() == slot.elemType &&
+         !getVolatile_();
+}
+
+DeletionKind
+StoreOp::removeBlockingUses(const MemorySlot &slot,
+                            const SmallPtrSetImpl<OpOperand *> &blockingUses,
+                            RewriterBase &rewriter, Value reachingDefinition) {
+  return DeletionKind::Delete;
+}
+
+LogicalResult
+StoreOp::ensureOnlySafeAccesses(const MemorySlot &slot,
+                                SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
+                                const ::mlir::DataLayout &dataLayout) {
+  return success(getAddr() != slot.ptr ||
+                 isValidAccessType(slot, getValue().getType(), dataLayout));
+}
+
+bool StoreOp::canRewire(const DestructurableMemorySlot &slot,
+                        SmallPtrSetImpl<Attribute> &usedIndices,
+                        SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
+                        const DataLayout &dataLayout) {
+  if (getVolatile_())
+    return false;
+
+  // Storing the pointer to memory cannot be dealt with.
+  if (getValue() == slot.ptr)
+    return false;
+
+  // A store always accesses the first element of the destructured slot.
+  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
+  Type subslotType = getTypeAtIndex(slot, index);
+  if (!subslotType)
+    return false;
+
+  // The access can only be replaced when the subslot is read within its bounds.
+  if (dataLayout.getTypeSize(getValue().getType()) >
+      dataLayout.getTypeSize(subslotType))
+    return false;
+
+  usedIndices.insert(index);
+  return true;
+}
+
+DeletionKind StoreOp::rewire(const DestructurableMemorySlot &slot,
+                             DenseMap<Attribute, MemorySlot> &subslots,
+                             RewriterBase &rewriter,
+                             const DataLayout &dataLayout) {
+  auto index = IntegerAttr::get(IntegerType::get(getContext(), 32), 0);
+  auto it = subslots.find(index);
+  assert(it != subslots.end());
+
+  rewriter.modifyOpInPlace(
+      *this, [&]() { getAddrMutable().set(it->getSecond().ptr); });
+  return DeletionKind::Keep;
+}
diff --git a/mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp b/mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp
new file mode 100644
index 00000000000000..25a8dec2b1b249
--- /dev/null
+++ b/mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp
@@ -0,0 +1,198 @@
+//===- PtrTypes.cpp - Pointer dialect types ---------------------*- C++ -*-===//
+//
+// This file is licensed 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Ptr dialect types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Ptr/IR/PtrTypes.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+using namespace mlir;
+using namespace mlir::ptr;
+
+//===----------------------------------------------------------------------===//
+// Pointer type
+//===----------------------------------------------------------------------===//
+
+constexpr const static unsigned kDefaultPointerSizeBits = 64;
+constexpr const static unsigned kBitsInByte = 8;
+constexpr const static unsigned kDefaultPointerAlignment = 8;
+
+/// Returns the part of the data layout entry that corresponds to `pos` for the
+/// given `type` by interpreting the list of entries `params`. For the pointer
+/// type in the default address space, returns the default value if the entries
+/// do not provide a custom one, for other address spaces returns std::nullopt.
+static std::optional<uint64_t>
+getPointerDataLayoutEntry(DataLayoutEntryListRef params, PtrType type,
+                          PtrDLEntryPos pos) {
+  // First, look for the entry for the pointer in the current address space.
+  Attribute currentEntry;
+  for (DataLayoutEntryInterface entry : params) {
+    if (!entry.isTypeEntry())
+      continue;
+    if (cast<PtrType>(entry.getKey().get<Type>()).getAddressSpace() ==
+        type.getAddressSpace()) {
+      currentEntry = entry.getValue();
+      break;
+    }
+  }
+  if (currentEntry) {
+    std::optional<uint64_t> value = extractPointerSpecValue(currentEntry, pos);
+    // If the optional `PtrDLEntryPos::Index` entry is not available, use the
+    // pointer size as the index bitwidth.
+    if (!value && pos == PtrDLEntryPos::Index)
+      value = extractPointerSpecValue(currentEntry, PtrDLEntryPos::Size);
+    bool isSizeOrIndex =
+        pos == PtrDLEntryPos::Size || pos == PtrDLEntryPos::Index;
+    return *value / (isSizeOrIndex ? 1 : kBitsInByte);
+  }
+
+  // If not found, and this is the pointer to the default memory space, assume
+  // 64-bit pointers.
+  if (type.getAddressSpace() == 0) {
+    bool isSizeOrIndex =
+        pos == PtrDLEntryPos::Size || pos == PtrDLEntryPos::Index;
+    return isSizeOrIndex ? kDefaultPointerSizeBits : kDefaultPointerAlignment;
+  }
+
+  return std::nullopt;
+}
+
+Dialect *PtrType::getAliasDialect() const {
+  if (auto iface =
+          mlir::dyn_cast_or_null<MemorySpaceAttrInterface>(getMemorySpace()))
+    if (auto dialect = iface.getMemorySpaceDialect())
+      return dialect;
+  return &getDialect();
+}
+
+MemoryModel PtrType::getMemoryModel() const { return getMemorySpace(); }
+
+int64_t PtrType::getAddressSpace() const {
+  return getMemoryModel().getAddressSpace();
+}
+
+Attribute PtrType::getDefaultMemorySpace() const {
+  return getMemoryModel().getDefaultMemorySpace();
+}
+
+bool PtrType::areCompatible(DataLayoutEntryListRef oldLayout,
+                            DataLayoutEntryListRef newLayout) const {
+  for (DataLayoutEntryInterface newEntry : newLayout) {
+    if (!newEntry.isTypeEntry())
+      continue;
+    unsigned size = kDefaultPointerSizeBits;
+    unsigned abi = kDefaultPointerAlignment;
+    auto newType = llvm::cast<PtrType>(newEntry.getKey().get<Type>());
+    const auto *it =
+        llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
+          if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
+            return llvm::cast<PtrType>(type).getMemorySpace() ==
+                   newType.getMemorySpace();
+          }
+          return false;
+        });
+    if (it == oldLayout.end()) {
+      llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
+        if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
+          return llvm::cast<PtrType>(type).getAddressSpace() == 0;
+        }
+        return false;
+      });
+    }
+    if (it != oldLayout.end()) {
+      size = *extractPointerSpecValue(*it, PtrDLEntryPos::Size);
+      abi = *extractPointerSpecValue(*it, PtrDLEntryPos::Abi);
+    }
+
+    Attribute newSpec = llvm::cast<DenseIntElementsAttr>(newEntry.getValue());
+    unsigned newSize = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Size);
+    unsigned newAbi = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Abi);
+    if (size != newSize || abi < newAbi || abi % newAbi != 0)
+      return false;
+  }
+  return true;
+}
+
+uint64_t PtrType::getABIAlignment(const DataLayout &dataLayout,
+                                  DataLayoutEntryListRef params) const {
+  if (std::optional<uint64_t> alignment =
+          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Abi))
+    return *alignment;
+
+  return dataLayout.getTypeABIAlignment(
+      get(getContext(), getDefaultMemorySpace()));
+}
+
+std::optional<uint64_t>
+PtrType::getIndexBitwidth(const DataLayout &dataLayout,
+                          DataLayoutEntryListRef params) const {
+  if (std::optional<uint64_t> indexBitwidth =
+          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Index))
+    return *indexBitwidth;
+
+  return dataLayout.getTypeIndexBitwidth(
+      get(getContext(), getDefaultMemorySpace()));
+}
+
+llvm::TypeSize PtrType::getTypeSizeInBits(const DataLayout &dataLayout,
+                                          DataLayoutEntryListRef params) const {
+  if (std::optional<uint64_t> size =
+          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Size))
+    return llvm::TypeSize::getFixed(*size);
+
+  // For other memory spaces, use the size of the pointer to the default memory
+  // space.
+  return dataLayout.getTypeSizeInBits(
+      get(getContext(), getDefaultMemorySpace()));
+}
+
+uint64_t PtrType::getPreferredAlignment(const DataLayout &dataLayout,
+                                        DataLayoutEntryListRef params) const {
+  if (std::optional<uint64_t> alignment =
+          getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Preferred))
+    return *alignment;
+
+  return dataLayout.getTypePreferredAlignment(
+      get(getContext(), getDefaultMemorySpace()));
+}
+
+std::optional<uint64_t> mlir::ptr::extractPointerSpecValue(Attribute attr,
+                                                           PtrDLEntryPos pos) {
+  auto spec = cast<DenseIntElementsAttr>(attr);
+  auto idx = static_cast<int64_t>(pos);
+  if (idx >= spec.size())
+    return std::nullopt;
+  return spec.getValues<uint64_t>()[idx];
+}
+
+LogicalResult PtrType::verifyEntries(DataLayoutEntryListRef entries,
+                                     Location loc) const {
+  for (DataLayoutEntryInterface entry : entries) {
+    if (!entry.isTypeEntry())
+      continue;
+    auto key = entry.getKey().get<Type>();
+    auto values = llvm::dyn_cast<DenseIntElementsAttr>(entry.getValue());
+    if (!values || (values.size() != 3 && values.size() != 4)) {
+      return emitError(loc)
+             << "expected layout attribute for " << key
+             << " to be a dense integer elements attribute with 3 or 4 "
+                "elements";
+    }
+    if (!values.getElementType().isInteger(64))
+      return emitError(loc) << "expected i64 parameters for " << key;
+
+    if (extractPointerSpecValue(values, PtrDLEntryPos::Abi) >
+        extractPointerSpecValue(values, PtrDLEntryPos::Preferred)) {
+      return emitError(loc) << "preferred alignment is expected to be at least "
+                               "as large as ABI alignment";
+    }
+  }
+  return success();
+}
diff --git a/mlir/lib/Dialect/SparseTensor/Transforms/SparseTensorPasses.cpp b/mlir/lib/Dialect/SparseTensor/Transforms/SparseTensorPasses.cpp
index d4c17928d4ca15..4b48be3220fec5 100644
--- a/mlir/lib/Dialect/SparseTensor/Transforms/SparseTensorPasses.cpp
+++ b/mlir/lib/Dialect/SparseTensor/Transforms/SparseTensorPasses.cpp
@@ -210,9 +210,10 @@ struct SparseTensorConversionPass
     target.addLegalOp<complex::ConstantOp, complex::NotEqualOp, linalg::FillOp,
                       linalg::YieldOp, tensor::ExtractOp,
                       tensor::FromElementsOp>();
-    target.addLegalDialect<
-        arith::ArithDialect, bufferization::BufferizationDialect,
-        LLVM::LLVMDialect, memref::MemRefDialect, scf::SCFDialect>();
+    target.addLegalDialect<arith::ArithDialect,
+                           bufferization::BufferizationDialect, ptr::PtrDialect,
+                           LLVM::LLVMDialect, memref::MemRefDialect,
+                           scf::SCFDialect>();
 
     // Populate with rules and apply rewriting rules.
     populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(patterns,
diff --git a/mlir/lib/ExecutionEngine/CMakeLists.txt b/mlir/lib/ExecutionEngine/CMakeLists.txt
index b7e448d5417ea9..ff7376a1632232 100644
--- a/mlir/lib/ExecutionEngine/CMakeLists.txt
+++ b/mlir/lib/ExecutionEngine/CMakeLists.txt
@@ -93,6 +93,7 @@ add_mlir_library(MLIRExecutionEngine
   MLIRExecutionEngineUtils
   MLIRLLVMDialect
   MLIRLLVMToLLVMIRTranslation
+  MLIRPtrToLLVMIRTranslation
   MLIROpenMPToLLVMIRTranslation
   MLIRTargetLLVMIRExport
   )
@@ -119,6 +120,7 @@ add_mlir_library(MLIRJitRunner
   MLIRIR
   MLIRParser
   MLIRLLVMToLLVMIRTranslation
+  MLIRPtrToLLVMIRTranslation
   MLIRTargetLLVMIRExport
   MLIRTransforms
   MLIRSupport
diff --git a/mlir/lib/IR/AsmInterfaces.cpp b/mlir/lib/IR/AsmInterfaces.cpp
new file mode 100644
index 00000000000000..009701912cf2d3
--- /dev/null
+++ b/mlir/lib/IR/AsmInterfaces.cpp
@@ -0,0 +1,19 @@
+//===- AsmInterfaces.cpp --------------------------------------------------===//
+//
+// 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 "mlir/IR/AsmInterfaces.h"
+
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+/// Tablegen Interface Definitions
+//===----------------------------------------------------------------------===//
+
+#include "mlir/IR/AsmAttrInterfaces.cpp.inc"
+
+#include "mlir/IR/AsmTypeInterfaces.cpp.inc"
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index 456cf6a2c27783..cd837cbd2b1b40 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -13,6 +13,7 @@
 
 #include "mlir/IR/AffineExpr.h"
 #include "mlir/IR/AffineMap.h"
+#include "mlir/IR/AsmInterfaces.h"
 #include "mlir/IR/AsmState.h"
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/Builders.h"
@@ -542,7 +543,9 @@ class AliasInitializer {
         aliasOS(aliasBuffer) {}
 
   void initialize(Operation *op, const OpPrintingFlags &printerFlags,
-                  llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias);
+                  llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias,
+                  llvm::DenseMap<const void *, const OpAsmDialectInterface *>
+                      &attrTypeToDialectAlias);
 
   /// Visit the given attribute to see if it has an alias. `canBeDeferred` is
   /// set to true if the originator of this attribute can resolve the alias
@@ -570,6 +573,10 @@ class AliasInitializer {
     InProgressAliasInfo(StringRef alias, bool isType, bool canBeDeferred)
         : alias(alias), aliasDepth(1), isType(isType),
           canBeDeferred(canBeDeferred) {}
+    InProgressAliasInfo(const OpAsmDialectInterface *aliasDialect, bool isType,
+                        bool canBeDeferred)
+        : alias(std::nullopt), aliasDepth(1), isType(isType),
+          canBeDeferred(canBeDeferred), aliasDialect(aliasDialect) {}
 
     bool operator<(const InProgressAliasInfo &rhs) const {
       // Order first by depth, then by attr/type kind, and then by name.
@@ -577,6 +584,8 @@ class AliasInitializer {
         return aliasDepth < rhs.aliasDepth;
       if (isType != rhs.isType)
         return isType;
+      if (aliasDialect != rhs.aliasDialect)
+        return aliasDialect < rhs.aliasDialect;
       return alias < rhs.alias;
     }
 
@@ -592,6 +601,8 @@ class AliasInitializer {
     bool canBeDeferred : 1;
     /// Indices for child aliases.
     SmallVector<size_t> childIndices;
+    /// Dialect interface used to print the alias.
+    const OpAsmDialectInterface *aliasDialect{};
   };
 
   /// Visit the given attribute or type to see if it has an alias.
@@ -617,7 +628,9 @@ class AliasInitializer {
   /// symbol to a given alias.
   static void initializeAliases(
       llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
-      llvm::MapVector<const void *, SymbolAlias> &symbolToAlias);
+      llvm::MapVector<const void *, SymbolAlias> &symbolToAlias,
+      llvm::DenseMap<const void *, const OpAsmDialectInterface *>
+          &attrTypeToDialectAlias);
 
   /// The set of asm interfaces within the context.
   DialectInterfaceCollection<OpAsmDialectInterface> &interfaces;
@@ -1027,7 +1040,9 @@ static StringRef sanitizeIdentifier(StringRef name, SmallString<16> &buffer,
 /// symbol to a given alias.
 void AliasInitializer::initializeAliases(
     llvm::MapVector<const void *, InProgressAliasInfo> &visitedSymbols,
-    llvm::MapVector<const void *, SymbolAlias> &symbolToAlias) {
+    llvm::MapVector<const void *, SymbolAlias> &symbolToAlias,
+    llvm::DenseMap<const void *, const OpAsmDialectInterface *>
+        &attrTypeToDialectAlias) {
   SmallVector<std::pair<const void *, InProgressAliasInfo>, 0>
       unprocessedAliases = visitedSymbols.takeVector();
   llvm::stable_sort(unprocessedAliases, [](const auto &lhs, const auto &rhs) {
@@ -1036,8 +1051,12 @@ void AliasInitializer::initializeAliases(
 
   llvm::StringMap<unsigned> nameCounts;
   for (auto &[symbol, aliasInfo] : unprocessedAliases) {
-    if (!aliasInfo.alias)
+    if (!aliasInfo.alias && !aliasInfo.aliasDialect)
       continue;
+    if (aliasInfo.aliasDialect) {
+      attrTypeToDialectAlias.insert({symbol, aliasInfo.aliasDialect});
+      continue;
+    }
     StringRef alias = *aliasInfo.alias;
     unsigned nameIndex = nameCounts[alias]++;
     symbolToAlias.insert(
@@ -1048,7 +1067,9 @@ void AliasInitializer::initializeAliases(
 
 void AliasInitializer::initialize(
     Operation *op, const OpPrintingFlags &printerFlags,
-    llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias) {
+    llvm::MapVector<const void *, SymbolAlias> &attrTypeToAlias,
+    llvm::DenseMap<const void *, const OpAsmDialectInterface *>
+        &attrTypeToDialectAlias) {
   // Use a dummy printer when walking the IR so that we can collect the
   // attributes/types that will actually be used during printing when
   // considering aliases.
@@ -1056,7 +1077,7 @@ void AliasInitializer::initialize(
   aliasPrinter.printCustomOrGenericOp(op);
 
   // Initialize the aliases.
-  initializeAliases(aliases, attrTypeToAlias);
+  initializeAliases(aliases, attrTypeToAlias, attrTypeToDialectAlias);
 }
 
 template <typename T, typename... PrintArgs>
@@ -1113,9 +1134,14 @@ template <typename T>
 void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
                                      bool canBeDeferred) {
   SmallString<32> nameBuffer;
+  const OpAsmDialectInterface *dialectAlias = nullptr;
   for (const auto &interface : interfaces) {
     OpAsmDialectInterface::AliasResult result =
         interface.getAlias(symbol, aliasOS);
+    if (result == OpAsmDialectInterface::AliasResult::DialectAlias) {
+      dialectAlias = &interface;
+      break;
+    }
     if (result == OpAsmDialectInterface::AliasResult::NoAlias)
       continue;
     nameBuffer = std::move(aliasBuffer);
@@ -1123,6 +1149,11 @@ void AliasInitializer::generateAlias(T symbol, InProgressAliasInfo &alias,
     if (result == OpAsmDialectInterface::AliasResult::FinalAlias)
       break;
   }
+  if (dialectAlias) {
+    alias = InProgressAliasInfo(
+        dialectAlias, /*isType=*/std::is_base_of_v<Type, T>, canBeDeferred);
+    return;
+  }
 
   if (nameBuffer.empty())
     return;
@@ -1157,6 +1188,13 @@ class AliasState {
   /// Returns success if an alias was printed, failure otherwise.
   LogicalResult getAlias(Type ty, raw_ostream &os) const;
 
+  /// Get a dialect alias for the given attribute if it has one or return
+  /// nullptr.
+  const OpAsmDialectInterface *getDialectAlias(Attribute attr) const;
+
+  /// Get a dialect alias for the given type if it has one or return nullptr.
+  const OpAsmDialectInterface *getDialectAlias(Type ty) const;
+
   /// Print all of the referenced aliases that can not be resolved in a deferred
   /// manner.
   void printNonDeferredAliases(AsmPrinter::Impl &p, NewLineCounter &newLine) {
@@ -1177,6 +1215,10 @@ class AliasState {
   /// Mapping between attribute/type and alias.
   llvm::MapVector<const void *, SymbolAlias> attrTypeToAlias;
 
+  /// Mapping between attribute/type and alias dialect interfaces.
+  llvm::DenseMap<const void *, const OpAsmDialectInterface *>
+      attrTypeToDialectAlias;
+
   /// An allocator used for alias names.
   llvm::BumpPtrAllocator aliasAllocator;
 };
@@ -1186,7 +1228,8 @@ void AliasState::initialize(
     Operation *op, const OpPrintingFlags &printerFlags,
     DialectInterfaceCollection<OpAsmDialectInterface> &interfaces) {
   AliasInitializer initializer(interfaces, aliasAllocator);
-  initializer.initialize(op, printerFlags, attrTypeToAlias);
+  initializer.initialize(op, printerFlags, attrTypeToAlias,
+                         attrTypeToDialectAlias);
 }
 
 LogicalResult AliasState::getAlias(Attribute attr, raw_ostream &os) const {
@@ -1206,6 +1249,20 @@ LogicalResult AliasState::getAlias(Type ty, raw_ostream &os) const {
   return success();
 }
 
+const OpAsmDialectInterface *AliasState::getDialectAlias(Attribute attr) const {
+  auto it = attrTypeToDialectAlias.find(attr.getAsOpaquePointer());
+  if (it == attrTypeToDialectAlias.end())
+    return nullptr;
+  return it->second;
+}
+
+const OpAsmDialectInterface *AliasState::getDialectAlias(Type ty) const {
+  auto it = attrTypeToDialectAlias.find(ty.getAsOpaquePointer());
+  if (it == attrTypeToDialectAlias.end())
+    return nullptr;
+  return it->second;
+}
+
 void AliasState::printAliases(AsmPrinter::Impl &p, NewLineCounter &newLine,
                               bool isDeferred) {
   auto filterFn = [=](const auto &aliasIt) {
@@ -2189,11 +2246,43 @@ static void printElidedElementsAttr(raw_ostream &os) {
 }
 
 LogicalResult AsmPrinter::Impl::printAlias(Attribute attr) {
-  return state.getAliasState().getAlias(attr, os);
+  if (succeeded(state.getAliasState().getAlias(attr, os)))
+    return success();
+  const OpAsmDialectInterface *iface =
+      state.getAliasState().getDialectAlias(attr);
+  if (!iface)
+    return failure();
+  // Ask the dialect to serialize the attribute to a string.
+  std::string attrName;
+  {
+    llvm::raw_string_ostream attrNameStr(attrName);
+    Impl subPrinter(attrNameStr, state);
+    DialectAsmPrinter printer(subPrinter);
+    if (failed(iface->printDialectAlias(printer, attr)))
+      return failure();
+  }
+  printDialectSymbol(os, "#", iface->getDialect()->getNamespace(), attrName);
+  return success();
 }
 
 LogicalResult AsmPrinter::Impl::printAlias(Type type) {
-  return state.getAliasState().getAlias(type, os);
+  if (succeeded(state.getAliasState().getAlias(type, os)))
+    return success();
+  const OpAsmDialectInterface *iface =
+      state.getAliasState().getDialectAlias(type);
+  if (!iface)
+    return failure();
+  // Ask the dialect to serialize the type to a string.
+  std::string typeName;
+  {
+    llvm::raw_string_ostream typeNameStr(typeName);
+    Impl subPrinter(typeNameStr, state);
+    DialectAsmPrinter printer(subPrinter);
+    if (failed(iface->printDialectAlias(printer, type)))
+      return failure();
+  }
+  printDialectSymbol(os, "!", iface->getDialect()->getNamespace(), typeName);
+  return success();
 }
 
 void AsmPrinter::Impl::printAttribute(Attribute attr,
@@ -2701,7 +2790,9 @@ void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
 }
 
 void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
-  auto &dialect = attr.getDialect();
+  Dialect *dialect = &attr.getDialect();
+  if (auto iface = dyn_cast<AttrAsmAliasAttrInterface>(attr))
+    dialect = iface.getAliasDialect();
 
   // Ask the dialect to serialize the attribute to a string.
   std::string attrName;
@@ -2709,13 +2800,15 @@ void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
     llvm::raw_string_ostream attrNameStr(attrName);
     Impl subPrinter(attrNameStr, state);
     DialectAsmPrinter printer(subPrinter);
-    dialect.printAttribute(attr, printer);
+    dialect->printAttribute(attr, printer);
   }
-  printDialectSymbol(os, "#", dialect.getNamespace(), attrName);
+  printDialectSymbol(os, "#", dialect->getNamespace(), attrName);
 }
 
 void AsmPrinter::Impl::printDialectType(Type type) {
-  auto &dialect = type.getDialect();
+  Dialect *dialect = &type.getDialect();
+  if (auto iface = dyn_cast<TypeAsmAliasTypeInterface>(type))
+    dialect = iface.getAliasDialect();
 
   // Ask the dialect to serialize the type to a string.
   std::string typeName;
@@ -2723,9 +2816,9 @@ void AsmPrinter::Impl::printDialectType(Type type) {
     llvm::raw_string_ostream typeNameStr(typeName);
     Impl subPrinter(typeNameStr, state);
     DialectAsmPrinter printer(subPrinter);
-    dialect.printType(type, printer);
+    dialect->printType(type, printer);
   }
-  printDialectSymbol(os, "!", dialect.getNamespace(), typeName);
+  printDialectSymbol(os, "!", dialect->getNamespace(), typeName);
 }
 
 void AsmPrinter::Impl::printEscapedString(StringRef str) {
diff --git a/mlir/lib/IR/CMakeLists.txt b/mlir/lib/IR/CMakeLists.txt
index c38ce6c058a006..0fd71dfa5c4499 100644
--- a/mlir/lib/IR/CMakeLists.txt
+++ b/mlir/lib/IR/CMakeLists.txt
@@ -7,6 +7,7 @@ endif()
 add_mlir_library(MLIRIR
   AffineExpr.cpp
   AffineMap.cpp
+  AsmInterfaces.cpp
   AsmPrinter.cpp
   Attributes.cpp
   AttrTypeSubElements.cpp
@@ -48,6 +49,7 @@ add_mlir_library(MLIRIR
   ${MLIR_MAIN_INCLUDE_DIR}/mlir/IR
 
   DEPENDS
+  MLIRAsmInterfacesIncGen
   MLIRBuiltinAttributesIncGen
   MLIRBuiltinAttributeInterfacesIncGen
   MLIRBuiltinDialectBytecodeIncGen
diff --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt
index 93032c3ce10387..bdd22d99a8be7b 100644
--- a/mlir/lib/Target/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt
@@ -37,6 +37,7 @@ add_mlir_translation_library(MLIRTargetLLVMIRExport
   LINK_LIBS PUBLIC
   MLIRDLTIDialect
   MLIRLLVMDialect
+  MLIRPtrDialect
   MLIRLLVMIRTransforms
   MLIRTranslateLib
   MLIRTransformUtils
@@ -57,6 +58,7 @@ add_mlir_translation_library(MLIRToLLVMIRTranslationRegistration
   MLIRNVVMToLLVMIRTranslation
   MLIROpenACCToLLVMIRTranslation
   MLIROpenMPToLLVMIRTranslation
+  MLIRPtrToLLVMIRTranslation
   MLIRROCDLToLLVMIRTranslation
   MLIRSPIRVToLLVMIRTranslation
   MLIRVCIXToLLVMIRTranslation
@@ -79,6 +81,7 @@ add_mlir_translation_library(MLIRTargetLLVMIRImport
   LINK_LIBS PUBLIC
   MLIRDLTIDialect
   MLIRLLVMDialect
+  MLIRPtrDialect
   MLIRTranslateLib
   )
 
@@ -88,4 +91,5 @@ add_mlir_translation_library(MLIRFromLLVMIRTranslationRegistration
   LINK_LIBS PUBLIC
   MLIRLLVMIRToLLVMTranslation
   MLIRLLVMIRToNVVMTranslation
+  MLIRLLVMIRToPtrTranslation
   )
diff --git a/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt
index a88e8b1fd8338e..de1a5944546af6 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt
+++ b/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory(LLVMIR)
 add_subdirectory(NVVM)
 add_subdirectory(OpenACC)
 add_subdirectory(OpenMP)
+add_subdirectory(Ptr)
 add_subdirectory(ROCDL)
 add_subdirectory(SPIRV)
 add_subdirectory(VCIX)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
index 40d8253d822f64..c71ccf5d82ff02 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
@@ -32,6 +32,27 @@ using namespace mlir::LLVM::detail;
 
 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsFromLLVM.inc"
 
+LLVM_ATTRIBUTE_UNUSED static ptr::AtomicOrdering
+convertAtomicOrderingFromLLVM(::llvm::AtomicOrdering value) {
+  switch (value) {
+  case ::llvm::AtomicOrdering::NotAtomic:
+    return AtomicOrdering::not_atomic;
+  case ::llvm::AtomicOrdering::Unordered:
+    return AtomicOrdering::unordered;
+  case ::llvm::AtomicOrdering::Monotonic:
+    return AtomicOrdering::monotonic;
+  case ::llvm::AtomicOrdering::Acquire:
+    return AtomicOrdering::acquire;
+  case ::llvm::AtomicOrdering::Release:
+    return AtomicOrdering::release;
+  case ::llvm::AtomicOrdering::AcquireRelease:
+    return AtomicOrdering::acq_rel;
+  case ::llvm::AtomicOrdering::SequentiallyConsistent:
+    return AtomicOrdering::seq_cst;
+  }
+  llvm_unreachable("unknown ::llvm::AtomicOrdering type");
+}
+
 /// Returns true if the LLVM IR intrinsic is convertible to an MLIR LLVM dialect
 /// intrinsic. Returns false otherwise.
 static bool isConvertibleIntrinsic(llvm::Intrinsic::ID id) {
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index f144c7158d6796..7452d9912a5b72 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -28,6 +28,27 @@ using mlir::LLVM::detail::getLLVMConstant;
 
 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
 
+static ::llvm::AtomicOrdering
+convertAtomicOrderingToLLVM(AtomicOrdering value) {
+  switch (value) {
+  case AtomicOrdering::not_atomic:
+    return ::llvm::AtomicOrdering::NotAtomic;
+  case AtomicOrdering::unordered:
+    return ::llvm::AtomicOrdering::Unordered;
+  case AtomicOrdering::monotonic:
+    return ::llvm::AtomicOrdering::Monotonic;
+  case AtomicOrdering::acquire:
+    return ::llvm::AtomicOrdering::Acquire;
+  case AtomicOrdering::release:
+    return ::llvm::AtomicOrdering::Release;
+  case AtomicOrdering::acq_rel:
+    return ::llvm::AtomicOrdering::AcquireRelease;
+  case AtomicOrdering::seq_cst:
+    return ::llvm::AtomicOrdering::SequentiallyConsistent;
+  }
+  llvm_unreachable("unknown AtomicOrdering type");
+}
+
 static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op) {
   using llvmFMF = llvm::FastMathFlags;
   using FuncT = void (llvmFMF::*)(bool);
diff --git a/mlir/lib/Target/LLVMIR/Dialect/Ptr/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Dialect/Ptr/CMakeLists.txt
new file mode 100644
index 00000000000000..9997bce94b2784
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/Dialect/Ptr/CMakeLists.txt
@@ -0,0 +1,31 @@
+set(LLVM_OPTIONAL_SOURCES
+  LLVMIRToPtrTranslation.cpp
+  PtrToLLVMIRTranslation.cpp
+  )
+
+add_mlir_translation_library(MLIRLLVMIRToPtrTranslation
+  LLVMIRToPtrTranslation.cpp
+
+  LINK_COMPONENTS
+  Core
+
+  LINK_LIBS PUBLIC
+  MLIRIR
+  MLIRPtrDialect
+  MLIRLLVMDialect
+  MLIRSupport
+  MLIRTargetLLVMIRImport
+  )
+
+add_mlir_translation_library(MLIRPtrToLLVMIRTranslation
+  PtrToLLVMIRTranslation.cpp
+
+  LINK_COMPONENTS
+  Core
+
+  LINK_LIBS PUBLIC
+  MLIRIR
+  MLIRPtrDialect
+  MLIRSupport
+  MLIRTargetLLVMIRExport
+  )
\ No newline at end of file
diff --git a/mlir/lib/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.cpp
new file mode 100644
index 00000000000000..4fc939dd751241
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.cpp
@@ -0,0 +1,312 @@
+//===- LLVMIRToPtrTranslation.cpp - Translate LLVM IR to Ptr dialect ------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a translation between LLVM IR and the MLIR Ptr dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Target/LLVMIR/Dialect/Ptr/LLVMIRToPtrTranslation.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/Ptr/IR/PtrOps.h"
+#include "mlir/Support/LLVM.h"
+#include "mlir/Target/LLVMIR/ModuleImport.h"
+
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/ModRef.h"
+
+using namespace mlir;
+using namespace mlir::ptr;
+
+namespace {
+inline ArrayRef<unsigned> getSupportedInstructionsImpl() {
+  static unsigned instructions[] = {
+      llvm::Instruction::AtomicCmpXchg, llvm::Instruction::AtomicRMW,
+      llvm::Instruction::Load,          llvm::Instruction::Store,
+      llvm::Instruction::AddrSpaceCast, llvm::Instruction::IntToPtr,
+      llvm::Instruction::PtrToInt};
+  return instructions;
+}
+
+inline LLVM_ATTRIBUTE_UNUSED AtomicBinOp
+convertAtomicBinOpFromLLVM(::llvm::AtomicRMWInst::BinOp value) {
+  switch (value) {
+  case ::llvm::AtomicRMWInst::BinOp::Xchg:
+    return AtomicBinOp::xchg;
+  case ::llvm::AtomicRMWInst::BinOp::Add:
+    return AtomicBinOp::add;
+  case ::llvm::AtomicRMWInst::BinOp::Sub:
+    return AtomicBinOp::sub;
+  case ::llvm::AtomicRMWInst::BinOp::And:
+    return AtomicBinOp::_and;
+  case ::llvm::AtomicRMWInst::BinOp::Nand:
+    return AtomicBinOp::nand;
+  case ::llvm::AtomicRMWInst::BinOp::Or:
+    return AtomicBinOp::_or;
+  case ::llvm::AtomicRMWInst::BinOp::Xor:
+    return AtomicBinOp::_xor;
+  case ::llvm::AtomicRMWInst::BinOp::Max:
+    return AtomicBinOp::max;
+  case ::llvm::AtomicRMWInst::BinOp::Min:
+    return AtomicBinOp::min;
+  case ::llvm::AtomicRMWInst::BinOp::UMax:
+    return AtomicBinOp::umax;
+  case ::llvm::AtomicRMWInst::BinOp::UMin:
+    return AtomicBinOp::umin;
+  case ::llvm::AtomicRMWInst::BinOp::FAdd:
+    return AtomicBinOp::fadd;
+  case ::llvm::AtomicRMWInst::BinOp::FSub:
+    return AtomicBinOp::fsub;
+  case ::llvm::AtomicRMWInst::BinOp::FMax:
+    return AtomicBinOp::fmax;
+  case ::llvm::AtomicRMWInst::BinOp::FMin:
+    return AtomicBinOp::fmin;
+  case ::llvm::AtomicRMWInst::BinOp::UIncWrap:
+    return AtomicBinOp::uinc_wrap;
+  case ::llvm::AtomicRMWInst::BinOp::UDecWrap:
+    return AtomicBinOp::udec_wrap;
+  case ::llvm::AtomicRMWInst::BinOp::BAD_BINOP:
+    llvm_unreachable(
+        "unsupported case ::llvm::AtomicRMWInst::BinOp::BAD_BINOP");
+  }
+  llvm_unreachable("unknown ::llvm::AtomicRMWInst::BinOp type");
+}
+
+LLVM_ATTRIBUTE_UNUSED AtomicOrdering
+convertAtomicOrderingFromLLVM(::llvm::AtomicOrdering value) {
+  switch (value) {
+  case ::llvm::AtomicOrdering::NotAtomic:
+    return AtomicOrdering::not_atomic;
+  case ::llvm::AtomicOrdering::Unordered:
+    return AtomicOrdering::unordered;
+  case ::llvm::AtomicOrdering::Monotonic:
+    return AtomicOrdering::monotonic;
+  case ::llvm::AtomicOrdering::Acquire:
+    return AtomicOrdering::acquire;
+  case ::llvm::AtomicOrdering::Release:
+    return AtomicOrdering::release;
+  case ::llvm::AtomicOrdering::AcquireRelease:
+    return AtomicOrdering::acq_rel;
+  case ::llvm::AtomicOrdering::SequentiallyConsistent:
+    return AtomicOrdering::seq_cst;
+  }
+  llvm_unreachable("unknown ::llvm::AtomicOrdering type");
+}
+
+StringRef getLLVMSyncScope(llvm::Instruction *inst) {
+  std::optional<llvm::SyncScope::ID> syncScopeID =
+      llvm::getAtomicSyncScopeID(inst);
+  if (!syncScopeID)
+    return "";
+
+  // Search the sync scope name for the given identifier. The default
+  // system-level sync scope thereby maps to the empty string.
+  SmallVector<StringRef> syncScopeName;
+  llvm::LLVMContext &llvmContext = inst->getContext();
+  llvmContext.getSyncScopeNames(syncScopeName);
+  auto *it = llvm::find_if(syncScopeName, [&](StringRef name) {
+    return *syncScopeID == llvmContext.getOrInsertSyncScopeID(name);
+  });
+  if (it != syncScopeName.end())
+    return *it;
+  llvm_unreachable("incorrect sync scope identifier");
+}
+
+LogicalResult convertAtomicCmpXchg(OpBuilder &builder, llvm::Instruction *inst,
+                                   ArrayRef<llvm::Value *> llvmOperands,
+                                   LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> ptr = moduleImport.convertValue(llvmOperands[0]);
+  if (failed(ptr))
+    return failure();
+  FailureOr<Value> cmp = moduleImport.convertValue(llvmOperands[1]);
+  if (failed(cmp))
+    return failure();
+  FailureOr<Value> val = moduleImport.convertValue(llvmOperands[2]);
+  if (failed(val))
+    return failure();
+  auto *cmpXchgInst = cast<llvm::AtomicCmpXchgInst>(inst);
+  unsigned alignment = cmpXchgInst->getAlign().value();
+  // Create the AtomicCmpXchgOp
+  auto op = builder.create<AtomicCmpXchgOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()), *ptr, *cmp, *val,
+      convertAtomicOrderingFromLLVM(cmpXchgInst->getSuccessOrdering()),
+      convertAtomicOrderingFromLLVM(cmpXchgInst->getFailureOrdering()),
+      getLLVMSyncScope(cmpXchgInst), alignment, cmpXchgInst->isWeak(),
+      cmpXchgInst->isVolatile());
+  // Create a struct to hold the result of AtomicCmpXchgOp
+  auto structType = LLVM::LLVMStructType::getLiteral(
+      builder.getContext(), {op.getRes().getType(), op.getStatus().getType()},
+      false);
+  Value res = builder.create<LLVM::UndefOp>(op.getLoc(), structType);
+  res = builder.create<LLVM::InsertValueOp>(res.getLoc(), res, op.getRes(),
+                                            llvm::ArrayRef<int64_t>{0});
+  res = builder.create<LLVM::InsertValueOp>(res.getLoc(), res, op.getStatus(),
+                                            llvm::ArrayRef<int64_t>{1});
+  moduleImport.mapOp(inst) = {res, op};
+  return success();
+}
+
+LogicalResult convertAtomicRMW(OpBuilder &builder, llvm::Instruction *inst,
+                               ArrayRef<llvm::Value *> llvmOperands,
+                               LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> ptr = moduleImport.convertValue(llvmOperands[0]);
+  if (failed(ptr))
+    return failure();
+  FailureOr<Value> val = moduleImport.convertValue(llvmOperands[1]);
+  if (failed(val))
+    return failure();
+  auto *atomicInst = cast<llvm::AtomicRMWInst>(inst);
+  unsigned alignment = atomicInst->getAlign().value();
+  // Create the AtomicRMWOp
+  moduleImport.mapValue(inst) = builder.create<AtomicRMWOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()),
+      convertAtomicBinOpFromLLVM(atomicInst->getOperation()), *ptr, *val,
+      convertAtomicOrderingFromLLVM(atomicInst->getOrdering()),
+      getLLVMSyncScope(atomicInst), alignment, atomicInst->isVolatile());
+  return success();
+}
+
+LogicalResult convertLoad(OpBuilder &builder, llvm::Instruction *inst,
+                          ArrayRef<llvm::Value *> llvmOperands,
+                          LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> addr = moduleImport.convertValue(llvmOperands[0]);
+  if (failed(addr))
+    return failure();
+  auto *loadInst = cast<llvm::LoadInst>(inst);
+  unsigned alignment = loadInst->getAlign().value();
+  // Create the LoadOp
+  moduleImport.mapValue(inst) = builder.create<LoadOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()),
+      moduleImport.convertType(inst->getType()), *addr, alignment,
+      loadInst->isVolatile(),
+      loadInst->hasMetadata(llvm::LLVMContext::MD_nontemporal),
+      loadInst->hasMetadata(llvm::LLVMContext::MD_invariant_load),
+      convertAtomicOrderingFromLLVM(loadInst->getOrdering()),
+      getLLVMSyncScope(loadInst));
+
+  return success();
+}
+
+LogicalResult convertStore(OpBuilder &builder, llvm::Instruction *inst,
+                           ArrayRef<llvm::Value *> llvmOperands,
+                           LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> value = moduleImport.convertValue(llvmOperands[0]);
+  if (failed(value))
+    return failure();
+  FailureOr<Value> addr = moduleImport.convertValue(llvmOperands[1]);
+  if (failed(addr))
+    return failure();
+  auto *storeInst = cast<llvm::StoreInst>(inst);
+  unsigned alignment = storeInst->getAlign().value();
+  // Create the StoreOp
+  moduleImport.mapNoResultOp(inst) = builder.create<StoreOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()), *value, *addr, alignment,
+      storeInst->isVolatile(),
+      storeInst->hasMetadata(llvm::LLVMContext::MD_nontemporal),
+      convertAtomicOrderingFromLLVM(storeInst->getOrdering()),
+      getLLVMSyncScope(storeInst));
+  return success();
+}
+
+LogicalResult convertAddrSpaceCast(OpBuilder &builder, llvm::Instruction *inst,
+                                   ArrayRef<llvm::Value *> llvmOperands,
+                                   LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> _llvmir_gen_operand_arg =
+      moduleImport.convertValue(llvmOperands[0]);
+  if (failed(_llvmir_gen_operand_arg))
+    return failure();
+  // Create the AddrSpaceCastOp
+  moduleImport.mapValue(inst) = builder.create<AddrSpaceCastOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()),
+      moduleImport.convertType(inst->getType()), *_llvmir_gen_operand_arg);
+  return success();
+}
+
+LogicalResult convertIntToPtr(OpBuilder &builder, llvm::Instruction *inst,
+                              ArrayRef<llvm::Value *> llvmOperands,
+                              LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> _llvmir_gen_operand_arg =
+      moduleImport.convertValue(llvmOperands[0]);
+  if (failed(_llvmir_gen_operand_arg))
+    return failure();
+  // Create the IntToPtrOp
+  moduleImport.mapValue(inst) = builder.create<IntToPtrOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()),
+      moduleImport.convertType(inst->getType()), *_llvmir_gen_operand_arg);
+
+  return success();
+}
+
+LogicalResult convertPtrToInt(OpBuilder &builder, llvm::Instruction *inst,
+                              ArrayRef<llvm::Value *> llvmOperands,
+                              LLVM::ModuleImport &moduleImport) {
+  FailureOr<Value> _llvmir_gen_operand_arg =
+      moduleImport.convertValue(llvmOperands[0]);
+  if (failed(_llvmir_gen_operand_arg))
+    return failure();
+  // Create the PtrToIntOp
+  moduleImport.mapValue(inst) = builder.create<PtrToIntOp>(
+      moduleImport.translateLoc(inst->getDebugLoc()),
+      moduleImport.convertType(inst->getType()), *_llvmir_gen_operand_arg);
+
+  return success();
+}
+
+class PtrDialectLLVMIRImportInterface : public LLVMImportDialectInterface {
+public:
+  using LLVMImportDialectInterface::LLVMImportDialectInterface;
+
+  LogicalResult
+  convertInstruction(OpBuilder &builder, llvm::Instruction *inst,
+                     ArrayRef<llvm::Value *> llvmOperands,
+                     LLVM::ModuleImport &moduleImport) const override {
+    switch (inst->getOpcode()) {
+    case llvm::Instruction::AtomicCmpXchg:
+      return convertAtomicCmpXchg(builder, inst, llvmOperands, moduleImport);
+    case llvm::Instruction::AtomicRMW:
+      return convertAtomicRMW(builder, inst, llvmOperands, moduleImport);
+    case llvm::Instruction::Load:
+      return convertLoad(builder, inst, llvmOperands, moduleImport);
+    case llvm::Instruction::Store:
+      return convertStore(builder, inst, llvmOperands, moduleImport);
+    case llvm::Instruction::AddrSpaceCast:
+      return convertAddrSpaceCast(builder, inst, llvmOperands, moduleImport);
+    case llvm::Instruction::IntToPtr:
+      return convertIntToPtr(builder, inst, llvmOperands, moduleImport);
+    case llvm::Instruction::PtrToInt:
+      return convertPtrToInt(builder, inst, llvmOperands, moduleImport);
+    default:
+      break;
+    }
+    return failure();
+  }
+
+  ArrayRef<unsigned> getSupportedInstructions() const override {
+    return getSupportedInstructionsImpl();
+  }
+};
+} // namespace
+
+void mlir::registerPtrDialectImport(DialectRegistry &registry) {
+  registry.insert<ptr::PtrDialect>();
+  registry.addExtension(+[](MLIRContext *ctx, ptr::PtrDialect *dialect) {
+    dialect->addInterfaces<PtrDialectLLVMIRImportInterface>();
+  });
+}
+
+void mlir::registerPtrDialectImport(MLIRContext &context) {
+  DialectRegistry registry;
+  registerPtrDialectImport(registry);
+  context.appendDialectRegistry(registry);
+}
diff --git a/mlir/lib/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.cpp
new file mode 100644
index 00000000000000..a25ccc41b8a190
--- /dev/null
+++ b/mlir/lib/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.cpp
@@ -0,0 +1,379 @@
+//===- PtrToLLVMIRTranslation.cpp - Translate Ptr dialect to LLVM IR ------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a translation between the MLIR Ptr dialect and LLVM IR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h"
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
+#include "mlir/Dialect/Ptr/IR/PtrOps.h"
+#include "mlir/Target/LLVMIR/LLVMTranslationInterface.h"
+#include "mlir/Target/LLVMIR/ModuleTranslation.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/MDBuilder.h"
+
+using namespace mlir;
+using namespace mlir::ptr;
+
+namespace {
+::llvm::AtomicRMWInst::BinOp convertAtomicBinOpToLLVM(AtomicBinOp value) {
+  switch (value) {
+  case AtomicBinOp::xchg:
+    return ::llvm::AtomicRMWInst::BinOp::Xchg;
+  case AtomicBinOp::add:
+    return ::llvm::AtomicRMWInst::BinOp::Add;
+  case AtomicBinOp::sub:
+    return ::llvm::AtomicRMWInst::BinOp::Sub;
+  case AtomicBinOp::_and:
+    return ::llvm::AtomicRMWInst::BinOp::And;
+  case AtomicBinOp::nand:
+    return ::llvm::AtomicRMWInst::BinOp::Nand;
+  case AtomicBinOp::_or:
+    return ::llvm::AtomicRMWInst::BinOp::Or;
+  case AtomicBinOp::_xor:
+    return ::llvm::AtomicRMWInst::BinOp::Xor;
+  case AtomicBinOp::max:
+    return ::llvm::AtomicRMWInst::BinOp::Max;
+  case AtomicBinOp::min:
+    return ::llvm::AtomicRMWInst::BinOp::Min;
+  case AtomicBinOp::umax:
+    return ::llvm::AtomicRMWInst::BinOp::UMax;
+  case AtomicBinOp::umin:
+    return ::llvm::AtomicRMWInst::BinOp::UMin;
+  case AtomicBinOp::fadd:
+    return ::llvm::AtomicRMWInst::BinOp::FAdd;
+  case AtomicBinOp::fsub:
+    return ::llvm::AtomicRMWInst::BinOp::FSub;
+  case AtomicBinOp::fmax:
+    return ::llvm::AtomicRMWInst::BinOp::FMax;
+  case AtomicBinOp::fmin:
+    return ::llvm::AtomicRMWInst::BinOp::FMin;
+  case AtomicBinOp::uinc_wrap:
+    return ::llvm::AtomicRMWInst::BinOp::UIncWrap;
+  case AtomicBinOp::udec_wrap:
+    return ::llvm::AtomicRMWInst::BinOp::UDecWrap;
+  }
+  llvm_unreachable("unknown AtomicBinOp type");
+}
+
+::llvm::AtomicOrdering convertAtomicOrderingToLLVM(AtomicOrdering value) {
+  switch (value) {
+  case AtomicOrdering::not_atomic:
+    return ::llvm::AtomicOrdering::NotAtomic;
+  case AtomicOrdering::unordered:
+    return ::llvm::AtomicOrdering::Unordered;
+  case AtomicOrdering::monotonic:
+    return ::llvm::AtomicOrdering::Monotonic;
+  case AtomicOrdering::acquire:
+    return ::llvm::AtomicOrdering::Acquire;
+  case AtomicOrdering::release:
+    return ::llvm::AtomicOrdering::Release;
+  case AtomicOrdering::acq_rel:
+    return ::llvm::AtomicOrdering::AcquireRelease;
+  case AtomicOrdering::seq_cst:
+    return ::llvm::AtomicOrdering::SequentiallyConsistent;
+  }
+  llvm_unreachable("unknown AtomicOrdering type");
+}
+
+//===----------------------------------------------------------------------===//
+// AtomicRMWOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertAtomicRMWOp(AtomicRMWOp op, llvm::IRBuilderBase &builder,
+                                 LLVM::ModuleTranslation &moduleTranslation) {
+  auto *inst = builder.CreateAtomicRMW(
+      convertAtomicBinOpToLLVM(op.getBinOp()),
+      moduleTranslation.lookupValue(op.getPtr()),
+      moduleTranslation.lookupValue(op.getVal()), llvm::MaybeAlign(),
+      convertAtomicOrderingToLLVM(op.getOrdering()));
+  moduleTranslation.mapValue(op.getRes()) = inst;
+  // Set volatile flag.
+  inst->setVolatile(op.getVolatile_());
+  // Set sync scope.
+  if (op.getSyncscope().has_value()) {
+    llvm::LLVMContext &llvmContext = builder.getContext();
+    inst->setSyncScopeID(
+        llvmContext.getOrInsertSyncScopeID(*op.getSyncscope()));
+  }
+  // Set alignment.
+  if (op.getAlignment().has_value()) {
+    auto align = *op.getAlignment();
+    if (align != 0)
+      inst->setAlignment(llvm::Align(align));
+  }
+  // Set access group.
+  if (auto accessGroup =
+          dyn_cast<LLVM::AccessGroupOpInterface>(op.getOperation()))
+    moduleTranslation.setAccessGroupsMetadata(accessGroup, inst);
+  // Set alias analysis.
+  if (auto aa = dyn_cast<LLVM::AliasAnalysisOpInterface>(op.getOperation())) {
+    moduleTranslation.setAliasScopeMetadata(aa, inst);
+    moduleTranslation.setTBAAMetadata(aa, inst);
+  }
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AtomicCmpXchgOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+convertAtomicCmpXchgOp(AtomicCmpXchgOp op, llvm::IRBuilderBase &builder,
+                       LLVM::ModuleTranslation &moduleTranslation) {
+  auto *inst = builder.CreateAtomicCmpXchg(
+      moduleTranslation.lookupValue(op.getPtr()),
+      moduleTranslation.lookupValue(op.getCmp()),
+      moduleTranslation.lookupValue(op.getVal()), llvm::MaybeAlign(),
+      convertAtomicOrderingToLLVM(op.getSuccessOrdering()),
+      convertAtomicOrderingToLLVM(op.getFailureOrdering()));
+  moduleTranslation.mapValue(op.getRes()) =
+      builder.CreateExtractValue(inst, {0});
+  moduleTranslation.mapValue(op.getStatus()) =
+      builder.CreateExtractValue(inst, {1});
+  inst->setWeak(op.getWeak());
+  // Set volatile flag.
+  inst->setVolatile(op.getVolatile_());
+  // Set sync scope.
+  if (op.getSyncscope().has_value()) {
+    llvm::LLVMContext &llvmContext = builder.getContext();
+    inst->setSyncScopeID(
+        llvmContext.getOrInsertSyncScopeID(*op.getSyncscope()));
+  }
+  // Set alignment.
+  if (op.getAlignment().has_value()) {
+    auto align = *op.getAlignment();
+    if (align != 0)
+      inst->setAlignment(llvm::Align(align));
+  }
+  // Set access group.
+  if (auto accessGroup =
+          dyn_cast<LLVM::AccessGroupOpInterface>(op.getOperation()))
+    moduleTranslation.setAccessGroupsMetadata(accessGroup, inst);
+  // Set alias analysis.
+  if (auto aa = dyn_cast<LLVM::AliasAnalysisOpInterface>(op.getOperation())) {
+    moduleTranslation.setAliasScopeMetadata(aa, inst);
+    moduleTranslation.setTBAAMetadata(aa, inst);
+  }
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// LoadOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertLoadOp(LoadOp op, llvm::IRBuilderBase &builder,
+                            LLVM::ModuleTranslation &moduleTranslation) {
+  auto *inst = builder.CreateLoad(
+      moduleTranslation.convertType(op.getResult().getType()),
+      moduleTranslation.lookupValue(op.getAddr()), op.getVolatile_());
+  moduleTranslation.mapValue(op.getRes()) = inst;
+  if (op.getInvariant()) {
+    llvm::MDNode *metadata =
+        llvm::MDNode::get(inst->getContext(), std::nullopt);
+    inst->setMetadata(llvm::LLVMContext::MD_invariant_load, metadata);
+  }
+  // Set atomic ordering.
+  inst->setAtomic(convertAtomicOrderingToLLVM(op.getOrdering()));
+  // Set sync scope.
+  if (op.getSyncscope().has_value()) {
+    llvm::LLVMContext &llvmContext = builder.getContext();
+    inst->setSyncScopeID(
+        llvmContext.getOrInsertSyncScopeID(*op.getSyncscope()));
+  }
+  // Set alignment.
+  if (op.getAlignment().has_value()) {
+    auto align = *op.getAlignment();
+    if (align != 0)
+      inst->setAlignment(llvm::Align(align));
+  }
+  // Set non-temporal.
+  if (op.getNontemporal()) {
+    llvm::MDNode *metadata = llvm::MDNode::get(
+        inst->getContext(), llvm::ConstantAsMetadata::get(builder.getInt32(1)));
+    inst->setMetadata(llvm::LLVMContext::MD_nontemporal, metadata);
+  }
+  // Set access group.
+  if (auto accessGroup =
+          dyn_cast<LLVM::AccessGroupOpInterface>(op.getOperation()))
+    moduleTranslation.setAccessGroupsMetadata(accessGroup, inst);
+  // Set alias analysis.
+  if (auto aa = dyn_cast<LLVM::AliasAnalysisOpInterface>(op.getOperation())) {
+    moduleTranslation.setAliasScopeMetadata(aa, inst);
+    moduleTranslation.setTBAAMetadata(aa, inst);
+  }
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// StoreOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertStoreOp(StoreOp op, llvm::IRBuilderBase &builder,
+                             LLVM::ModuleTranslation &moduleTranslation) {
+  auto *inst = builder.CreateStore(moduleTranslation.lookupValue(op.getValue()),
+                                   moduleTranslation.lookupValue(op.getAddr()),
+                                   op.getVolatile_());
+
+  // Set atomic ordering.
+  inst->setAtomic(convertAtomicOrderingToLLVM(op.getOrdering()));
+  // Set sync scope.
+  if (op.getSyncscope().has_value()) {
+    llvm::LLVMContext &llvmContext = builder.getContext();
+    inst->setSyncScopeID(
+        llvmContext.getOrInsertSyncScopeID(*op.getSyncscope()));
+  }
+  // Set alignment.
+  if (op.getAlignment().has_value()) {
+    auto align = *op.getAlignment();
+    if (align != 0)
+      inst->setAlignment(llvm::Align(align));
+  }
+  // Set non-temporal.
+  if (op.getNontemporal()) {
+    llvm::MDNode *metadata = llvm::MDNode::get(
+        inst->getContext(), llvm::ConstantAsMetadata::get(builder.getInt32(1)));
+    inst->setMetadata(llvm::LLVMContext::MD_nontemporal, metadata);
+  }
+  // Set access group.
+  if (auto accessGroup =
+          dyn_cast<LLVM::AccessGroupOpInterface>(op.getOperation()))
+    moduleTranslation.setAccessGroupsMetadata(accessGroup, inst);
+  // Set alias analysis.
+  if (auto aa = dyn_cast<LLVM::AliasAnalysisOpInterface>(op.getOperation())) {
+    moduleTranslation.setAliasScopeMetadata(aa, inst);
+    moduleTranslation.setTBAAMetadata(aa, inst);
+  }
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AddrSpaceCastOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+convertAddrSpaceCastOp(AddrSpaceCastOp op, llvm::IRBuilderBase &builder,
+                       LLVM::ModuleTranslation &moduleTranslation) {
+  moduleTranslation.mapValue(op.getRes()) = builder.CreateAddrSpaceCast(
+      moduleTranslation.lookupValue(op.getArg()),
+      moduleTranslation.convertType(op.getResult().getType()));
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AddrSpaceCastOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertIntToPtrOp(IntToPtrOp op, llvm::IRBuilderBase &builder,
+                                LLVM::ModuleTranslation &moduleTranslation) {
+  moduleTranslation.mapValue(op.getRes()) = builder.CreateIntToPtr(
+      moduleTranslation.lookupValue(op.getArg()),
+      moduleTranslation.convertType(op.getResult().getType()));
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AddrSpaceCastOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertPtrToIntOp(PtrToIntOp op, llvm::IRBuilderBase &builder,
+                                LLVM::ModuleTranslation &moduleTranslation) {
+  moduleTranslation.mapValue(op.getRes()) = builder.CreatePtrToInt(
+      moduleTranslation.lookupValue(op.getArg()),
+      moduleTranslation.convertType(op.getResult().getType()));
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// ConstantOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertConstantOp(ConstantOp op, llvm::IRBuilderBase &builder,
+                                LLVM::ModuleTranslation &moduleTranslation) {
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// TypeOffsetOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertTypeOffsetOp(TypeOffsetOp op, llvm::IRBuilderBase &builder,
+                                  LLVM::ModuleTranslation &moduleTranslation) {
+  return success();
+}
+
+//===----------------------------------------------------------------------===//
+// PtrAddOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult convertPtrAddOp(PtrAddOp op, llvm::IRBuilderBase &builder,
+                              LLVM::ModuleTranslation &moduleTranslation) {
+  return success();
+}
+
+class PtrDialectLLVMIRTranslationInterface
+    : public LLVMTranslationDialectInterface {
+public:
+  using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
+
+  LogicalResult
+  convertOperation(Operation *operation, llvm::IRBuilderBase &builder,
+                   LLVM::ModuleTranslation &moduleTranslation) const override {
+    return llvm::TypeSwitch<Operation *, LogicalResult>(operation)
+        .Case([&](ptr::AtomicRMWOp op) {
+          return convertAtomicRMWOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::AtomicCmpXchgOp op) {
+          return convertAtomicCmpXchgOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::LoadOp op) {
+          return convertLoadOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::StoreOp op) {
+          return convertStoreOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::AddrSpaceCastOp op) {
+          return convertAddrSpaceCastOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::IntToPtrOp op) {
+          return convertIntToPtrOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::PtrToIntOp op) {
+          return convertPtrToIntOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::ConstantOp op) {
+          return convertConstantOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::TypeOffsetOp op) {
+          return convertTypeOffsetOp(op, builder, moduleTranslation);
+        })
+        .Case([&](ptr::PtrAddOp op) {
+          return convertPtrAddOp(op, builder, moduleTranslation);
+        })
+        .Default([&](Operation *op) {
+          return op->emitError("unsupported Ptr operation: ") << op->getName();
+        });
+  }
+};
+} // namespace
+
+void mlir::registerPtrDialectTranslation(DialectRegistry &registry) {
+  registry.insert<ptr::PtrDialect>();
+  registry.addExtension(+[](MLIRContext *ctx, ptr::PtrDialect *dialect) {
+    dialect->addInterfaces<PtrDialectLLVMIRTranslationInterface>();
+  });
+}
+
+void mlir::registerPtrDialectTranslation(MLIRContext &context) {
+  DialectRegistry registry;
+  registerPtrDialectTranslation(registry);
+  context.appendDialectRegistry(registry);
+}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 6e70d52fa760b6..a95539eb8d4c9b 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -47,6 +47,27 @@ using namespace mlir::LLVM::detail;
 
 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsFromLLVM.inc"
 
+LLVM_ATTRIBUTE_UNUSED static ptr::AtomicOrdering
+convertAtomicOrderingFromLLVM(::llvm::AtomicOrdering value) {
+  switch (value) {
+  case ::llvm::AtomicOrdering::NotAtomic:
+    return AtomicOrdering::not_atomic;
+  case ::llvm::AtomicOrdering::Unordered:
+    return AtomicOrdering::unordered;
+  case ::llvm::AtomicOrdering::Monotonic:
+    return AtomicOrdering::monotonic;
+  case ::llvm::AtomicOrdering::Acquire:
+    return AtomicOrdering::acquire;
+  case ::llvm::AtomicOrdering::Release:
+    return AtomicOrdering::release;
+  case ::llvm::AtomicOrdering::AcquireRelease:
+    return AtomicOrdering::acq_rel;
+  case ::llvm::AtomicOrdering::SequentiallyConsistent:
+    return AtomicOrdering::seq_cst;
+  }
+  llvm_unreachable("unknown ::llvm::AtomicOrdering type");
+}
+
 // Utility to print an LLVM value as a string for passing to emitError().
 // FIXME: Diagnostic should be able to natively handle types that have
 // operator << (raw_ostream&) defined.
@@ -123,13 +144,17 @@ static SmallVector<int64_t> getPositionFromIndices(ArrayRef<unsigned> indices) {
 /// access to the private module import methods.
 static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,
                                             llvm::Instruction *inst,
-                                            ModuleImport &moduleImport) {
+                                            ModuleImport &moduleImport,
+                                            LLVMImportInterface &importIface) {
   // Copy the operands to an LLVM operands array reference for conversion.
   SmallVector<llvm::Value *> operands(inst->operands());
   ArrayRef<llvm::Value *> llvmOperands(operands);
 
   // Convert all instructions that provide an MLIR builder.
 #include "mlir/Dialect/LLVMIR/LLVMOpFromLLVMIRConversions.inc"
+  if (importIface.isConvertibleInstruction(inst->getOpcode()))
+    return importIface.convertInstruction(odsBuilder, inst, llvmOperands,
+                                          moduleImport);
   return failure();
 }
 
@@ -1177,7 +1202,7 @@ FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {
   // Return the mapped value if it has been converted before.
   auto it = valueMapping.find(value);
   if (it != valueMapping.end())
-    return it->getSecond();
+    return it->getSecond().first;
 
   // Convert constants such as immediate values that have no mapping yet.
   if (auto *constant = dyn_cast<llvm::Constant>(value))
@@ -1203,7 +1228,7 @@ FailureOr<Value> ModuleImport::convertMetadataValue(llvm::Value *value) {
   // Return the mapped value if it has been converted before.
   auto it = valueMapping.find(value);
   if (it != valueMapping.end())
-    return it->getSecond();
+    return it->getSecond().first;
 
   // Convert constants such as immediate values that have no mapping yet.
   if (auto *constant = dyn_cast<llvm::Constant>(value))
@@ -1596,7 +1621,7 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
   }
 
   // Convert all instructions that have an mlirBuilder.
-  if (succeeded(convertInstructionImpl(builder, inst, *this)))
+  if (succeeded(convertInstructionImpl(builder, inst, *this, iface)))
     return success();
 
   return emitError(loc) << "unhandled instruction: " << diag(*inst);
@@ -2061,7 +2086,7 @@ LogicalResult ModuleImport::processBasicBlock(llvm::BasicBlock *bb,
     // Set the non-debug metadata attributes on the imported operation and emit
     // a warning if an instruction other than a phi instruction is dropped
     // during the import.
-    if (Operation *op = lookupOperation(&inst)) {
+    if (Operation *op = lookupOperation(&inst, true)) {
       setNonDebugMetadataAttrs(&inst, op);
     } else if (inst.getOpcode() != llvm::Instruction::PHI) {
       if (emitExpensiveWarnings) {
diff --git a/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp b/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
index 6d8b415ff09dce..c040ff2f0369a2 100644
--- a/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
+++ b/mlir/lib/Target/LLVMIR/TypeToLLVM.cpp
@@ -8,6 +8,7 @@
 
 #include "mlir/Target/LLVMIR/TypeToLLVM.h"
 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/Ptr/IR/PtrTypes.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/MLIRContext.h"
 
@@ -71,7 +72,7 @@ class TypeToLLVMIRTranslatorImpl {
               return llvm::Type::getMetadataTy(context);
             })
             .Case<LLVM::LLVMArrayType, IntegerType, LLVM::LLVMFunctionType,
-                  LLVM::LLVMPointerType, LLVM::LLVMStructType,
+                  LLVM::LLVMPointerType, ptr::PtrType, LLVM::LLVMStructType,
                   LLVM::LLVMFixedVectorType, LLVM::LLVMScalableVectorType,
                   VectorType, LLVM::LLVMTargetExtType>(
                 [this](auto type) { return this->translate(type); })
@@ -109,6 +110,11 @@ class TypeToLLVMIRTranslatorImpl {
     return llvm::PointerType::get(context, type.getAddressSpace());
   }
 
+  /// Translates the given pointer type.
+  llvm::Type *translate(ptr::PtrType type) {
+    return llvm::PointerType::get(context, type.getAddressSpace());
+  }
+
   /// Translates the given structure type, supports both identified and literal
   /// structs. This will _create_ a new identified structure every time, use
   /// `convertType` if a structure with the same name must be looked up instead.
diff --git a/mlir/lib/Transforms/Mem2Reg.cpp b/mlir/lib/Transforms/Mem2Reg.cpp
index 80e3b790163297..3aca5eb19ff5af 100644
--- a/mlir/lib/Transforms/Mem2Reg.cpp
+++ b/mlir/lib/Transforms/Mem2Reg.cpp
@@ -202,6 +202,7 @@ class MemorySlotPromoter {
   /// Contains the reaching definition at this operation. Reaching definitions
   /// are only computed for promotable memory operations with blocking uses.
   DenseMap<PromotableMemOpInterface, Value> reachingDefs;
+  DenseMap<PromotableMemOpInterface, Value> mutatedValues;
   DominanceInfo &dominance;
   MemorySlotPromotionInfo info;
   const Mem2RegStatistics &statistics;
@@ -438,6 +439,7 @@ Value MemorySlotPromoter::computeReachingDefInBlock(Block *block,
         assert(stored && "a memory operation storing to a slot must provide a "
                          "new definition of the slot");
         reachingDef = stored;
+        mutatedValues[memOp] = stored;
       }
     }
   }
@@ -552,6 +554,8 @@ void MemorySlotPromoter::removeBlockingUses() {
   dominanceSort(usersToRemoveUses, *slot.ptr.getParentBlock()->getParent());
 
   llvm::SmallVector<Operation *> toErase;
+  llvm::SmallVector<std::pair<Operation *, Value>> mutatedDefinitions;
+  llvm::SmallVector<PromotableOpInterface> visitMutatedDefinitions;
   for (Operation *toPromote : llvm::reverse(usersToRemoveUses)) {
     if (auto toPromoteMemOp = dyn_cast<PromotableMemOpInterface>(toPromote)) {
       Value reachingDef = reachingDefs.lookup(toPromoteMemOp);
@@ -565,7 +569,9 @@ void MemorySlotPromoter::removeBlockingUses() {
               slot, info.userToBlockingUses[toPromote], rewriter,
               reachingDef) == DeletionKind::Delete)
         toErase.push_back(toPromote);
-
+      if (toPromoteMemOp.storesTo(slot))
+        if (Value mutatedValue = mutatedValues[toPromoteMemOp])
+          mutatedDefinitions.push_back({toPromoteMemOp, mutatedValue});
       continue;
     }
 
@@ -574,6 +580,12 @@ void MemorySlotPromoter::removeBlockingUses() {
     if (toPromoteBasic.removeBlockingUses(info.userToBlockingUses[toPromote],
                                           rewriter) == DeletionKind::Delete)
       toErase.push_back(toPromote);
+    if (toPromoteBasic.requiresVisitingMutatedDefs())
+      visitMutatedDefinitions.push_back(toPromoteBasic);
+  }
+  for (PromotableOpInterface op : visitMutatedDefinitions) {
+    rewriter.setInsertionPointAfter(op);
+    op.visitMutatedDefs(mutatedDefinitions, rewriter);
   }
 
   for (Operation *toEraseOp : toErase)
diff --git a/mlir/test/Conversion/AMDGPUToROCDL/amdgpu-to-rocdl.mlir b/mlir/test/Conversion/AMDGPUToROCDL/amdgpu-to-rocdl.mlir
index bb1cedaa276b33..a8e6abc7addb22 100644
--- a/mlir/test/Conversion/AMDGPUToROCDL/amdgpu-to-rocdl.mlir
+++ b/mlir/test/Conversion/AMDGPUToROCDL/amdgpu-to-rocdl.mlir
@@ -9,7 +9,7 @@ func.func @gpu_gcn_raw_buffer_load_scalar_i32(%buf: memref<i32>) -> i32 {
   // CHECK: %[[numRecords:.*]] = llvm.mlir.constant(4 : i32)
   // GFX9:  %[[flags:.*]] = llvm.mlir.constant(159744 : i32)
   // RDNA:  %[[flags:.*]] = llvm.mlir.constant(822243328 : i32)
-  // CHECK: %[[resource:.*]] = rocdl.make.buffer.rsrc %{{.*}}, %[[stride]], %[[numRecords]], %[[flags]] : !llvm.ptr to <8>
+  // CHECK: %[[resource:.*]] = rocdl.make.buffer.rsrc %{{.*}}, %[[stride]], %[[numRecords]], %[[flags]] : !llvm.ptr to !llvm.ptr<8>
   // CHECK: %[[ret:.*]] = rocdl.raw.ptr.buffer.load %[[resource]], %{{.*}}, %{{.*}}, %{{.*}} : i32
   // CHECK: return %[[ret]]
   %0 = amdgpu.raw_buffer_load {boundsCheck = true} %buf[] : memref<i32> -> i32
@@ -22,7 +22,7 @@ func.func @gpu_gcn_raw_buffer_load_i32(%buf: memref<64xi32>, %idx: i32) -> i32 {
   // CHECK: %[[numRecords:.*]] = llvm.mlir.constant(256 : i32)
   // GFX9:  %[[flags:.*]] = llvm.mlir.constant(159744 : i32)
   // RDNA:  %[[flags:.*]] = llvm.mlir.constant(822243328 : i32)
-  // CHECK: %[[resource:.*]] = rocdl.make.buffer.rsrc %{{.*}}, %[[stride]], %[[numRecords]], %[[flags]] : !llvm.ptr to <8>
+  // CHECK: %[[resource:.*]] = rocdl.make.buffer.rsrc %{{.*}}, %[[stride]], %[[numRecords]], %[[flags]] : !llvm.ptr to !llvm.ptr<8>
   // CHECK: %[[ret:.*]] = rocdl.raw.ptr.buffer.load %[[resource]], %{{.*}}, %{{.*}}, %{{.*}} : i32
   // CHECK: return %[[ret]]
   %0 = amdgpu.raw_buffer_load {boundsCheck = true} %buf[%idx] : memref<64xi32>, i32 -> i32
diff --git a/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm.mlir b/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm.mlir
index 4077edc7420dca..3544226187fa26 100644
--- a/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm.mlir
+++ b/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm.mlir
@@ -11,7 +11,7 @@ func.func @create_token() {
 func.func @create_value() {
   // CHECK: %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
   // CHECK: %[[OFFSET:.*]] = llvm.getelementptr %[[NULL]][1]
-  // CHECK: %[[SIZE:.*]] = llvm.ptrtoint %[[OFFSET]]
+  // CHECK: %[[SIZE:.*]] = ptr.ptrtoint %[[OFFSET]]
   // CHECK: %[[VALUE:.*]] = call @mlirAsyncRuntimeCreateValue(%[[SIZE]])
   %0 = async.runtime.create : !async.value<f32>
   return
@@ -152,7 +152,7 @@ func.func @store() {
   // CHECK: %[[VALUE:.*]] = call @mlirAsyncRuntimeCreateValue
   %1 = async.runtime.create : !async.value<f32>
   // CHECK: %[[P0:.*]] = call @mlirAsyncRuntimeGetValueStorage(%[[VALUE]])
-  // CHECK: llvm.store %[[CST]], %[[P0]] : f32, !llvm.ptr
+  // CHECK: ptr.store %[[CST]], %[[P0]] : f32, !llvm.ptr
   async.runtime.store %0, %1 : !async.value<f32>
   return
 }
@@ -162,7 +162,7 @@ func.func @load() -> f32 {
   // CHECK: %[[VALUE:.*]] = call @mlirAsyncRuntimeCreateValue
   %0 = async.runtime.create : !async.value<f32>
   // CHECK: %[[P0:.*]] = call @mlirAsyncRuntimeGetValueStorage(%[[VALUE]])
-  // CHECK: %[[VALUE:.*]] = llvm.load %[[P0]] : !llvm.ptr -> f32
+  // CHECK: %[[VALUE:.*]] = ptr.load %[[P0]] : !llvm.ptr -> f32
   %1 = async.runtime.load %0 : !async.value<f32>
   // CHECK: return %[[VALUE]] : f32
   return %1 : f32
diff --git a/mlir/test/Conversion/AsyncToLLVM/convert-to-llvm.mlir b/mlir/test/Conversion/AsyncToLLVM/convert-to-llvm.mlir
index dd54bdb7987244..25a545827ef626 100644
--- a/mlir/test/Conversion/AsyncToLLVM/convert-to-llvm.mlir
+++ b/mlir/test/Conversion/AsyncToLLVM/convert-to-llvm.mlir
@@ -227,7 +227,7 @@ func.func @execute_and_return_f32() -> f32 {
   }
 
   // CHECK: %[[STORAGE:.*]] = call @mlirAsyncRuntimeGetValueStorage(%[[RET]]#1)
-  // CHECK: %[[LOADED:.*]] = llvm.load %[[STORAGE]] : !llvm.ptr -> f32
+  // CHECK: %[[LOADED:.*]] = ptr.load %[[STORAGE]] : !llvm.ptr -> f32
   %0 = async.await %result : !async.value<f32>
 
   return %0 : f32
@@ -246,7 +246,7 @@ func.func @execute_and_return_f32() -> f32 {
 // Emplace result value.
 // CHECK: %[[CST:.*]] = arith.constant 1.230000e+02 : f32
 // CHECK: %[[STORAGE:.*]] = call @mlirAsyncRuntimeGetValueStorage(%[[VALUE]])
-// CHECK: llvm.store %[[CST]], %[[STORAGE]] : f32, !llvm.ptr
+// CHECK: ptr.store %[[CST]], %[[STORAGE]] : f32, !llvm.ptr
 // CHECK: call @mlirAsyncRuntimeEmplaceValue(%[[VALUE]])
 
 // Emplace result token.
@@ -293,7 +293,7 @@ func.func @async_value_operands() {
 
 // Get the operand value storage, cast to f32 and add the value.
 // CHECK: %[[STORAGE:.*]] = call @mlirAsyncRuntimeGetValueStorage(%arg0)
-// CHECK: %[[LOADED:.*]] = llvm.load %[[STORAGE]] : !llvm.ptr -> f32
+// CHECK: %[[LOADED:.*]] = ptr.load %[[STORAGE]] : !llvm.ptr -> f32
 // CHECK: arith.addf %[[LOADED]], %[[LOADED]] : f32
 
 // Emplace result token.
diff --git a/mlir/test/Conversion/FuncToLLVM/calling-convention.mlir b/mlir/test/Conversion/FuncToLLVM/calling-convention.mlir
index 7cdb89e1f72d28..8cdc8ea508d6ee 100644
--- a/mlir/test/Conversion/FuncToLLVM/calling-convention.mlir
+++ b/mlir/test/Conversion/FuncToLLVM/calling-convention.mlir
@@ -24,7 +24,7 @@ func.func private @external(%arg0: memref<?x?xf32>, %arg1: memref<f32>)
   // Allocate on stack and store to comply with C calling convention.
   // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index)
   // CHECK: %[[DESC0_ALLOCA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
-  // CHECK: llvm.store %[[DESC07]], %[[DESC0_ALLOCA]]
+  // CHECK: ptr.store %[[DESC07]], %[[DESC0_ALLOCA]]
 
   // Populate the descriptor for arg1.
   // CHECK: %[[DESC10:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64)>
@@ -35,7 +35,7 @@ func.func private @external(%arg0: memref<?x?xf32>, %arg1: memref<f32>)
   // Allocate on stack and store to comply with C calling convention.
   // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index)
   // CHECK: %[[DESC1_ALLOCA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr, ptr, i64)>
-  // CHECK: llvm.store %[[DESC13]], %[[DESC1_ALLOCA]]
+  // CHECK: ptr.store %[[DESC13]], %[[DESC1_ALLOCA]]
 
   // Call the interface function.
   // CHECK: llvm.call @_mlir_ciface_external
@@ -83,7 +83,7 @@ func.func @callee(%arg0: memref<?xf32>, %arg1: index) {
 // CHECK-LABEL: @_mlir_ciface_callee
 // CHECK: %[[ARG0:.*]]: !llvm.ptr
   // Load the memref descriptor pointer.
-  // CHECK: %[[DESC:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
+  // CHECK: %[[DESC:.*]] = ptr.load %[[ARG0]] : !llvm.ptr -> !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
 
   // Extract individual components of the descriptor.
   // CHECK: %[[ALLOC:.*]] = llvm.extractvalue %[[DESC]][0]
@@ -262,7 +262,7 @@ func.func @bare_ptr_calling_conv(%arg0: memref<4x3xf32>, %arg1 : index, %arg2 :
 
   // CHECK: %[[ALIGNEDPTR:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]
   // CHECK: %[[STOREPTR:.*]] = llvm.getelementptr %[[ALIGNEDPTR]]
-  // CHECK: llvm.store %{{.*}}, %[[STOREPTR]]
+  // CHECK: ptr.store %{{.*}}, %[[STOREPTR]]
   memref.store %arg3, %arg0[%arg1, %arg2] : memref<4x3xf32>
 
   // CHECK: llvm.return %[[ARG0]]
@@ -290,12 +290,12 @@ func.func @bare_ptr_calling_conv_multiresult(%arg0: memref<4x3xf32>, %arg1 : ind
 
   // CHECK: %[[ALIGNEDPTR:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]
   // CHECK: %[[STOREPTR:.*]] = llvm.getelementptr %[[ALIGNEDPTR]]
-  // CHECK: llvm.store %{{.*}}, %[[STOREPTR]]
+  // CHECK: ptr.store %{{.*}}, %[[STOREPTR]]
   memref.store %arg3, %arg0[%arg1, %arg2] : memref<4x3xf32>
 
   // CHECK: %[[ALIGNEDPTR0:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]
   // CHECK: %[[LOADPTR:.*]] = llvm.getelementptr %[[ALIGNEDPTR0]]
-  // CHECK: %[[RETURN0:.*]] = llvm.load %[[LOADPTR]]
+  // CHECK: %[[RETURN0:.*]] = ptr.load %[[LOADPTR]]
   %0 = memref.load %arg0[%arg1, %arg2] : memref<4x3xf32>
 
   // CHECK: %[[RETURN_DESC:.*]] = llvm.mlir.undef : !llvm.struct<(f32, ptr)>
diff --git a/mlir/test/Conversion/GPUCommon/lower-alloc-to-gpu-runtime-calls.mlir b/mlir/test/Conversion/GPUCommon/lower-alloc-to-gpu-runtime-calls.mlir
index ae8b7aaac7fd94..d8898c9b93a244 100644
--- a/mlir/test/Conversion/GPUCommon/lower-alloc-to-gpu-runtime-calls.mlir
+++ b/mlir/test/Conversion/GPUCommon/lower-alloc-to-gpu-runtime-calls.mlir
@@ -7,7 +7,7 @@ module attributes {gpu.container_module} {
     // CHECK: %[[stream:.*]] = llvm.call @mgpuStreamCreate()
     %0 = gpu.wait async
     // CHECK: %[[gep:.*]] = llvm.getelementptr {{.*}}[%[[size]]]
-    // CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]]
+    // CHECK: %[[size_bytes:.*]] = ptr.ptrtoint %[[gep]]
     // CHECK: %[[isHostShared:.*]] = llvm.mlir.constant 
     // CHECK: llvm.call @mgpuMemAlloc(%[[size_bytes]], %[[stream]], %[[isHostShared]])
     %1, %2 = gpu.alloc async [%0] (%size) : memref<?xf32>
@@ -24,7 +24,7 @@ module attributes {gpu.container_module} {
   // CHECK-SAME: %[[size:.*]]: i64
   func.func @alloc_sync(%size : index) {
     // CHECK: %[[gep:.*]] = llvm.getelementptr {{.*}}[%[[size]]]
-    // CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]]
+    // CHECK: %[[size_bytes:.*]] = ptr.ptrtoint %[[gep]]
     // CHECK: %[[nullptr:.*]] = llvm.mlir.zero
     // CHECK: %[[isHostShared:.*]] = llvm.mlir.constant 
     // CHECK: llvm.call @mgpuMemAlloc(%[[size_bytes]], %[[nullptr]], %[[isHostShared]])
diff --git a/mlir/test/Conversion/GPUCommon/lower-memcpy-to-gpu-runtime-calls.mlir b/mlir/test/Conversion/GPUCommon/lower-memcpy-to-gpu-runtime-calls.mlir
index 3f86b076982795..2985db83d9b141 100644
--- a/mlir/test/Conversion/GPUCommon/lower-memcpy-to-gpu-runtime-calls.mlir
+++ b/mlir/test/Conversion/GPUCommon/lower-memcpy-to-gpu-runtime-calls.mlir
@@ -6,9 +6,9 @@ module attributes {gpu.container_module} {
   func.func @foo(%dst : memref<7xf32, 1>, %src : memref<7xf32>) {
     // CHECK: %[[t0:.*]] = llvm.call @mgpuStreamCreate
     %t0 = gpu.wait async
-    // CHECK: %[[size_bytes:.*]] = llvm.ptrtoint
-    // CHECK-NOT: llvm.addrspacecast
-    // CHECK: %[[addr_cast:.*]] = llvm.addrspacecast
+    // CHECK: %[[size_bytes:.*]] = ptr.ptrtoint
+    // CHECK-NOT: ptr.addrspacecast
+    // CHECK: %[[addr_cast:.*]] = ptr.addrspacecast
     // CHECK: llvm.call @mgpuMemcpy(%[[addr_cast]], %{{.*}}, %[[size_bytes]], %[[t0]])
     %t1 = gpu.memcpy async [%t0] %dst, %src : memref<7xf32, 1>, memref<7xf32>
     // CHECK: llvm.call @mgpuStreamSynchronize(%[[t0]])
diff --git a/mlir/test/Conversion/GPUCommon/lower-memory-space-attrs.mlir b/mlir/test/Conversion/GPUCommon/lower-memory-space-attrs.mlir
index 771f3185904bb8..eb54d99a21bcee 100644
--- a/mlir/test/Conversion/GPUCommon/lower-memory-space-attrs.mlir
+++ b/mlir/test/Conversion/GPUCommon/lower-memory-space-attrs.mlir
@@ -10,7 +10,7 @@ gpu.module @kernel {
 }
 
 // CHECK-LABEL:  llvm.func @private
-//      CHECK:  llvm.store
+//      CHECK:  ptr.store
 // ROCDL-SAME:   : f32, !llvm.ptr<5>
 //  NVVM-SAME:   : f32, !llvm.ptr
 
@@ -26,7 +26,7 @@ gpu.module @kernel {
 }
 
 // CHECK-LABEL:  llvm.func @workgroup
-//       CHECK:  llvm.store
+//       CHECK:  ptr.store
 //  CHECK-SAME:   : f32, !llvm.ptr<3>
 
 // -----
@@ -41,9 +41,9 @@ gpu.module @kernel {
 }
 
 // CHECK-LABEL:  llvm.func @nested_memref
-//       CHECK:  llvm.load
+//       CHECK:  ptr.load
 //  CHECK-SAME:   : !llvm.ptr<1>
-//       CHECK: [[value:%.+]] = llvm.load
+//       CHECK: [[value:%.+]] = ptr.load
 //  CHECK-SAME:   : !llvm.ptr<1> -> f32
 //       CHECK: llvm.return [[value]]
 
@@ -64,8 +64,8 @@ gpu.module @kernel {
 // NVVM: llvm.mlir.global internal @__dynamic_shmem__0() {addr_space = 3 : i32, alignment = 16 : i64} : !llvm.array<0 x i8>
 // CHECK-LABEL:  llvm.func @dynamic_shmem_with_vector
 // CHECK: llvm.mlir.addressof @__dynamic_shmem__0 : !llvm.ptr<3>
-// CHECK: llvm.load %{{.*}} {alignment = 4 : i64} : !llvm.ptr<3> -> vector<1xf32>
-// CHECK: llvm.store
+// CHECK: ptr.load %{{.*}} {alignment = 4 : i64} : !llvm.ptr<3> -> vector<1xf32>
+// CHECK: ptr.store
 
 // -----
 
@@ -80,6 +80,6 @@ gpu.module @kernel {
 }
 
 // CHECK-LABEL:  llvm.func @dynamic_shmem
-//       CHECK:  llvm.store
+//       CHECK:  ptr.store
 //  CHECK-SAME:   : f32, !llvm.ptr<3>
 
diff --git a/mlir/test/Conversion/GPUCommon/lower-memset-to-gpu-runtime-calls.mlir b/mlir/test/Conversion/GPUCommon/lower-memset-to-gpu-runtime-calls.mlir
index aaced31813d574..a5752139b35a84 100644
--- a/mlir/test/Conversion/GPUCommon/lower-memset-to-gpu-runtime-calls.mlir
+++ b/mlir/test/Conversion/GPUCommon/lower-memset-to-gpu-runtime-calls.mlir
@@ -7,7 +7,7 @@ module attributes {gpu.container_module} {
     // CHECK: %[[t0:.*]] = llvm.call @mgpuStreamCreate
     %t0 = gpu.wait async
     // CHECK: %[[size_bytes:.*]] = llvm.mlir.constant
-    // CHECK: %[[addr_cast:.*]] = llvm.addrspacecast
+    // CHECK: %[[addr_cast:.*]] = ptr.addrspacecast
     // CHECK: llvm.call @mgpuMemset32(%[[addr_cast]], %{{.*}}, %[[size_bytes]], %[[t0]])
     %t1 = gpu.memset async [%t0] %dst, %value : memref<7xf32, 1>, f32
     // CHECK: llvm.call @mgpuStreamSynchronize(%[[t0]])
diff --git a/mlir/test/Conversion/GPUCommon/memory-attrbution.mlir b/mlir/test/Conversion/GPUCommon/memory-attrbution.mlir
index 4fc19b8e93646c..be1de375d2c004 100644
--- a/mlir/test/Conversion/GPUCommon/memory-attrbution.mlir
+++ b/mlir/test/Conversion/GPUCommon/memory-attrbution.mlir
@@ -36,11 +36,11 @@ gpu.module @kernel {
     // we emit some core instructions.
     // NVVM: llvm.extractvalue %[[descr6:.*]]
     // NVVM: llvm.getelementptr
-    // NVVM: llvm.store
+    // NVVM: ptr.store
 
     // ROCDL: llvm.extractvalue %[[descr6:.*]]
     // ROCDL: llvm.getelementptr
-    // ROCDL: llvm.store
+    // ROCDL: ptr.store
     %c0 = arith.constant 0 : index
     memref.store %arg0, %arg1[%c0] : memref<4xf32, #gpu.address_space<private>>
 
@@ -100,11 +100,11 @@ gpu.module @kernel {
     // we emit some core instructions.
     // NVVM: llvm.extractvalue %[[descr6:.*]]
     // NVVM: llvm.getelementptr
-    // NVVM: llvm.store
+    // NVVM: ptr.store
 
     // ROCDL: llvm.extractvalue %[[descr6:.*]]
     // ROCDL: llvm.getelementptr
-    // ROCDL: llvm.store
+    // ROCDL: ptr.store
     %c0 = arith.constant 0 : index
     memref.store %arg0, %arg1[%c0] : memref<4xf32, #gpu.address_space<workgroup>>
 
diff --git a/mlir/test/Conversion/GPUCommon/transfer_write.mlir b/mlir/test/Conversion/GPUCommon/transfer_write.mlir
index cba85915b49e43..5587730641c74b 100644
--- a/mlir/test/Conversion/GPUCommon/transfer_write.mlir
+++ b/mlir/test/Conversion/GPUCommon/transfer_write.mlir
@@ -6,7 +6,7 @@
       // CHECK:%[[val:[0-9]+]] = llvm.extractelement
       // CHECK:%[[base:[0-9]+]] = llvm.extractvalue
       // CHECK:%[[ptr:[0-9]+]] = llvm.getelementptr %[[base]]
-      // CHECK:llvm.store %[[val]], %[[ptr]]
+      // CHECK:ptr.store %[[val]], %[[ptr]]
       vector.transfer_write %arg3, %arg1[%c0, %c0] {in_bounds = [true]} : vector<1xf32>, memref<1024x1024xf32>
     }
     return
diff --git a/mlir/test/Conversion/GPUToNVVM/gpu-to-nvvm.mlir b/mlir/test/Conversion/GPUToNVVM/gpu-to-nvvm.mlir
index 8877ee083286b4..f46ce102ec8bde 100644
--- a/mlir/test/Conversion/GPUToNVVM/gpu-to-nvvm.mlir
+++ b/mlir/test/Conversion/GPUToNVVM/gpu-to-nvvm.mlir
@@ -594,9 +594,9 @@ gpu.module @test_module_29 {
     // CHECK-NEXT: %[[O:.*]] = llvm.mlir.constant(1 : index) : i64
     // CHECK-NEXT: %[[ALLOC:.*]] = llvm.alloca %[[O]] x !llvm.struct<(i32, f64)> : (i64) -> !llvm.ptr
     // CHECK-NEXT: %[[EL0:.*]] = llvm.getelementptr %[[ALLOC]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, f64)>
-    // CHECK-NEXT: llvm.store %[[ARG0]], %[[EL0]] : i32, !llvm.ptr
+    // CHECK-NEXT: ptr.store %[[ARG0]], %[[EL0]] : i32, !llvm.ptr
     // CHECK-NEXT: %[[EL1:.*]] = llvm.getelementptr %[[ALLOC]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, f64)>
-    // CHECK-NEXT: llvm.store %[[EXT]], %[[EL1]] : f64, !llvm.ptr
+    // CHECK-NEXT: ptr.store %[[EXT]], %[[EL1]] : f64, !llvm.ptr
     // CHECK-NEXT: llvm.call @vprintf(%[[FORMATSTART]], %[[ALLOC]]) : (!llvm.ptr, !llvm.ptr) -> i32
     gpu.printf "Hello: %d\n" %arg0, %arg1 : i32, f32
     gpu.return
@@ -705,7 +705,7 @@ module attributes {transform.with_named_sequence} {
         use_bare_ptr_memref_call_conv = true,
         use_opaque_pointers = true}
     } {
-      legal_dialects = ["llvm", "memref", "nvvm", "test"],
+      legal_dialects = ["ptr", "llvm", "memref", "nvvm", "test"],
       legal_ops = ["func.func", "gpu.module", "gpu.module_end", "gpu.yield"],
       illegal_dialects = ["gpu"],
       illegal_ops = ["llvm.cos", "llvm.exp", "llvm.exp2", "llvm.fabs", "llvm.fceil",
diff --git a/mlir/test/Conversion/GPUToVulkan/invoke-vulkan.mlir b/mlir/test/Conversion/GPUToVulkan/invoke-vulkan.mlir
index fe8a36ee29a9f0..ec7adb474089eb 100644
--- a/mlir/test/Conversion/GPUToVulkan/invoke-vulkan.mlir
+++ b/mlir/test/Conversion/GPUToVulkan/invoke-vulkan.mlir
@@ -24,7 +24,7 @@ module attributes {gpu.container_module} {
     %1 = llvm.mlir.zero : !llvm.ptr
     %2 = llvm.mlir.constant(1 : index) : i64
     %3 = llvm.getelementptr %1[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    %4 = llvm.ptrtoint %3 : !llvm.ptr to i64
+    %4 = ptr.ptrtoint %3 : !llvm.ptr to i64
     %5 = llvm.mul %0, %4 : i64
     %6 = llvm.call @malloc(%5) : (i64) -> !llvm.ptr
     %8 = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
@@ -54,7 +54,7 @@ module attributes {gpu.container_module} {
     %5 = llvm.insertvalue %arg10, %4[4, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
     %6 = llvm.mlir.constant(1 : index) : i64
     %7 = llvm.alloca %6 x !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> : (i64) -> !llvm.ptr
-    llvm.store %5, %7 : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, !llvm.ptr
+    ptr.store %5, %7 : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, !llvm.ptr
     llvm.call @_mlir_ciface_vulkanLaunch(%arg0, %arg1, %arg2, %7) : (i64, i64, i64, !llvm.ptr) -> ()
     llvm.return
   }
diff --git a/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir b/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir
index 609fcb10b992c6..3461a991fd6d2b 100644
--- a/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir
@@ -13,7 +13,7 @@ func.func @mixed_alloc(%arg0: index, %arg1: index) -> memref<?x42x?xf32> {
 //  CHECK-NEXT:  %[[sz:.*]] = llvm.mul %[[st0]], %[[M]] : i64
 //  CHECK-NEXT:  %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
 //  CHECK-NEXT:  %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-//  CHECK-NEXT:  %[[sz_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr to i64
+//  CHECK-NEXT:  %[[sz_bytes:.*]] = ptr.ptrtoint %[[gep]] : !llvm.ptr to i64
 //  CHECK-NEXT:  llvm.call @malloc(%[[sz_bytes]]) : (i64) -> !llvm.ptr
 //  CHECK-NEXT:  llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<3 x i64>, array<3 x i64>)>
 //  CHECK-NEXT:  llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm.struct<(ptr, ptr, i64, array<3 x i64>, array<3 x i64>)>
@@ -45,7 +45,7 @@ func.func @mixed_dealloc(%arg0: memref<?x42x?xf32>) {
 // CHECK-LABEL: func @unranked_dealloc
 func.func @unranked_dealloc(%arg0: memref<*xf32>) {
 //      CHECK: %[[memref:.*]] = llvm.extractvalue %{{.*}} : !llvm.struct<(i64, ptr)>
-//      CHECK: %[[ptr:.*]] = llvm.load %[[memref]]
+//      CHECK: %[[ptr:.*]] = ptr.load %[[memref]]
 // CHECK-NEXT: llvm.call @free(%[[ptr]])
   memref.dealloc %arg0 : memref<*xf32>
   return
@@ -62,7 +62,7 @@ func.func @dynamic_alloc(%arg0: index, %arg1: index) -> memref<?x?xf32> {
 //  CHECK-NEXT:  %[[sz:.*]] = llvm.mul %[[N]], %[[M]] : i64
 //  CHECK-NEXT:  %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
 //  CHECK-NEXT:  %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-//  CHECK-NEXT:  %[[sz_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr to i64
+//  CHECK-NEXT:  %[[sz_bytes:.*]] = ptr.ptrtoint %[[gep]] : !llvm.ptr to i64
 //  CHECK-NEXT:  llvm.call @malloc(%[[sz_bytes]]) : (i64) -> !llvm.ptr
 //  CHECK-NEXT:  llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 //  CHECK-NEXT:  llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
@@ -130,7 +130,7 @@ func.func @stdlib_aligned_alloc(%N : index) -> memref<32x18xf32> {
 // ALIGNED-ALLOC-NEXT:  %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : i64
 // ALIGNED-ALLOC-NEXT:  %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
 // ALIGNED-ALLOC-NEXT:  %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// ALIGNED-ALLOC-NEXT:  %[[bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr to i64
+// ALIGNED-ALLOC-NEXT:  %[[bytes:.*]] = ptr.ptrtoint %[[gep]] : !llvm.ptr to i64
 // ALIGNED-ALLOC-NEXT:  %[[alignment:.*]] = llvm.mlir.constant(32 : index) : i64
 // ALIGNED-ALLOC-NEXT:  %[[allocated:.*]] = llvm.call @aligned_alloc(%[[alignment]], %[[bytes]]) : (i64, i64) -> !llvm.ptr
   %0 = memref.alloc() {alignment = 32} : memref<32x18xf32>
@@ -178,7 +178,7 @@ func.func @mixed_load(%mixed : memref<42x?xf32>, %i : index, %j : index) {
 //  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
 //  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-//  CHECK-NEXT:  llvm.load %[[addr]] : !llvm.ptr -> f32
+//  CHECK-NEXT:  ptr.load %[[addr]] : !llvm.ptr -> f32
   %0 = memref.load %mixed[%i, %j] : memref<42x?xf32>
   return
 }
@@ -195,7 +195,7 @@ func.func @dynamic_load(%dynamic : memref<?x?xf32>, %i : index, %j : index) {
 //  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
 //  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-//  CHECK-NEXT:  llvm.load %[[addr]] : !llvm.ptr -> f32
+//  CHECK-NEXT:  ptr.load %[[addr]] : !llvm.ptr -> f32
   %0 = memref.load %dynamic[%i, %j] : memref<?x?xf32>
   return
 }
@@ -233,7 +233,7 @@ func.func @dynamic_store(%dynamic : memref<?x?xf32>, %i : index, %j : index, %va
 //  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
 //  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-//  CHECK-NEXT:  llvm.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
+//  CHECK-NEXT:  ptr.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
   memref.store %val, %dynamic[%i, %j] : memref<?x?xf32>
   return
 }
@@ -250,7 +250,7 @@ func.func @mixed_store(%mixed : memref<42x?xf32>, %i : index, %j : index, %val :
 //  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
 //  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-//  CHECK-NEXT:  llvm.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
+//  CHECK-NEXT:  ptr.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
   memref.store %val, %mixed[%i, %j] : memref<42x?xf32>
   return
 }
@@ -289,14 +289,14 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
 // CHECK: llvm.insertvalue [[RESULT_DESC]], [[RESULT_1]][1]
 
 // Cast pointers
-// CHECK: [[SOURCE_ALLOC:%.*]] = llvm.load [[SOURCE_DESC]]
+// CHECK: [[SOURCE_ALLOC:%.*]] = ptr.load [[SOURCE_DESC]]
 // CHECK: [[SOURCE_ALIGN_GEP:%.*]] = llvm.getelementptr [[SOURCE_DESC]][1]
-// CHECK: [[SOURCE_ALIGN:%.*]] = llvm.load [[SOURCE_ALIGN_GEP]] : !llvm.ptr
-// CHECK: [[RESULT_ALLOC:%.*]] = llvm.addrspacecast [[SOURCE_ALLOC]] : !llvm.ptr to !llvm.ptr<1>
-// CHECK: [[RESULT_ALIGN:%.*]] = llvm.addrspacecast [[SOURCE_ALIGN]] : !llvm.ptr to !llvm.ptr<1>
-// CHECK: llvm.store [[RESULT_ALLOC]], [[RESULT_DESC]] : !llvm.ptr
+// CHECK: [[SOURCE_ALIGN:%.*]] = ptr.load [[SOURCE_ALIGN_GEP]] : !llvm.ptr
+// CHECK: [[RESULT_ALLOC:%.*]] = ptr.addrspacecast [[SOURCE_ALLOC]] : !llvm.ptr to !llvm.ptr<1>
+// CHECK: [[RESULT_ALIGN:%.*]] = ptr.addrspacecast [[SOURCE_ALIGN]] : !llvm.ptr to !llvm.ptr<1>
+// CHECK: ptr.store [[RESULT_ALLOC]], [[RESULT_DESC]] : !llvm.ptr
 // CHECK: [[RESULT_ALIGN_GEP:%.*]] = llvm.getelementptr [[RESULT_DESC]][1]
-// CHECK: llvm.store [[RESULT_ALIGN]], [[RESULT_ALIGN_GEP]] : !llvm.ptr
+// CHECK: ptr.store [[RESULT_ALIGN]], [[RESULT_ALIGN_GEP]] : !llvm.ptr
 
 // Memcpy remaining values
 
@@ -376,14 +376,14 @@ func.func @memref_cast_mixed_to_mixed(%mixed : memref<42x?xf32>) {
 func.func @memref_cast_ranked_to_unranked(%arg : memref<42x2x?xf32>) {
 // CHECK-DAG:  %[[c:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK-DAG:  %[[p:.*]] = llvm.alloca %[[c]] x !llvm.struct<(ptr, ptr, i64, array<3 x i64>, array<3 x i64>)> : (i64) -> !llvm.ptr
-// CHECK-DAG:  llvm.store %{{.*}}, %[[p]] : !llvm.struct<(ptr, ptr, i64, array<3 x i64>, array<3 x i64>)>, !llvm.ptr
+// CHECK-DAG:  ptr.store %{{.*}}, %[[p]] : !llvm.struct<(ptr, ptr, i64, array<3 x i64>, array<3 x i64>)>, !llvm.ptr
 // CHECK-DAG:  %[[r:.*]] = llvm.mlir.constant(3 : index) : i64
 // CHECK    :  llvm.mlir.undef : !llvm.struct<(i64, ptr)>
 // CHECK-DAG:  llvm.insertvalue %[[r]], %{{.*}}[0] : !llvm.struct<(i64, ptr)>
 // CHECK-DAG:  llvm.insertvalue %[[p]], %{{.*}}[1] : !llvm.struct<(i64, ptr)>
 // CHECK32-DAG:  %[[c:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK32-DAG:  %[[p:.*]] = llvm.alloca %[[c]] x !llvm.struct<(ptr, ptr, i32, array<3 x i32>, array<3 x i32>)> : (i64) -> !llvm.ptr
-// CHECK32-DAG:  llvm.store %{{.*}}, %[[p]] : !llvm.struct<(ptr, ptr, i32, array<3 x i32>, array<3 x i32>)>, !llvm.ptr
+// CHECK32-DAG:  ptr.store %{{.*}}, %[[p]] : !llvm.struct<(ptr, ptr, i32, array<3 x i32>, array<3 x i32>)>, !llvm.ptr
 // CHECK32-DAG:  %[[r:.*]] = llvm.mlir.constant(3 : index) : i32
 // CHECK32    :  llvm.mlir.undef : !llvm.struct<(i32, ptr)>
 // CHECK32-DAG:  llvm.insertvalue %[[r]], %{{.*}}[0] : !llvm.struct<(i32, ptr)>
@@ -432,9 +432,9 @@ func.func @memref_dim_with_dyn_index(%arg : memref<3x?xf32>, %idx : index) -> in
   // CHECK-DAG: %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64
   // CHECK-DAG: %[[SIZES:.*]] = llvm.extractvalue %{{.*}}[3] : ![[DESCR_TY:.*]]
   // CHECK-DAG: %[[SIZES_PTR:.*]] = llvm.alloca %[[C1]] x !llvm.array<2 x i64> : (i64) -> !llvm.ptr
-  // CHECK-DAG: llvm.store %[[SIZES]], %[[SIZES_PTR]] : !llvm.array<2 x i64>, !llvm.ptr
+  // CHECK-DAG: ptr.store %[[SIZES]], %[[SIZES_PTR]] : !llvm.array<2 x i64>, !llvm.ptr
   // CHECK-DAG: %[[RESULT_PTR:.*]] = llvm.getelementptr %[[SIZES_PTR]][0, %[[IDX]]] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<2 x i64>
-  // CHECK-DAG: %[[RESULT:.*]] = llvm.load %[[RESULT_PTR]] : !llvm.ptr -> i64
+  // CHECK-DAG: %[[RESULT:.*]] = ptr.load %[[RESULT_PTR]] : !llvm.ptr -> i64
   %result = memref.dim %arg, %idx : memref<3x?xf32>
   return %result : index
 }
@@ -492,10 +492,10 @@ func.func @memref_reinterpret_cast_unranked_to_dynamic_shape(%offset: index,
 // CHECK-DAG: [[INPUT:%.*]] = builtin.unrealized_conversion_cast
 // CHECK: [[OUT_0:%.*]] = llvm.mlir.undef : [[TY:!.*]]
 // CHECK: [[DESCRIPTOR:%.*]] = llvm.extractvalue [[INPUT]][1] : !llvm.struct<(i64, ptr)>
-// CHECK: [[BASE_PTR:%.*]] = llvm.load [[DESCRIPTOR]] : !llvm.ptr -> !llvm.ptr
+// CHECK: [[BASE_PTR:%.*]] = ptr.load [[DESCRIPTOR]] : !llvm.ptr -> !llvm.ptr
 // CHECK: [[ALIGNED_PTR_PTR:%.*]] = llvm.getelementptr [[DESCRIPTOR]]{{\[}}1]
 // CHECK-SAME: : (!llvm.ptr) -> !llvm.ptr, !llvm.ptr
-// CHECK: [[ALIGNED_PTR:%.*]] = llvm.load [[ALIGNED_PTR_PTR]] : !llvm.ptr -> !llvm.ptr
+// CHECK: [[ALIGNED_PTR:%.*]] = ptr.load [[ALIGNED_PTR_PTR]] : !llvm.ptr -> !llvm.ptr
 // CHECK: [[OUT_1:%.*]] = llvm.insertvalue [[BASE_PTR]], [[OUT_0]][0] : [[TY]]
 // CHECK: [[OUT_2:%.*]] = llvm.insertvalue [[ALIGNED_PTR]], [[OUT_1]][1] : [[TY]]
 // CHECK: [[OUT_3:%.*]] = llvm.insertvalue [[OFFSET]], [[OUT_2]][2] : [[TY]]
@@ -532,11 +532,11 @@ func.func @memref_reshape(%input : memref<2x3xf32>, %shape : memref<?xindex>) {
 // CHECK: [[ALLOC_PTR:%.*]] = llvm.extractvalue [[INPUT]][0] : [[INPUT_TY]]
 // CHECK: [[ALIGN_PTR:%.*]] = llvm.extractvalue [[INPUT]][1] : [[INPUT_TY]]
 // CHECK: [[OFFSET:%.*]] = llvm.extractvalue [[INPUT]][2] : [[INPUT_TY]]
-// CHECK: llvm.store [[ALLOC_PTR]], [[UNDERLYING_DESC]] : !llvm.ptr, !llvm.ptr
+// CHECK: ptr.store [[ALLOC_PTR]], [[UNDERLYING_DESC]] : !llvm.ptr, !llvm.ptr
 // CHECK: [[ALIGNED_PTR_PTR:%.*]] = llvm.getelementptr [[UNDERLYING_DESC]]{{\[}}1]
-// CHECK: llvm.store [[ALIGN_PTR]], [[ALIGNED_PTR_PTR]] : !llvm.ptr, !llvm.ptr
+// CHECK: ptr.store [[ALIGN_PTR]], [[ALIGNED_PTR_PTR]] : !llvm.ptr, !llvm.ptr
 // CHECK: [[OFFSET_PTR:%.*]] = llvm.getelementptr [[UNDERLYING_DESC]]{{\[}}2]
-// CHECK: llvm.store [[OFFSET]], [[OFFSET_PTR]] : i64, !llvm.ptr
+// CHECK: ptr.store [[OFFSET]], [[OFFSET_PTR]] : i64, !llvm.ptr
 
 // Iterate over shape operand in reverse order and set sizes and strides.
 // CHECK: [[SIZES_PTR:%.*]] = llvm.getelementptr [[UNDERLYING_DESC]]{{\[}}0, 3]
@@ -553,11 +553,11 @@ func.func @memref_reshape(%input : memref<2x3xf32>, %shape : memref<?xindex>) {
 
 // CHECK: ^bb2:
 // CHECK:   [[SIZE_PTR:%.*]] = llvm.getelementptr [[SHAPE_IN_PTR]]{{\[}}[[DIM]]]
-// CHECK:   [[SIZE:%.*]] = llvm.load [[SIZE_PTR]] : !llvm.ptr -> i64
+// CHECK:   [[SIZE:%.*]] = ptr.load [[SIZE_PTR]] : !llvm.ptr -> i64
 // CHECK:   [[TARGET_SIZE_PTR:%.*]] = llvm.getelementptr [[SIZES_PTR]]{{\[}}[[DIM]]]
-// CHECK:   llvm.store [[SIZE]], [[TARGET_SIZE_PTR]] : i64, !llvm.ptr
+// CHECK:   ptr.store [[SIZE]], [[TARGET_SIZE_PTR]] : i64, !llvm.ptr
 // CHECK:   [[TARGET_STRIDE_PTR:%.*]] = llvm.getelementptr [[STRIDES_PTR]]{{\[}}[[DIM]]]
-// CHECK:   llvm.store [[CUR_STRIDE]], [[TARGET_STRIDE_PTR]] : i64, !llvm.ptr
+// CHECK:   ptr.store [[CUR_STRIDE]], [[TARGET_STRIDE_PTR]] : i64, !llvm.ptr
 // CHECK:   [[UPDATE_STRIDE:%.*]] = llvm.mul [[CUR_STRIDE]], [[SIZE]] : i64
 // CHECK:   [[STRIDE_COND:%.*]] = llvm.sub [[DIM]], [[C1_]] : i64
 // CHECK:   llvm.br ^bb1([[STRIDE_COND]], [[UPDATE_STRIDE]] : i64, i64)
@@ -572,7 +572,7 @@ func.func @memref_of_memref() {
   // Sizeof computation is as usual.
   // ALIGNED-ALLOC: %[[NULL:.*]] = llvm.mlir.zero
   // ALIGNED-ALLOC: %[[PTR:.*]] = llvm.getelementptr
-  // ALIGNED-ALLOC: %[[SIZEOF:.*]] = llvm.ptrtoint
+  // ALIGNED-ALLOC: %[[SIZEOF:.*]] = ptr.ptrtoint
 
   // Static alignment should be computed as ceilPowerOf2(2 * sizeof(pointer) +
   // (1 + 2 * rank) * sizeof(index) = ceilPowerOf2(2 * 8 + 3 * 8) = 64.
@@ -594,7 +594,7 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<index, 32>> } {
     // Sizeof computation is as usual.
     // ALIGNED-ALLOC: %[[NULL:.*]] = llvm.mlir.zero
     // ALIGNED-ALLOC: %[[PTR:.*]] = llvm.getelementptr
-    // ALIGNED-ALLOC: %[[SIZEOF:.*]] = llvm.ptrtoint
+    // ALIGNED-ALLOC: %[[SIZEOF:.*]] = ptr.ptrtoint
 
     // Static alignment should be computed as ceilPowerOf2(2 * sizeof(pointer) +
     // (1 + 2 * rank) * sizeof(index) = ceilPowerOf2(2 * 8 + 3 * 4) = 32.
@@ -617,7 +617,7 @@ func.func @memref_of_memref_of_memref() {
   // Sizeof computation is as usual, also check the type.
   // ALIGNED-ALLOC: %[[NULL:.*]] = llvm.mlir.zero : !llvm.ptr
   // ALIGNED-ALLOC: %[[PTR:.*]] = llvm.getelementptr
-  // ALIGNED-ALLOC: %[[SIZEOF:.*]] = llvm.ptrtoint
+  // ALIGNED-ALLOC: %[[SIZEOF:.*]] = ptr.ptrtoint
 
   // Static alignment should be computed as ceilPowerOf2(2 * sizeof(pointer) +
   // (1 + 2 * rank) * sizeof(index) = ceilPowerOf2(2 * 8 + 3 * 8) = 64.
@@ -634,7 +634,7 @@ func.func @ranked_unranked() {
   // ALIGNED-ALLOC: llvm.mlir.zero
   // ALIGNED-ALLOC-SAME: !llvm.ptr
   // ALIGNED-ALLOC: llvm.getelementptr
-  // ALIGNED-ALLOC: llvm.ptrtoint
+  // ALIGNED-ALLOC: ptr.ptrtoint
 
   // Static alignment should be computed as ceilPowerOf2(sizeof(index) +
   // sizeof(pointer)) = 16.
diff --git a/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir b/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir
index f1600d43e7bfb3..414a34580371eb 100644
--- a/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir
@@ -5,7 +5,7 @@ func.func @zero_d_alloc() -> memref<f32> {
 // CHECK: %[[one:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK: %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr to i64
+// CHECK: %[[size_bytes:.*]] = ptr.ptrtoint %[[gep]] : !llvm.ptr to i64
 // CHECK: %[[ptr:.*]] = llvm.call @malloc(%[[size_bytes]]) : (i64) -> !llvm.ptr
 // CHECK: llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64)>
 // CHECK: llvm.insertvalue %[[ptr]], %{{.*}}[0] : !llvm.struct<(ptr, ptr, i64)>
@@ -38,17 +38,17 @@ func.func @aligned_1d_alloc() -> memref<42xf32> {
 // CHECK: %[[st1:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK: %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr to i64
+// CHECK: %[[size_bytes:.*]] = ptr.ptrtoint %[[gep]] : !llvm.ptr to i64
 // CHECK: %[[alignment:.*]] = llvm.mlir.constant(8 : index) : i64
 // CHECK: %[[allocsize:.*]] = llvm.add %[[size_bytes]], %[[alignment]] : i64
 // CHECK: %[[ptr:.*]] = llvm.call @malloc(%[[allocsize]]) : (i64) -> !llvm.ptr
-// CHECK: %[[allocatedAsInt:.*]] = llvm.ptrtoint %[[ptr]] : !llvm.ptr to i64
+// CHECK: %[[allocatedAsInt:.*]] = ptr.ptrtoint %[[ptr]] : !llvm.ptr to i64
 // CHECK: %[[one_1:.*]] = llvm.mlir.constant(1 : index) : i64
 // CHECK: %[[bump:.*]] = llvm.sub %[[alignment]], %[[one_1]] : i64
 // CHECK: %[[bumped:.*]] = llvm.add %[[allocatedAsInt]], %[[bump]] : i64
 // CHECK: %[[mod:.*]] = llvm.urem %[[bumped]], %[[alignment]] : i64
 // CHECK: %[[aligned:.*]] = llvm.sub %[[bumped]], %[[mod]] : i64
-// CHECK: %[[alignedBitCast:.*]] = llvm.inttoptr %[[aligned]] : i64 to !llvm.ptr
+// CHECK: %[[alignedBitCast:.*]] = ptr.inttoptr %[[aligned]] : i64 to !llvm.ptr
 // CHECK: llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
 // CHECK: llvm.insertvalue %[[ptr]], %{{.*}}[0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
 // CHECK: llvm.insertvalue %[[alignedBitCast]], %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
@@ -65,7 +65,7 @@ func.func @static_alloc() -> memref<32x18xf32> {
 // CHECK: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : i64
 // CHECK: %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
 // CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr to i64
+// CHECK: %[[size_bytes:.*]] = ptr.ptrtoint %[[gep]] : !llvm.ptr to i64
 // CHECK: llvm.call @malloc(%[[size_bytes]]) : (i64) -> !llvm.ptr
  %0 = memref.alloc() : memref<32x18xf32>
  return %0 : memref<32x18xf32>
@@ -108,7 +108,7 @@ func.func @static_dealloc(%static: memref<10x8xf32>) {
 // CHECK-LABEL: func @zero_d_load
 func.func @zero_d_load(%arg0: memref<f32>) -> f32 {
 // CHECK: %[[ptr:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64)>
-// CHECK: %{{.*}} = llvm.load %[[ptr]] : !llvm.ptr -> f32
+// CHECK: %{{.*}} = ptr.load %[[ptr]] : !llvm.ptr -> f32
   %0 = memref.load %arg0[] : memref<f32>
   return %0 : f32
 }
@@ -127,7 +127,7 @@ func.func @static_load(%static : memref<10x42xf32>, %i : index, %j : index) {
 // CHECK:  %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] : i64
 // CHECK:  %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] : i64
 // CHECK:  %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK:  llvm.load %[[addr]] : !llvm.ptr -> f32
+// CHECK:  ptr.load %[[addr]] : !llvm.ptr -> f32
   %0 = memref.load %static[%i, %j] : memref<10x42xf32>
   return
 }
@@ -137,7 +137,7 @@ func.func @static_load(%static : memref<10x42xf32>, %i : index, %j : index) {
 // CHECK-LABEL: func @zero_d_store
 func.func @zero_d_store(%arg0: memref<f32>, %arg1: f32) {
 // CHECK: %[[ptr:.*]] = llvm.extractvalue %[[ld:.*]][1] : !llvm.struct<(ptr, ptr, i64)>
-// CHECK: llvm.store %{{.*}}, %[[ptr]] : f32, !llvm.ptr
+// CHECK: ptr.store %{{.*}}, %[[ptr]] : f32, !llvm.ptr
   memref.store %arg1, %arg0[] : memref<f32>
   return
 }
@@ -155,7 +155,7 @@ func.func @static_store(%static : memref<10x42xf32>, %i : index, %j : index, %va
 // CHECK: %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] : i64
 // CHECK: %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] : i64
 // CHECK: %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: llvm.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
+// CHECK: ptr.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
 
   memref.store %val, %static[%i, %j] : memref<10x42xf32>
   return
@@ -190,7 +190,7 @@ func.func @static_out_of_bound_memref_dim(%static : memref<42x32x15x13x27xf32>)
 // CHECK: %[[C_MINUS_7:.*]] = arith.constant -7 : index
 // CHECK: %[[C_MINUS_7_I64:.*]] = builtin.unrealized_conversion_cast %[[C_MINUS_7]] : index to i64
 // CHECK: %[[UB_IDX:.*]] = llvm.getelementptr %{{.*}}[0, %[[C_MINUS_7_I64]]] : (!llvm.ptr, i64) -> !llvm.ptr
-// CHECK: %[[UB_DIM_I64:.*]] = llvm.load %[[UB_IDX]] : !llvm.ptr
+// CHECK: %[[UB_DIM_I64:.*]] = ptr.load %[[UB_IDX]] : !llvm.ptr
 // CHECK: %[[UB_DIM:.*]] = builtin.unrealized_conversion_cast %[[UB_DIM_I64]] : i64 to index
 // CHECK: return %[[UB_DIM]] : index
   %c-7 = arith.constant -7 : index
@@ -209,16 +209,16 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<index, 32>> } {
     // CHECK: %[[CST:.*]] = builtin.unrealized_conversion_cast
     // CHECK: llvm.mlir.zero
     // CHECK: llvm.getelementptr %{{.*}}[[CST]]
-    // CHECK: llvm.ptrtoint %{{.*}} : !llvm.ptr to i32
-    // CHECK: llvm.ptrtoint %{{.*}} : !llvm.ptr to i32
+    // CHECK: ptr.ptrtoint %{{.*}} : !llvm.ptr to i32
+    // CHECK: ptr.ptrtoint %{{.*}} : !llvm.ptr to i32
     // CHECK: llvm.add %{{.*}} : i32
     // CHECK: llvm.call @malloc(%{{.*}}) : (i32) -> !llvm.ptr
-    // CHECK: llvm.ptrtoint %{{.*}} : !llvm.ptr to i32
+    // CHECK: ptr.ptrtoint %{{.*}} : !llvm.ptr to i32
     // CHECK: llvm.sub {{.*}} : i32
     // CHECK: llvm.add {{.*}} : i32
     // CHECK: llvm.urem {{.*}} : i32
     // CHECK: llvm.sub {{.*}} : i32
-    // CHECK: llvm.inttoptr %{{.*}} : i32 to !llvm.ptr
+    // CHECK: ptr.inttoptr %{{.*}} : i32 to !llvm.ptr
     return
   }
 }
@@ -294,7 +294,7 @@ func.func @memref.reshape.dynamic.dim(%arg: memref<?x?x?xf32>, %shape: memref<4x
   // CHECK: %[[one1:.*]] = llvm.mlir.constant(1 : index) : i64
   // CHECK: %[[shape_ptr0:.*]] = llvm.extractvalue %[[shape_cast]][1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: %[[shape_gep0:.*]] = llvm.getelementptr %[[shape_ptr0]][%[[one1]]] : (!llvm.ptr, i64) -> !llvm.ptr, i64
-  // CHECK: %[[shape_load0:.*]] = llvm.load %[[shape_gep0]] : !llvm.ptr -> i64
+  // CHECK: %[[shape_load0:.*]] = ptr.load %[[shape_gep0]] : !llvm.ptr -> i64
   // CHECK: %[[insert7:.*]] = llvm.insertvalue %[[shape_load0]], %[[insert6]][3, 1] : !llvm.struct<(ptr, ptr, i64, array<4 x i64>, array<4 x i64>)>
   // CHECK: %[[insert8:.*]] = llvm.insertvalue %[[three_hundred_and_eighty_four]], %[[insert7]][4, 1] : !llvm.struct<(ptr, ptr, i64, array<4 x i64>, array<4 x i64>)>
 
@@ -302,7 +302,7 @@ func.func @memref.reshape.dynamic.dim(%arg: memref<?x?x?xf32>, %shape: memref<4x
   // CHECK: %[[zero1:.*]] = llvm.mlir.constant(0 : index) : i64
   // CHECK: %[[shape_ptr1:.*]] = llvm.extractvalue %[[shape_cast]][1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: %[[shape_gep1:.*]] = llvm.getelementptr %[[shape_ptr1]][%[[zero1]]] : (!llvm.ptr, i64) -> !llvm.ptr, i64
-  // CHECK: %[[shape_load1:.*]] = llvm.load %[[shape_gep1]] : !llvm.ptr -> i64
+  // CHECK: %[[shape_load1:.*]] = ptr.load %[[shape_gep1]] : !llvm.ptr -> i64
   // CHECK: %[[insert9:.*]] = llvm.insertvalue %[[shape_load1]], %[[insert8]][3, 0] : !llvm.struct<(ptr, ptr, i64, array<4 x i64>, array<4 x i64>)>
   // CHECK: %[[insert10:.*]] = llvm.insertvalue %[[mul]], %[[insert9]][4, 0] : !llvm.struct<(ptr, ptr, i64, array<4 x i64>, array<4 x i64>)>
 
@@ -334,7 +334,7 @@ func.func @memref.reshape_index(%arg0: memref<?x?xi32>, %shape: memref<1xindex>)
 
   // CHECK: %[[shape_ptr0:.*]] = llvm.extractvalue %[[shape_cast:.*]][1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: %[[shape_gep0:.*]] = llvm.getelementptr %[[shape_ptr0:.*]][%[[zero1:.*]]] : (!llvm.ptr, i64) -> !llvm.ptr, i64
-  // CHECK: %[[shape_load0:.*]] = llvm.load %[[shape_gep0:.*]] : !llvm.ptr -> i64
+  // CHECK: %[[shape_load0:.*]] = ptr.load %[[shape_gep0:.*]] : !llvm.ptr -> i64
   // CHECK: %[[insert3:.*]] = llvm.insertvalue %[[shape_load0:.*]], %[[insert2:.*]][3, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: %[[insert4:.*]] = llvm.insertvalue %[[one0:.*]], %[[insert3:.*]][4, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
 
@@ -356,8 +356,8 @@ func.func @memref_memory_space_cast(%input : memref<?xf32>) -> memref<?xf32, 1>
 // CHECK: [[OFFSET:%.*]] = llvm.extractvalue [[INPUT]][2]
 //   CHECK: [[SIZE:%.*]] = llvm.extractvalue [[INPUT]][3, 0]
 // CHECK: [[STRIDE:%.*]] = llvm.extractvalue [[INPUT]][4, 0]
-// CHECK: [[CAST_ALLOC:%.*]] = llvm.addrspacecast [[ALLOC]] : !llvm.ptr to !llvm.ptr<1>
-// CHECK: [[CAST_ALIGN:%.*]] = llvm.addrspacecast [[ALIGN]] : !llvm.ptr to !llvm.ptr<1>
+// CHECK: [[CAST_ALLOC:%.*]] = ptr.addrspacecast [[ALLOC]] : !llvm.ptr to !llvm.ptr<1>
+// CHECK: [[CAST_ALIGN:%.*]] = ptr.addrspacecast [[ALIGN]] : !llvm.ptr to !llvm.ptr<1>
 // CHECK: [[RESULT_0:%.*]] = llvm.mlir.undef
 // CHECK: [[RESULT_1:%.*]] = llvm.insertvalue [[CAST_ALLOC]], [[RESULT_0]][0]
 // CHECK: [[RESULT_2:%.*]] = llvm.insertvalue [[CAST_ALIGN]], [[RESULT_1]][1]
diff --git a/mlir/test/Conversion/MemRefToLLVM/expand-then-convert-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/expand-then-convert-to-llvm.mlir
index 87d613986c7c3f..4ba6ae26d9311d 100644
--- a/mlir/test/Conversion/MemRefToLLVM/expand-then-convert-to-llvm.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/expand-then-convert-to-llvm.mlir
@@ -681,12 +681,12 @@ func.func @collapse_static_shape_with_non_identity_layout(%arg: memref<1x1x8x8xf
 // CHECK: %[[ALIGNED_PTR:.*]] = llvm.extractvalue %[[DESC]][1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 // CHECK: %[[OFFSET:.*]] = llvm.extractvalue %[[DESC]][2] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 // CHECK: %[[BUFF_ADDR:.*]] = llvm.getelementptr %[[ALIGNED_PTR]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: %[[INT_TO_PTR:.*]] = llvm.ptrtoint %[[BUFF_ADDR]] : !llvm.ptr to i64
+// CHECK: %[[INT_TO_PTR:.*]] = ptr.ptrtoint %[[BUFF_ADDR]] : !llvm.ptr to i64
 // CHECK: %[[AND:.*]] = llvm.and %[[INT_TO_PTR]], {{.*}}  : i64
 // CHECK: %[[CMP:.*]] = llvm.icmp "eq" %[[AND]], {{.*}} : i64
 // CHECK: "llvm.intr.assume"(%[[CMP]]) : (i1) -> ()
 // CHECK: %[[LD_ADDR:.*]] = llvm.getelementptr %[[BUFF_ADDR]][%{{.*}}] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: %[[VAL:.*]] = llvm.load %[[LD_ADDR]] : !llvm.ptr -> f32
+// CHECK: %[[VAL:.*]] = ptr.load %[[LD_ADDR]] : !llvm.ptr -> f32
 // CHECK: return %[[VAL]] : f32
 func.func @load_and_assume(
     %arg0: memref<?x?xf32, strided<[?, ?], offset: ?>>,
diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
index 37999d6fc14ad1..9be7de6d43eed5 100644
--- a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
@@ -157,7 +157,7 @@ func.func @assume_alignment(%0 : memref<4x4xf16>) {
   // CHECK: %[[PTR:.*]] = llvm.extractvalue %[[MEMREF:.*]][1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
   // CHECK-NEXT: %[[ZERO:.*]] = llvm.mlir.constant(0 : index) : i64
   // CHECK-NEXT: %[[MASK:.*]] = llvm.mlir.constant(15 : index) : i64
-  // CHECK-NEXT: %[[INT:.*]] = llvm.ptrtoint %[[PTR]] : !llvm.ptr to i64
+  // CHECK-NEXT: %[[INT:.*]] = ptr.ptrtoint %[[PTR]] : !llvm.ptr to i64
   // CHECK-NEXT: %[[MASKED_PTR:.*]] = llvm.and %[[INT]], %[[MASK:.*]] : i64
   // CHECK-NEXT: %[[CONDITION:.*]] = llvm.icmp "eq" %[[MASKED_PTR]], %[[ZERO]] : i64
   // CHECK-NEXT: "llvm.intr.assume"(%[[CONDITION]]) : (i1) -> ()
@@ -174,7 +174,7 @@ func.func @assume_alignment_w_offset(%0 : memref<4x4xf16, strided<[?, ?], offset
   // CHECK-DAG: %[[BUFF_ADDR:.*]] =  llvm.getelementptr %[[PTR]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, f16
   // CHECK-DAG: %[[ZERO:.*]] = llvm.mlir.constant(0 : index) : i64
   // CHECK-DAG: %[[MASK:.*]] = llvm.mlir.constant(15 : index) : i64
-  // CHECK-NEXT: %[[INT:.*]] = llvm.ptrtoint %[[BUFF_ADDR]] : !llvm.ptr to i64
+  // CHECK-NEXT: %[[INT:.*]] = ptr.ptrtoint %[[BUFF_ADDR]] : !llvm.ptr to i64
   // CHECK-NEXT: %[[MASKED_PTR:.*]] = llvm.and %[[INT]], %[[MASK:.*]] : i64
   // CHECK-NEXT: %[[CONDITION:.*]] = llvm.icmp "eq" %[[MASKED_PTR]], %[[ZERO]] : i64
   // CHECK-NEXT: "llvm.intr.assume"(%[[CONDITION]]) : (i1) -> ()
@@ -204,21 +204,21 @@ func.func @dim_of_unranked(%unranked: memref<*xi32>) -> index {
 // CHECK: %[[SIZE_PTR:.*]] = llvm.getelementptr %[[OFFSET_PTR]]{{\[}}
 // CHECK-SAME:   %[[INDEX_INC]]] : (!llvm.ptr, i64) -> !llvm.ptr
 
-// CHECK: %[[SIZE:.*]] = llvm.load %[[SIZE_PTR]] : !llvm.ptr -> i64
+// CHECK: %[[SIZE:.*]] = ptr.load %[[SIZE_PTR]] : !llvm.ptr -> i64
 
-// CHECK32: %[[SIZE:.*]] = llvm.load %{{.*}} : !llvm.ptr -> i32
+// CHECK32: %[[SIZE:.*]] = ptr.load %{{.*}} : !llvm.ptr -> i32
 
 // -----
 
 // CHECK-LABEL: func @address_space(
 func.func @address_space(%arg0 : memref<32xf32, affine_map<(d0) -> (d0)>, 7>) {
   // CHECK: %[[MEMORY:.*]] = llvm.call @malloc(%{{.*}})
-  // CHECK: %[[CAST:.*]] = llvm.addrspacecast %[[MEMORY]] : !llvm.ptr to !llvm.ptr<5>
+  // CHECK: %[[CAST:.*]] = ptr.addrspacecast %[[MEMORY]] : !llvm.ptr to !llvm.ptr<5>
   // CHECK: llvm.insertvalue %[[CAST]], %{{[[:alnum:]]+}}[0]
   // CHECK: llvm.insertvalue %[[CAST]], %{{[[:alnum:]]+}}[1]
   %0 = memref.alloc() : memref<32xf32, affine_map<(d0) -> (d0)>, 5>
   %1 = arith.constant 7 : index
-  // CHECK: llvm.load %{{.*}} : !llvm.ptr<5> -> f32
+  // CHECK: ptr.load %{{.*}} : !llvm.ptr<5> -> f32
   %2 = memref.load %0[%1] : memref<32xf32, affine_map<(d0) -> (d0)>, 5>
   func.return
 }
@@ -270,7 +270,7 @@ func.func @get_gv0_memref() {
   // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @gv0 : !llvm.ptr
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ADDR]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x f32>
   // CHECK: %[[DEADBEEF:.*]] = llvm.mlir.constant(3735928559 : index) : i64
-  // CHECK: %[[DEADBEEFPTR:.*]] = llvm.inttoptr %[[DEADBEEF]] : i64 to !llvm.ptr
+  // CHECK: %[[DEADBEEFPTR:.*]] = ptr.inttoptr %[[DEADBEEF]] : i64 to !llvm.ptr
   // CHECK: llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: llvm.insertvalue %[[DEADBEEFPTR]], {{.*}}[0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: llvm.insertvalue %[[GEP]], {{.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
@@ -290,7 +290,7 @@ func.func @get_gv2_memref() {
   // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @gv2 : !llvm.ptr
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ADDR]][0, 0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x array<3 x f32>>
   // CHECK: %[[DEADBEEF:.*]] = llvm.mlir.constant(3735928559 : index) : i64
-  // CHECK: %[[DEADBEEFPTR:.*]] = llvm.inttoptr %[[DEADBEEF]] : i64 to !llvm.ptr
+  // CHECK: %[[DEADBEEFPTR:.*]] = ptr.inttoptr %[[DEADBEEF]] : i64 to !llvm.ptr
   // CHECK: llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
   // CHECK: llvm.insertvalue %[[DEADBEEFPTR]], {{.*}}[0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
   // CHECK: llvm.insertvalue %[[GEP]], {{.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
@@ -314,7 +314,7 @@ func.func @get_gv3_memref() {
   // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @gv3 : !llvm.ptr
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ADDR]][0] : (!llvm.ptr) -> !llvm.ptr, f32
   // CHECK: %[[DEADBEEF:.*]] = llvm.mlir.constant(3735928559 : index) : i64
-  // CHECK: %[[DEADBEEFPTR:.*]] = llvm.inttoptr %[[DEADBEEF]] : i64 to !llvm.ptr
+  // CHECK: %[[DEADBEEFPTR:.*]] = ptr.inttoptr %[[DEADBEEF]] : i64 to !llvm.ptr
   // CHECK: llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64)>
   // CHECK: llvm.insertvalue %[[DEADBEEFPTR]], {{.*}}[0] : !llvm.struct<(ptr, ptr, i64)>
   // CHECK: llvm.insertvalue %[[GEP]], {{.*}}[1] : !llvm.struct<(ptr, ptr, i64)>
@@ -378,23 +378,23 @@ func.func @rank_of_ranked(%ranked: memref<?xi32>) {
 // CHECK-LABEL: func @atomic_rmw
 func.func @atomic_rmw(%I : memref<10xi32>, %ival : i32, %F : memref<10xf32>, %fval : f32, %i : index) {
   memref.atomic_rmw assign %fval, %F[%i] : (f32, memref<10xf32>) -> f32
-  // CHECK: llvm.atomicrmw xchg %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw xchg %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw addi %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw add %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw add %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw maxs %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw max %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw max %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw mins %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw min %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw min %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw maxu %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw umax %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw umax %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw minu %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw umin %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw umin %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw addf %fval, %F[%i] : (f32, memref<10xf32>) -> f32
-  // CHECK: llvm.atomicrmw fadd %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw fadd %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw ori %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw _or %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw _or %{{.*}}, %{{.*}} acq_rel
   memref.atomic_rmw andi %ival, %I[%i] : (i32, memref<10xi32>) -> i32
-  // CHECK: llvm.atomicrmw _and %{{.*}}, %{{.*}} acq_rel
+  // CHECK: ptr.atomicrmw _and %{{.*}}, %{{.*}} acq_rel
   return
 }
 
@@ -414,7 +414,7 @@ func.func @atomic_rmw_with_offset(%I : memref<10xi32, strided<[1], offset: 5>>,
 // CHECK:        %[[OFFSET:.+]] = llvm.mlir.constant(5 : index) : i64
 // CHECK:        %[[OFFSET_PTR:.+]] = llvm.getelementptr %[[BASE_PTR]][%[[OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
 // CHECK:        %[[PTR:.+]] = llvm.getelementptr %[[OFFSET_PTR]][%[[INDEX]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
-// CHECK:        llvm.atomicrmw _and %[[PTR]], %[[ARG1]] acq_rel
+// CHECK:        ptr.atomicrmw _and %[[PTR]], %[[ARG1]] acq_rel
 
 // -----
 
@@ -426,13 +426,11 @@ func.func @generic_atomic_rmw(%I : memref<10xi32>, %i : index) {
   }
   llvm.return
 }
-// CHECK:        %[[INIT:.*]] = llvm.load %{{.*}} : !llvm.ptr -> i32
+// CHECK:        %[[INIT:.*]] = ptr.load %{{.*}} : !llvm.ptr -> i32
 // CHECK-NEXT:   llvm.br ^bb1(%[[INIT]] : i32)
 // CHECK-NEXT: ^bb1(%[[LOADED:.*]]: i32):
-// CHECK-NEXT:   %[[PAIR:.*]] = llvm.cmpxchg %{{.*}}, %[[LOADED]], %[[LOADED]]
+// CHECK-NEXT:   %[[NEW:.*]], %[[OK:.*]] = ptr.cmpxchg %{{.*}}, %[[LOADED]], %[[LOADED]]
 // CHECK-SAME:                      acq_rel monotonic : !llvm.ptr, i32
-// CHECK-NEXT:   %[[NEW:.*]] = llvm.extractvalue %[[PAIR]][0]
-// CHECK-NEXT:   %[[OK:.*]] = llvm.extractvalue %[[PAIR]][1]
 // CHECK-NEXT:   llvm.cond_br %[[OK]], ^bb2, ^bb1(%[[NEW]] : i32)
 
 // -----
@@ -452,13 +450,11 @@ func.func @generic_atomic_rmw_in_alloca_scope(){
 // CHECK:        %[[STACK_SAVE:.*]] = llvm.intr.stacksave : !llvm.ptr
 // CHECK-NEXT:   llvm.br ^bb1
 // CHECK:      ^bb1:
-// CHECK:        %[[INIT:.*]] = llvm.load %[[BUF:.*]] : !llvm.ptr -> i32
+// CHECK:        %[[INIT:.*]] = ptr.load %[[BUF:.*]] : !llvm.ptr -> i32
 // CHECK-NEXT:   llvm.br ^bb2(%[[INIT]] : i32)
 // CHECK-NEXT: ^bb2(%[[LOADED:.*]]: i32):
-// CHECK-NEXT:   %[[PAIR:.*]] = llvm.cmpxchg %[[BUF]], %[[LOADED]], %[[LOADED]]
+// CHECK-NEXT:   %[[NEW:.*]], %[[OK:.*]] = ptr.cmpxchg %[[BUF]], %[[LOADED]], %[[LOADED]]
 // CHECK-SAME:     acq_rel monotonic : !llvm.ptr, i32
-// CHECK-NEXT:   %[[NEW:.*]] = llvm.extractvalue %[[PAIR]][0]
-// CHECK-NEXT:   %[[OK:.*]] = llvm.extractvalue %[[PAIR]][1]
 // CHECK-NEXT:   llvm.cond_br %[[OK]], ^bb3, ^bb2(%[[NEW]] : i32)
 // CHECK-NEXT: ^bb3:
 // CHECK-NEXT:   llvm.intr.stackrestore %[[STACK_SAVE]] : !llvm.ptr
@@ -484,7 +480,7 @@ func.func @memref_copy_ranked() {
   // CHECK: [[MUL:%.*]] = llvm.mul [[ONE]], [[EXTRACT0]] : i64
   // CHECK: [[NULL:%.*]] = llvm.mlir.zero : !llvm.ptr
   // CHECK: [[GEP:%.*]] = llvm.getelementptr [[NULL]][1] : (!llvm.ptr) -> !llvm.ptr, f32
-  // CHECK: [[PTRTOINT:%.*]] = llvm.ptrtoint [[GEP]] : !llvm.ptr to i64
+  // CHECK: [[PTRTOINT:%.*]] = ptr.ptrtoint [[GEP]] : !llvm.ptr to i64
   // CHECK: [[SIZE:%.*]] = llvm.mul [[MUL]], [[PTRTOINT]] : i64
   // CHECK: [[EXTRACT1P:%.*]] = llvm.extractvalue {{%.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
   // CHECK: [[EXTRACT1O:%.*]] = llvm.extractvalue {{%.*}}[2] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
@@ -515,7 +511,7 @@ func.func @memref_copy_contiguous(%in: memref<16x4xi32>, %offset: index) {
   // CHECK: [[MUL2:%.*]] = llvm.mul [[MUL1]], [[EXTRACT1]] : i64
   // CHECK: [[NULL:%.*]] = llvm.mlir.zero : !llvm.ptr
   // CHECK: [[GEP:%.*]] = llvm.getelementptr [[NULL]][1] : (!llvm.ptr) -> !llvm.ptr, i32
-  // CHECK: [[PTRTOINT:%.*]] = llvm.ptrtoint [[GEP]] : !llvm.ptr to i64
+  // CHECK: [[PTRTOINT:%.*]] = ptr.ptrtoint [[GEP]] : !llvm.ptr to i64
   // CHECK: [[SIZE:%.*]] = llvm.mul [[MUL2]], [[PTRTOINT]] : i64
   // CHECK: [[EXTRACT1P:%.*]] = llvm.extractvalue {{%.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
   // CHECK: [[EXTRACT1O:%.*]] = llvm.extractvalue {{%.*}}[2] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
@@ -565,7 +561,7 @@ func.func @memref_copy_unranked() {
   memref.copy %1, %3 : memref<*xi1> to memref<*xi1>
   // CHECK: [[ONE:%.*]] = llvm.mlir.constant(1 : index) : i64
   // CHECK: [[ALLOCA:%.*]] = llvm.alloca [[ONE]] x !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> : (i64) -> !llvm.ptr
-  // CHECK: llvm.store {{%.*}}, [[ALLOCA]] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, !llvm.ptr
+  // CHECK: ptr.store {{%.*}}, [[ALLOCA]] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, !llvm.ptr
   // CHECK: [[RANK:%.*]] = llvm.mlir.constant(1 : index) : i64
   // CHECK: [[UNDEF:%.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr)>
   // CHECK: [[INSERT:%.*]] = llvm.insertvalue [[RANK]], [[UNDEF]][0] : !llvm.struct<(i64, ptr)>
@@ -573,11 +569,11 @@ func.func @memref_copy_unranked() {
   // CHECK: [[STACKSAVE:%.*]] = llvm.intr.stacksave : !llvm.ptr
   // CHECK: [[RANK2:%.*]] = llvm.mlir.constant(1 : index) : i64
   // CHECK: [[ALLOCA2:%.*]] = llvm.alloca [[RANK2]] x !llvm.struct<(i64, ptr)> : (i64) -> !llvm.ptr
-  // CHECK: llvm.store {{%.*}}, [[ALLOCA2]] : !llvm.struct<(i64, ptr)>, !llvm.ptr
+  // CHECK: ptr.store {{%.*}}, [[ALLOCA2]] : !llvm.struct<(i64, ptr)>, !llvm.ptr
   // CHECK: [[ALLOCA3:%.*]] = llvm.alloca [[RANK2]] x !llvm.struct<(i64, ptr)> : (i64) -> !llvm.ptr
-  // CHECK: llvm.store [[INSERT2]], [[ALLOCA3]] : !llvm.struct<(i64, ptr)>, !llvm.ptr
+  // CHECK: ptr.store [[INSERT2]], [[ALLOCA3]] : !llvm.struct<(i64, ptr)>, !llvm.ptr
   // CHECK: [[SIZEPTR:%.*]] = llvm.getelementptr {{%.*}}[1] : (!llvm.ptr) -> !llvm.ptr, i1
-  // CHECK: [[SIZE:%.*]] = llvm.ptrtoint [[SIZEPTR]] : !llvm.ptr to i64
+  // CHECK: [[SIZE:%.*]] = ptr.ptrtoint [[SIZEPTR]] : !llvm.ptr to i64
   // CHECK: llvm.call @memrefCopy([[SIZE]], [[ALLOCA2]], [[ALLOCA3]]) : (i64, !llvm.ptr, !llvm.ptr) -> ()
   // CHECK: llvm.intr.stackrestore [[STACKSAVE]]
   return
@@ -589,7 +585,7 @@ func.func @memref_copy_unranked() {
 func.func @extract_aligned_pointer_as_index(%m: memref<?xf32>) -> index {
   %0 = memref.extract_aligned_pointer_as_index %m: memref<?xf32> -> index
   // CHECK: %[[E:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
-  // CHECK: %[[I64:.*]] = llvm.ptrtoint %[[E]] : !llvm.ptr to i64
+  // CHECK: %[[I64:.*]] = ptr.ptrtoint %[[E]] : !llvm.ptr to i64
   // CHECK: %[[R:.*]] = builtin.unrealized_conversion_cast %[[I64]] : i64 to index
 
   // CHECK: return %[[R:.*]] : index
@@ -630,7 +626,7 @@ func.func @extract_strided_metadata(
 // CHECK-LABEL: func @load_non_temporal(
 func.func @load_non_temporal(%arg0 : memref<32xf32, affine_map<(d0) -> (d0)>>) {
   %1 = arith.constant 7 : index
-  // CHECK: llvm.load %{{.*}} {nontemporal} : !llvm.ptr -> f32
+  // CHECK: ptr.load %{{.*}} {nontemporal} : !llvm.ptr -> f32
   %2 = memref.load %arg0[%1] {nontemporal = true} : memref<32xf32, affine_map<(d0) -> (d0)>>
   func.return
 }
@@ -641,7 +637,7 @@ func.func @load_non_temporal(%arg0 : memref<32xf32, affine_map<(d0) -> (d0)>>) {
 func.func @store_non_temporal(%input : memref<32xf32, affine_map<(d0) -> (d0)>>, %output : memref<32xf32, affine_map<(d0) -> (d0)>>) {
   %1 = arith.constant 7 : index
   %2 = memref.load %input[%1] {nontemporal = true} : memref<32xf32, affine_map<(d0) -> (d0)>>
-  // CHECK: llvm.store %{{.*}}, %{{.*}}  {nontemporal} : f32, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}}  {nontemporal} : f32, !llvm.ptr
   memref.store %2, %output[%1] {nontemporal = true} : memref<32xf32, affine_map<(d0) -> (d0)>>
   func.return
 }
diff --git a/mlir/test/Conversion/NVGPUToNVVM/nvgpu-to-nvvm.mlir b/mlir/test/Conversion/NVGPUToNVVM/nvgpu-to-nvvm.mlir
index dbf8ead49f78db..79f19d5bed877e 100644
--- a/mlir/test/Conversion/NVGPUToNVVM/nvgpu-to-nvvm.mlir
+++ b/mlir/test/Conversion/NVGPUToNVVM/nvgpu-to-nvvm.mlir
@@ -237,7 +237,7 @@ func.func @async_cp(
   // CHECK-DAG: %[[FI3:.*]] = llvm.mul %[[IDX1]], %[[S3]]  : i64
   // CHECK-DAG: %[[FI4:.*]] = llvm.add %[[FI3]], %[[IDX1]]  : i64
   // CHECK-DAG: %[[ADDRESSSRC:.*]] = llvm.getelementptr %[[BASESRC]][%[[FI4]]] : (!llvm.ptr, i64) -> !llvm.ptr
-  // CHECK-DAG: %[[CAST2:.*]] = llvm.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
+  // CHECK-DAG: %[[CAST2:.*]] = ptr.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
   // CHECK-DAG: nvvm.cp.async.shared.global %[[ADDRESSDST]], %[[CAST2]], 16, cache = ca
   %0 = nvgpu.device_async_copy %src[%i, %i], %dst[%i, %i, %i], 4 : memref<128x128xf32> to memref<3x16x128xf32, 3>
   // CHECK: nvvm.cp.async.commit.group
@@ -265,7 +265,7 @@ func.func @async_cp_i4(
   // CHECK-DAG: %[[FI2:.*]] = llvm.mul %[[IDX1]], %[[S2]]  : i64
   // CHECK-DAG: %[[FI3:.*]] = llvm.add %[[FI2]], %[[IDX1]]  : i64
   // CHECK-DAG: %[[ADDRESSSRC:.*]] = llvm.getelementptr %[[BASESRC]][%[[FI3]]] : (!llvm.ptr, i64) -> !llvm.ptr
-  // CHECK-DAG: %[[CAST2:.*]] = llvm.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
+  // CHECK-DAG: %[[CAST2:.*]] = ptr.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
   // CHECK-DAG: nvvm.cp.async.shared.global %[[ADDRESSDST]], %[[CAST2]], 16, cache = ca
   %0 = nvgpu.device_async_copy %src[%i, %i], %dst[%i, %i], 32 : memref<128x64xi4> to memref<128x128xi4, 3>
   return %0 : !nvgpu.device.async.token
@@ -290,7 +290,7 @@ func.func @async_cp_zfill_f32_align4(
   // CHECK-DAG: %[[FI2:.*]] = llvm.mul %[[IDX1]], %[[S2]]  : i64
   // CHECK-DAG: %[[FI3:.*]] = llvm.add %[[FI2]], %[[IDX1]]  : i64
   // CHECK-DAG: %[[ADDRESSSRC:.*]] = llvm.getelementptr %[[BASESRC]][%[[FI3]]] : (!llvm.ptr, i64) -> !llvm.ptr
-  // CHECK-DAG: %[[CAST2:.*]] = llvm.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
+  // CHECK-DAG: %[[CAST2:.*]] = ptr.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
   // CHECK-DAG: %[[c1:.*]] = llvm.mlir.constant(3 : i32) : i32
   // CHECK-DAG: %[[c2:.*]] = llvm.mlir.constant(32 : i32) : i32
   // CHECK-DAG: %[[c3:.*]] = llvm.trunc %[[SRC1]] : i64 to i32  
@@ -325,7 +325,7 @@ func.func @async_cp_zfill_f32_align1(
   // CHECK-DAG: %[[FI2:.*]] = llvm.mul %[[IDX1]], %[[S2]]  : i64
   // CHECK-DAG: %[[FI3:.*]] = llvm.add %[[FI2]], %[[IDX1]]  : i64
   // CHECK-DAG: %[[ADDRESSSRC:.*]] = llvm.getelementptr %[[BASESRC]][%[[FI3]]] : (!llvm.ptr, i64) -> !llvm.ptr
-  // CHECK-DAG: %[[CAST2:.*]] = llvm.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
+  // CHECK-DAG: %[[CAST2:.*]] = ptr.addrspacecast %[[ADDRESSSRC]] : !llvm.ptr to !llvm.ptr<1>
   // CHECK-DAG: %[[c1:.*]] = llvm.mlir.constant(3 : i32) : i32
   // CHECK-DAG: %[[c2:.*]] = llvm.mlir.constant(32 : i32) : i32
   // CHECK-DAG: %[[c3:.*]] = llvm.trunc %[[SRC1]] : i64 to i32  
@@ -835,7 +835,7 @@ func.func @create_wgmma_descriptor(%tensorMap : !tensorMap) -> !nvgpu.warpgroup.
     // CHECK: %[[c64:.+]] =  llvm.mlir.constant(64 : i64) : i64
     // CHECK: %[[c1024:.+]] = llvm.mlir.constant(1024 : i64) : i64
     // CHECK: %[[S2:.+]] = llvm.extractvalue %[[S1]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> 
-    // CHECK: %[[S3:.+]] = llvm.ptrtoint %[[S2]] : !llvm.ptr<3> to i64
+    // CHECK: %[[S3:.+]] = ptr.ptrtoint %[[S2]] : !llvm.ptr<3> to i64
     // CHECK: %[[S4:.+]] = llvm.mlir.constant(46 : i64) : i64
     // CHECK: %[[S5:.+]] = llvm.shl %[[S3]], %[[S4]]  : i64
     // CHECK: %[[S6:.+]] = llvm.mlir.constant(50 : i64) : i64
@@ -1331,7 +1331,7 @@ module attributes {transform.with_named_sequence} {
     } with type_converter {
       transform.apply_conversion_patterns.memref.memref_to_llvm_type_converter
         {use_opaque_pointers = true}
-    } {legal_dialects = ["arith", "func", "llvm", "memref", "nvvm", "vector", "scf"], partial_conversion} : !transform.any_op
+    } {legal_dialects = ["arith", "func", "ptr", "llvm", "memref", "nvvm", "vector", "scf"], partial_conversion} : !transform.any_op
     transform.yield
   }
 }
diff --git a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
index dc5d6969ca7896..34ae0a9d1cad42 100644
--- a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
+++ b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
@@ -223,7 +223,7 @@ llvm.func @_QPomp_target_data(%a : !llvm.ptr, %b : !llvm.ptr, %c : !llvm.ptr, %d
 // CHECK: %[[MAP_0:.*]] = omp.map.info var_ptr(%[[ARG0]] : !llvm.ptr, !llvm.array<1024 x i32>)  map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
 // CHECK: omp.target_data map_entries(%[[MAP_0]] : !llvm.ptr) {
 // CHECK:           %[[VAL_1:.*]] = llvm.mlir.constant(10 : i32) : i32
-// CHECK:           llvm.store %[[VAL_1]], %[[ARG1]] : i32, !llvm.ptr
+// CHECK:           ptr.store %[[VAL_1]], %[[ARG1]] : i32, !llvm.ptr
 // CHECK:           omp.terminator
 // CHECK:         }
 // CHECK:         llvm.return
@@ -232,7 +232,7 @@ llvm.func @_QPomp_target_data_region(%a : !llvm.ptr, %i : !llvm.ptr) {
   %1 = omp.map.info var_ptr(%a : !llvm.ptr, !llvm.array<1024 x i32>)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
   omp.target_data map_entries(%1 : !llvm.ptr) {
     %2 = llvm.mlir.constant(10 : i32) : i32
-    llvm.store %2, %i : i32, !llvm.ptr
+    ptr.store %2, %i : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -249,7 +249,7 @@ llvm.func @_QPomp_target_data_region(%a : !llvm.ptr, %i : !llvm.ptr) {
 // CHECK:           omp.target   thread_limit(%[[VAL_0]] : i32) map_entries(%[[MAP1]] -> %[[BB_ARG0:.*]], %[[MAP2]] -> %[[BB_ARG1:.*]] : !llvm.ptr, !llvm.ptr) {
 // CHECK:           ^bb0(%[[BB_ARG0]]: !llvm.ptr, %[[BB_ARG1]]: !llvm.ptr):
 // CHECK:             %[[VAL_1:.*]] = llvm.mlir.constant(10 : i32) : i32
-// CHECK:             llvm.store %[[VAL_1]], %[[BB_ARG1]] : i32, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_1]], %[[BB_ARG1]] : i32, !llvm.ptr
 // CHECK:             omp.terminator
 // CHECK:           }
 // CHECK:           llvm.return
@@ -262,7 +262,7 @@ llvm.func @_QPomp_target(%a : !llvm.ptr, %i : !llvm.ptr) {
   omp.target   thread_limit(%0 : i32) map_entries(%1 -> %arg0, %3 -> %arg1 : !llvm.ptr, !llvm.ptr) {
     ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
     %2 = llvm.mlir.constant(10 : i32) : i32
-    llvm.store %2, %arg1 : i32, !llvm.ptr
+    ptr.store %2, %arg1 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -321,10 +321,10 @@ llvm.func @_QPsb() {
 // CHECK:    %[[RED_ACCUMULATOR:.*]] = llvm.alloca %{{.*}} x i32 {bindc_name = "x", uniq_name = "_QFsimple_reductionEx"} : (i64) -> !llvm.ptr
 // CHECK:    omp.parallel
 // CHECK:      omp.wsloop reduction(@eqv_reduction %{{.+}} -> %[[PRV:.+]] : !llvm.ptr) for
-// CHECK:        %[[LPRV:.+]] = llvm.load %[[PRV]] : !llvm.ptr -> i32
+// CHECK:        %[[LPRV:.+]] = ptr.load %[[PRV]] : !llvm.ptr -> i32
 // CHECK:        %[[CMP:.+]] = llvm.icmp "eq" %{{.*}}, %[[LPRV]] : i32
 // CHECK:        %[[ZEXT:.+]] = llvm.zext %[[CMP]] : i1 to i32
-// CHECK:        llvm.store %[[ZEXT]], %[[PRV]] : i32, !llvm.ptr
+// CHECK:        ptr.store %[[ZEXT]], %[[PRV]] : i32, !llvm.ptr
 // CHECK:        omp.yield
 // CHECK:      omp.terminator
 // CHECK:    llvm.return
@@ -350,20 +350,20 @@ llvm.func @_QPsimple_reduction(%arg0: !llvm.ptr {fir.bindc_name = "y"}) {
   %3 = llvm.mlir.constant(1 : i64) : i64
   %4 = llvm.alloca %3 x i32 {bindc_name = "x", uniq_name = "_QFsimple_reductionEx"} : (i64) -> !llvm.ptr
   %5 = llvm.zext %2 : i1 to i32
-  llvm.store %5, %4 : i32, !llvm.ptr
+  ptr.store %5, %4 : i32, !llvm.ptr
   omp.parallel   {
     %6 = llvm.alloca %3 x i32 {adapt.valuebyref, in_type = i32, operandSegmentSizes = array<i32: 0, 0>, pinned} : (i64) -> !llvm.ptr
     omp.wsloop   reduction(@eqv_reduction %4 -> %prv : !llvm.ptr) for  (%arg1) : i32 = (%1) to (%0) inclusive step (%1) {
-      llvm.store %arg1, %6 : i32, !llvm.ptr
-      %7 = llvm.load %6 : !llvm.ptr -> i32
+      ptr.store %arg1, %6 : i32, !llvm.ptr
+      %7 = ptr.load %6 : !llvm.ptr -> i32
       %8 = llvm.sext %7 : i32 to i64
       %9 = llvm.sub %8, %3  : i64
       %10 = llvm.getelementptr %arg0[0, %9] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<100 x i32>
-      %11 = llvm.load %10 : !llvm.ptr -> i32
-      %12 = llvm.load %prv : !llvm.ptr -> i32
+      %11 = ptr.load %10 : !llvm.ptr -> i32
+      %12 = ptr.load %prv : !llvm.ptr -> i32
       %13 = llvm.icmp "eq" %11, %12 : i32
       %14 = llvm.zext %13 : i1 to i32
-      llvm.store %14, %prv : i32, !llvm.ptr
+      ptr.store %14, %prv : i32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -388,7 +388,7 @@ llvm.func @_QQmain() {
     %8 = llvm.icmp "sgt" %7, %0 : i64
     llvm.cond_br %8, ^bb2, ^bb3
   ^bb2:  // pred: ^bb1
-    llvm.store %6, %4 : i32, !llvm.ptr
+    ptr.store %6, %4 : i32, !llvm.ptr
 // CHECK: omp.task
     omp.task   {
 // CHECK: llvm.call @[[CALL_FUNC:.*]]({{.*}}) :
@@ -396,12 +396,12 @@ llvm.func @_QQmain() {
 // CHECK: omp.terminator
       omp.terminator
     }
-    %9 = llvm.load %4 : !llvm.ptr -> i32
+    %9 = ptr.load %4 : !llvm.ptr -> i32
     %10 = llvm.add %9, %5  : i32
     %11 = llvm.sub %7, %2  : i64
     llvm.br ^bb1(%10, %11 : i32, i64)
   ^bb3:  // pred: ^bb1
-    llvm.store %6, %4 : i32, !llvm.ptr
+    ptr.store %6, %4 : i32, !llvm.ptr
 // CHECK: omp.terminator
     omp.terminator
   }
@@ -428,15 +428,15 @@ llvm.func @sub_() {
     %7 = llvm.icmp "sgt" %6, %0 : i64
     llvm.cond_br %7, ^bb2, ^bb3
   ^bb2:  // pred: ^bb1
-    llvm.store %5, %3 : i32, !llvm.ptr
-    %8 = llvm.load %3 : !llvm.ptr -> i32
+    ptr.store %5, %3 : i32, !llvm.ptr
+    %8 = ptr.load %3 : !llvm.ptr -> i32
 // CHECK: llvm.add
     %9 = arith.addi %8, %4 : i32
 // CHECK: llvm.sub
     %10 = arith.subi %6, %1 : i64
     llvm.br ^bb1(%9, %10 : i32, i64)
   ^bb3:  // pred: ^bb1
-    llvm.store %5, %3 : i32, !llvm.ptr
+    ptr.store %5, %3 : i32, !llvm.ptr
 // CHECK: omp.terminator
     omp.terminator
   }
diff --git a/mlir/test/Conversion/SCFToOpenMP/reductions.mlir b/mlir/test/Conversion/SCFToOpenMP/reductions.mlir
index 3b6c145d62f1a8..0a6c1606f02912 100644
--- a/mlir/test/Conversion/SCFToOpenMP/reductions.mlir
+++ b/mlir/test/Conversion/SCFToOpenMP/reductions.mlir
@@ -13,8 +13,8 @@
 
 // CHECK: atomic
 // CHECK: ^{{.*}}(%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr):
-// CHECK: %[[RHS:.*]] = llvm.load %[[ARG1]] : !llvm.ptr -> f32
-// CHECK: llvm.atomicrmw fadd %[[ARG0]], %[[RHS]] monotonic
+// CHECK: %[[RHS:.*]] = ptr.load %[[ARG1]] : !llvm.ptr -> f32
+// CHECK: ptr.atomicrmw fadd %[[ARG0]], %[[RHS]] monotonic
 
 // CHECK-LABEL: @reduction1
 func.func @reduction1(%arg0 : index, %arg1 : index, %arg2 : index,
@@ -22,7 +22,7 @@ func.func @reduction1(%arg0 : index, %arg1 : index, %arg2 : index,
   // CHECK: %[[CST:.*]] = arith.constant 0.0
   // CHECK: %[[ONE:.*]] = llvm.mlir.constant(1
   // CHECK: %[[BUF:.*]] = llvm.alloca %[[ONE]] x f32
-  // CHECK: llvm.store %[[CST]], %[[BUF]]
+  // CHECK: ptr.store %[[CST]], %[[BUF]]
   %step = arith.constant 1 : index
   %zero = arith.constant 0.0 : f32
   // CHECK: omp.parallel
@@ -33,9 +33,9 @@ func.func @reduction1(%arg0 : index, %arg1 : index, %arg2 : index,
                             step (%arg4, %step) init (%zero) -> (f32) {
     // CHECK: %[[CST_INNER:.*]] = arith.constant 1.0
     %one = arith.constant 1.0 : f32
-    // CHECK: %[[PVT_VAL:.*]] = llvm.load %[[PVT_BUF]] : !llvm.ptr -> f32
+    // CHECK: %[[PVT_VAL:.*]] = ptr.load %[[PVT_BUF]] : !llvm.ptr -> f32
     // CHECK: %[[ADD_RESULT:.*]] = arith.addf %[[PVT_VAL]], %[[CST_INNER]] : f32
-    // CHECK: llvm.store %[[ADD_RESULT]], %[[PVT_BUF]] : f32, !llvm.ptr
+    // CHECK: ptr.store %[[ADD_RESULT]], %[[PVT_BUF]] : f32, !llvm.ptr
     scf.reduce(%one : f32) {
     ^bb0(%lhs : f32, %rhs: f32):
       %res = arith.addf %lhs, %rhs : f32
@@ -44,7 +44,7 @@ func.func @reduction1(%arg0 : index, %arg1 : index, %arg2 : index,
     // CHECK: omp.yield
   }
   // CHECK: omp.terminator
-  // CHECK: llvm.load %[[BUF]]
+  // CHECK: ptr.load %[[BUF]]
   return
 }
 
@@ -111,9 +111,9 @@ func.func @reduction_muli(%arg0 : index, %arg1 : index, %arg2 : index,
                             step (%arg4, %step) init (%one) -> (i32) {
     // CHECK: %[[C2:.*]] = arith.constant 2 : i32
     %pow2 = arith.constant 2 : i32
-    // CHECK: %[[RED_PVT_VAL:.*]] = llvm.load %[[RED_PVT_VAR]] : !llvm.ptr -> i32
+    // CHECK: %[[RED_PVT_VAL:.*]] = ptr.load %[[RED_PVT_VAR]] : !llvm.ptr -> i32
     // CHECK: %[[MUL_RESULT:.*]] = arith.muli %[[RED_PVT_VAL]], %[[C2]] : i32
-    // CHECK: llvm.store %[[MUL_RESULT]], %[[RED_PVT_VAR]] : i32, !llvm.ptr
+    // CHECK: ptr.store %[[MUL_RESULT]], %[[RED_PVT_VAR]] : i32, !llvm.ptr
     scf.reduce(%pow2 : i32) {
     ^bb0(%lhs : i32, %rhs: i32):
       %res = arith.muli %lhs, %rhs : i32
@@ -188,8 +188,8 @@ func.func @reduction3(%arg0 : index, %arg1 : index, %arg2 : index,
 
 // CHECK: atomic
 // CHECK: ^{{.*}}(%[[ARG0:.*]]: !llvm.ptr, %[[ARG1:.*]]: !llvm.ptr):
-// CHECK: %[[RHS:.*]] = llvm.load %[[ARG1]] : !llvm.ptr -> i64
-// CHECK: llvm.atomicrmw max %[[ARG0]], %[[RHS]] monotonic
+// CHECK: %[[RHS:.*]] = ptr.load %[[ARG1]] : !llvm.ptr -> i64
+// CHECK: ptr.atomicrmw max %[[ARG0]], %[[RHS]] monotonic
 
 // CHECK-LABEL: @reduction4
 func.func @reduction4(%arg0 : index, %arg1 : index, %arg2 : index,
@@ -200,9 +200,9 @@ func.func @reduction4(%arg0 : index, %arg1 : index, %arg2 : index,
   // CHECK: %[[IONE:.*]] = arith.constant 1
   %ione = arith.constant 1 : i64
   // CHECK: %[[BUF1:.*]] = llvm.alloca %{{.*}} x f32
-  // CHECK: llvm.store %[[ZERO]], %[[BUF1]]
+  // CHECK: ptr.store %[[ZERO]], %[[BUF1]]
   // CHECK: %[[BUF2:.*]] = llvm.alloca %{{.*}} x i64
-  // CHECK: llvm.store %[[IONE]], %[[BUF2]]
+  // CHECK: ptr.store %[[IONE]], %[[BUF2]]
 
   // CHECK: omp.parallel
   // CHECK: omp.wsloop
@@ -215,14 +215,14 @@ func.func @reduction4(%arg0 : index, %arg1 : index, %arg2 : index,
     %one = arith.constant 1.0 : f32
     // CHECK: %[[CST_INT_ONE:.*]] = arith.fptosi
     %1 = arith.fptosi %one : f32 to i64
-    // CHECK: %[[PVT_VAL1:.*]] = llvm.load %[[PVT_BUF1]] : !llvm.ptr -> f32
+    // CHECK: %[[PVT_VAL1:.*]] = ptr.load %[[PVT_BUF1]] : !llvm.ptr -> f32
     // CHECK: %[[TEMP1:.*]] = arith.cmpf oge, %[[PVT_VAL1]], %[[CST_ONE]] : f32
     // CHECK: %[[CMP_VAL1:.*]] = arith.select %[[TEMP1]], %[[PVT_VAL1]], %[[CST_ONE]] : f32
-    // CHECK: llvm.store %[[CMP_VAL1]], %[[PVT_BUF1]] : f32, !llvm.ptr
-    // CHECK: %[[PVT_VAL2:.*]] = llvm.load %[[PVT_BUF2]] : !llvm.ptr -> i64
+    // CHECK: ptr.store %[[CMP_VAL1]], %[[PVT_BUF1]] : f32, !llvm.ptr
+    // CHECK: %[[PVT_VAL2:.*]] = ptr.load %[[PVT_BUF2]] : !llvm.ptr -> i64
     // CHECK: %[[TEMP2:.*]] = arith.cmpi slt, %[[PVT_VAL2]], %[[CST_INT_ONE]] : i64
     // CHECK: %[[CMP_VAL2:.*]] = arith.select %[[TEMP2]], %[[CST_INT_ONE]], %[[PVT_VAL2]] : i64
-    // CHECK: llvm.store %[[CMP_VAL2]], %[[PVT_BUF2]] : i64, !llvm.ptr
+    // CHECK: ptr.store %[[CMP_VAL2]], %[[PVT_BUF2]] : i64, !llvm.ptr
     scf.reduce(%one, %1 : f32, i64) {
     ^bb0(%lhs : f32, %rhs: f32):
       %cmp = arith.cmpf oge, %lhs, %rhs : f32
@@ -237,8 +237,8 @@ func.func @reduction4(%arg0 : index, %arg1 : index, %arg2 : index,
     // CHECK: omp.yield
   }
   // CHECK: omp.terminator
-  // CHECK: %[[RES1:.*]] = llvm.load %[[BUF1]] : !llvm.ptr -> f32
-  // CHECK: %[[RES2:.*]] = llvm.load %[[BUF2]] : !llvm.ptr -> i64
+  // CHECK: %[[RES1:.*]] = ptr.load %[[BUF1]] : !llvm.ptr -> f32
+  // CHECK: %[[RES2:.*]] = ptr.load %[[BUF2]] : !llvm.ptr -> i64
   // CHECK: return %[[RES1]], %[[RES2]]
   return %res#0, %res#1 : f32, i64
 }
diff --git a/mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir b/mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir
index 1847975b279afa..1f8a35dd8e2361 100644
--- a/mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir
+++ b/mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir
@@ -94,7 +94,7 @@ spirv.module Logical GLSL450 {
 // CHECK-LABEL: @load
 spirv.func @load() "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  //  CHECK: llvm.load %{{.*}} : !llvm.ptr -> f32
+  //  CHECK: ptr.load %{{.*}} : !llvm.ptr -> f32
   %1 = spirv.Load "Function" %0 : f32
   spirv.Return
 }
@@ -102,7 +102,7 @@ spirv.func @load() "None" {
 // CHECK-LABEL: @load_none
 spirv.func @load_none() "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  //  CHECK: llvm.load %{{.*}} : !llvm.ptr -> f32
+  //  CHECK: ptr.load %{{.*}} : !llvm.ptr -> f32
   %1 = spirv.Load "Function" %0 ["None"] : f32
   spirv.Return
 }
@@ -110,7 +110,7 @@ spirv.func @load_none() "None" {
 // CHECK-LABEL: @load_with_alignment
 spirv.func @load_with_alignment() "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.load %{{.*}} {alignment = 4 : i64} : !llvm.ptr -> f32
+  // CHECK: ptr.load %{{.*}} {alignment = 4 : i64} : !llvm.ptr -> f32
   %1 = spirv.Load "Function" %0 ["Aligned", 4] : f32
   spirv.Return
 }
@@ -118,7 +118,7 @@ spirv.func @load_with_alignment() "None" {
 // CHECK-LABEL: @load_volatile
 spirv.func @load_volatile() "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.load volatile %{{.*}} : !llvm.ptr -> f32
+  // CHECK: ptr.load volatile %{{.*}} : !llvm.ptr -> f32
   %1 = spirv.Load "Function" %0 ["Volatile"] : f32
   spirv.Return
 }
@@ -126,7 +126,7 @@ spirv.func @load_volatile() "None" {
 // CHECK-LABEL: @load_nontemporal
 spirv.func @load_nontemporal() "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.load %{{.*}} {nontemporal} : !llvm.ptr -> f32
+  // CHECK: ptr.load %{{.*}} {nontemporal} : !llvm.ptr -> f32
   %1 = spirv.Load "Function" %0 ["Nontemporal"] : f32
   spirv.Return
 }
@@ -138,7 +138,7 @@ spirv.func @load_nontemporal() "None" {
 // CHECK-LABEL: @store
 spirv.func @store(%arg0 : f32) "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.store %{{.*}}, %{{.*}} : f32, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} : f32, !llvm.ptr
   spirv.Store "Function" %0, %arg0 : f32
   spirv.Return
 }
@@ -146,7 +146,7 @@ spirv.func @store(%arg0 : f32) "None" {
 // CHECK-LABEL: @store_composite
 spirv.func @store_composite(%arg0 : !spirv.struct<(f64)>) "None" {
   %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(f64)>, Function>
-  // CHECK: llvm.store %{{.*}}, %{{.*}} : !llvm.struct<packed (f64)>, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} : !llvm.struct<packed (f64)>, !llvm.ptr
   spirv.Store "Function" %0, %arg0 : !spirv.struct<(f64)>
   spirv.Return
 }
@@ -154,7 +154,7 @@ spirv.func @store_composite(%arg0 : !spirv.struct<(f64)>) "None" {
 // CHECK-LABEL: @store_with_alignment
 spirv.func @store_with_alignment(%arg0 : f32) "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.store %{{.*}}, %{{.*}} {alignment = 4 : i64} : f32, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} {alignment = 4 : i64} : f32, !llvm.ptr
   spirv.Store "Function" %0, %arg0 ["Aligned", 4] : f32
   spirv.Return
 }
@@ -162,7 +162,7 @@ spirv.func @store_with_alignment(%arg0 : f32) "None" {
 // CHECK-LABEL: @store_volatile
 spirv.func @store_volatile(%arg0 : f32) "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.store volatile %{{.*}}, %{{.*}} : f32, !llvm.ptr
+  // CHECK: ptr.store volatile %{{.*}}, %{{.*}} : f32, !llvm.ptr
   spirv.Store "Function" %0, %arg0 ["Volatile"] : f32
   spirv.Return
 }
@@ -170,7 +170,7 @@ spirv.func @store_volatile(%arg0 : f32) "None" {
 // CHECK-LABEL: @store_nontemporal
 spirv.func @store_nontemporal(%arg0 : f32) "None" {
   %0 = spirv.Variable : !spirv.ptr<f32, Function>
-  // CHECK: llvm.store %{{.*}}, %{{.*}} {nontemporal} : f32, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} {nontemporal} : f32, !llvm.ptr
   spirv.Store "Function" %0, %arg0 ["Nontemporal"] : f32
   spirv.Return
 }
@@ -195,7 +195,7 @@ spirv.func @variable_scalar_with_initialization() "None" {
   // CHECK: %[[VALUE:.*]] = llvm.mlir.constant(0 : i64) : i64
   // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCATED:.*]] = llvm.alloca %[[SIZE]] x i64 : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[VALUE]], %[[ALLOCATED]] : i64, !llvm.ptr
+  // CHECK: ptr.store %[[VALUE]], %[[ALLOCATED]] : i64, !llvm.ptr
   %c = spirv.Constant 0 : i64
   %0 = spirv.Variable init(%c) : !spirv.ptr<i64, Function>
   spirv.Return
@@ -214,7 +214,7 @@ spirv.func @variable_vector_with_initialization() "None" {
   // CHECK: %[[VALUE:.*]] = llvm.mlir.constant(dense<false> : vector<3xi1>) : vector<3xi1>
   // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCATED:.*]] = llvm.alloca %[[SIZE]] x vector<3xi1> : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[VALUE]], %[[ALLOCATED]] : vector<3xi1>, !llvm.ptr
+  // CHECK: ptr.store %[[VALUE]], %[[ALLOCATED]] : vector<3xi1>, !llvm.ptr
   %c = spirv.Constant dense<false> : vector<3xi1>
   %0 = spirv.Variable init(%c) : !spirv.ptr<vector<3xi1>, Function>
   spirv.Return
diff --git a/mlir/test/Conversion/VectorToLLVM/vector-scalable-memcpy.mlir b/mlir/test/Conversion/VectorToLLVM/vector-scalable-memcpy.mlir
index 811b10721bf284..ab292efbe666d4 100644
--- a/mlir/test/Conversion/VectorToLLVM/vector-scalable-memcpy.mlir
+++ b/mlir/test/Conversion/VectorToLLVM/vector-scalable-memcpy.mlir
@@ -13,11 +13,11 @@ func.func @vector_scalable_memcopy(%src : memref<?xf32>, %dst : memref<?xf32>, %
     // CHECK: [[DATAIDX:%[0-9]+]] = builtin.unrealized_conversion_cast [[LOOPIDX]] : index to i64
     // CHECK: [[SRCMEM:%[0-9]+]] = llvm.extractvalue [[SRCMRS]][1] : !llvm.struct<(ptr
     // CHECK-NEXT: [[SRCPTR:%[0-9]+]] = llvm.getelementptr [[SRCMEM]]{{.}}[[DATAIDX]]{{.}} : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    // CHECK-NEXT: [[LDVAL:%[0-9]+]] = llvm.load [[SRCPTR]]{{.*}}: !llvm.ptr -> vector<[4]xf32>
+    // CHECK-NEXT: [[LDVAL:%[0-9]+]] = ptr.load [[SRCPTR]]{{.*}}: !llvm.ptr -> vector<[4]xf32>
     %0 = vector.load %src[%i0] : memref<?xf32>, vector<[4]xf32>
     // CHECK: [[DSTMEM:%[0-9]+]] = llvm.extractvalue [[DSTMRS]][1] : !llvm.struct<(ptr
     // CHECK-NEXT: [[DSTPTR:%[0-9]+]] = llvm.getelementptr [[DSTMEM]]{{.}}[[DATAIDX]]{{.}} : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    // CHECK-NEXT: llvm.store [[LDVAL]], [[DSTPTR]]{{.*}}: vector<[4]xf32>, !llvm.ptr
+    // CHECK-NEXT: ptr.store [[LDVAL]], [[DSTPTR]]{{.*}}: vector<[4]xf32>, !llvm.ptr
     vector.store %0, %dst[%i0] : memref<?xf32>, vector<[4]xf32>
   }
 
diff --git a/mlir/test/Conversion/VectorToLLVM/vector-to-llvm.mlir b/mlir/test/Conversion/VectorToLLVM/vector-to-llvm.mlir
index e94e51d49a98b7..2880136d05ed0e 100644
--- a/mlir/test/Conversion/VectorToLLVM/vector-to-llvm.mlir
+++ b/mlir/test/Conversion/VectorToLLVM/vector-to-llvm.mlir
@@ -1828,7 +1828,7 @@ func.func @transfer_read_1d_inbounds(%A : memref<?xf32>, %base: index) -> vector
 //  CHECK-SAME: (!llvm.ptr, i64) -> !llvm.ptr, f32
 //
 // 2. Rewrite as a load.
-//       CHECK: %[[loaded:.*]] = llvm.load %[[gep]] {alignment = 4 : i64} : !llvm.ptr -> vector<17xf32>
+//       CHECK: %[[loaded:.*]] = ptr.load %[[gep]] {alignment = 4 : i64} : !llvm.ptr -> vector<17xf32>
 
 // -----
 
@@ -2062,7 +2062,7 @@ func.func @vector_load_op(%memref : memref<200x100xf32>, %i : index, %j : index)
 // CHECK: %[[mul:.*]] = llvm.mul %{{.*}}, %[[c100]]  : i64
 // CHECK: %[[add:.*]] = llvm.add %[[mul]], %{{.*}}  : i64
 // CHECK: %[[gep:.*]] = llvm.getelementptr %{{.*}}[%[[add]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: llvm.load %[[gep]] {alignment = 4 : i64} : !llvm.ptr -> vector<8xf32>
+// CHECK: ptr.load %[[gep]] {alignment = 4 : i64} : !llvm.ptr -> vector<8xf32>
 
 // -----
 
@@ -2076,7 +2076,7 @@ func.func @vector_load_op_nontemporal(%memref : memref<200x100xf32>, %i : index,
 // CHECK: %[[mul:.*]] = llvm.mul %{{.*}}, %[[c100]]  : i64
 // CHECK: %[[add:.*]] = llvm.add %[[mul]], %{{.*}}  : i64
 // CHECK: %[[gep:.*]] = llvm.getelementptr %{{.*}}[%[[add]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: llvm.load %[[gep]] {alignment = 4 : i64, nontemporal} : !llvm.ptr -> vector<8xf32>
+// CHECK: ptr.load %[[gep]] {alignment = 4 : i64, nontemporal} : !llvm.ptr -> vector<8xf32>
 
 // -----
 
@@ -2085,7 +2085,7 @@ func.func @vector_load_op_index(%memref : memref<200x100xindex>, %i : index, %j
   return %0 : vector<8xindex>
 }
 // CHECK-LABEL: func @vector_load_op_index
-// CHECK: %[[T0:.*]] = llvm.load %{{.*}} {alignment = 8 : i64} : !llvm.ptr -> vector<8xi64>
+// CHECK: %[[T0:.*]] = ptr.load %{{.*}} {alignment = 8 : i64} : !llvm.ptr -> vector<8xi64>
 // CHECK: %[[T1:.*]] = builtin.unrealized_conversion_cast %[[T0]] : vector<8xi64> to vector<8xindex>
 // CHECK: return %[[T1]] : vector<8xindex>
 
@@ -2102,7 +2102,7 @@ func.func @vector_store_op(%memref : memref<200x100xf32>, %i : index, %j : index
 // CHECK: %[[mul:.*]] = llvm.mul %{{.*}}, %[[c100]]  : i64
 // CHECK: %[[add:.*]] = llvm.add %[[mul]], %{{.*}}  : i64
 // CHECK: %[[gep:.*]] = llvm.getelementptr %{{.*}}[%[[add]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: llvm.store %{{.*}}, %[[gep]] {alignment = 4 : i64} :  vector<4xf32>, !llvm.ptr
+// CHECK: ptr.store %{{.*}}, %[[gep]] {alignment = 4 : i64} :  vector<4xf32>, !llvm.ptr
 
 // -----
 
@@ -2117,7 +2117,7 @@ func.func @vector_store_op_nontemporal(%memref : memref<200x100xf32>, %i : index
 // CHECK: %[[mul:.*]] = llvm.mul %{{.*}}, %[[c100]]  : i64
 // CHECK: %[[add:.*]] = llvm.add %[[mul]], %{{.*}}  : i64
 // CHECK: %[[gep:.*]] = llvm.getelementptr %{{.*}}[%[[add]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-// CHECK: llvm.store %{{.*}}, %[[gep]] {alignment = 4 : i64, nontemporal} :  vector<4xf32>, !llvm.ptr
+// CHECK: ptr.store %{{.*}}, %[[gep]] {alignment = 4 : i64, nontemporal} :  vector<4xf32>, !llvm.ptr
 
 // -----
 
@@ -2127,7 +2127,7 @@ func.func @vector_store_op_index(%memref : memref<200x100xindex>, %i : index, %j
   return
 }
 // CHECK-LABEL: func @vector_store_op_index
-// CHECK: llvm.store %{{.*}}, %{{.*}} {alignment = 8 : i64} : vector<4xi64>, !llvm.ptr
+// CHECK: ptr.store %{{.*}}, %{{.*}} {alignment = 8 : i64} : vector<4xi64>, !llvm.ptr
 
 // -----
 
diff --git a/mlir/test/Dialect/LLVMIR/canonicalize.mlir b/mlir/test/Dialect/LLVMIR/canonicalize.mlir
index 5e26fa37b681d7..fd55a483546efc 100644
--- a/mlir/test/Dialect/LLVMIR/canonicalize.mlir
+++ b/mlir/test/Dialect/LLVMIR/canonicalize.mlir
@@ -105,7 +105,7 @@ llvm.func @fold_bitcast2(%x : i32) -> i32 {
 // CHECK-SAME: %[[a0:arg[0-9]+]]
 // CHECK-NEXT: llvm.return %[[a0]]
 llvm.func @fold_addrcast(%x : !llvm.ptr) -> !llvm.ptr {
-  %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr
+  %c = ptr.addrspacecast %x : !llvm.ptr to !llvm.ptr
   llvm.return %c : !llvm.ptr
 }
 
@@ -113,8 +113,8 @@ llvm.func @fold_addrcast(%x : !llvm.ptr) -> !llvm.ptr {
 // CHECK-SAME: %[[a0:arg[0-9]+]]
 // CHECK-NEXT: llvm.return %[[a0]]
 llvm.func @fold_addrcast2(%x : !llvm.ptr) -> !llvm.ptr {
-  %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr<5>
-  %d = llvm.addrspacecast %c : !llvm.ptr<5> to !llvm.ptr
+  %c = ptr.addrspacecast %x : !llvm.ptr to !llvm.ptr<5>
+  %d = ptr.addrspacecast %c : !llvm.ptr<5> to !llvm.ptr
   llvm.return %d : !llvm.ptr
 }
 
@@ -171,7 +171,7 @@ llvm.func @llvm_constant() -> i32 {
 // CHECK-LABEL: load_dce
 // CHECK-NEXT: llvm.return
 llvm.func @load_dce(%x : !llvm.ptr) {
-  %0 = llvm.load %x : !llvm.ptr -> i8
+  %0 = ptr.load %x : !llvm.ptr -> i8
   llvm.return
 }
 
@@ -198,13 +198,13 @@ llvm.func @alloca_dce() {
 llvm.func @volatile_load(%x : !llvm.ptr) {
   // A volatile load may have side-effects such as a write operation to arbitrary memory.
   // Make sure it is not removed.
-  // CHECK: llvm.load volatile
-  %0 = llvm.load volatile %x : !llvm.ptr -> i8
+  // CHECK: ptr.load volatile
+  %0 = ptr.load volatile %x : !llvm.ptr -> i8
   // Same with monotonic atomics and any stricter modes.
-  // CHECK: llvm.load %{{.*}} atomic monotonic
-  %2 = llvm.load %x atomic monotonic { alignment = 1 } : !llvm.ptr -> i8
+  // CHECK: ptr.load %{{.*}} atomic monotonic
+  %2 = ptr.load %x atomic monotonic { alignment = 1 } : !llvm.ptr -> i8
   // But not unordered!
-  // CHECK-NOT: llvm.load %{{.*}} atomic unordered
-  %3 = llvm.load %x  atomic unordered { alignment = 1 } : !llvm.ptr -> i8
+  // CHECK-NOT: ptr.load %{{.*}} atomic unordered
+  %3 = ptr.load %x  atomic unordered { alignment = 1 } : !llvm.ptr -> i8
   llvm.return
 }
diff --git a/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir b/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir
index 29450833bee598..2159a8b9eb4e1f 100644
--- a/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir
+++ b/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir
@@ -1,40 +1,40 @@
 // RUN: mlir-opt %s -inline -split-input-file | FileCheck %s
 
-#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "foo">
-#alias_scope = #llvm.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain, description = "foo load">
-#alias_scope1 = #llvm.alias_scope<id = distinct[2]<>, domain = #alias_scope_domain, description = "foo store">
+#alias_scope_domain = #ptr.alias_scope_domain<id = distinct[0]<>, description = "foo">
+#alias_scope = #ptr.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain, description = "foo load">
+#alias_scope1 = #ptr.alias_scope<id = distinct[2]<>, domain = #alias_scope_domain, description = "foo store">
 
-// CHECK-DAG: #[[FOO_DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$FOO_LOAD:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[FOO_DOMAIN]], description = {{.*}}>
-// CHECK-DAG: #[[$FOO_STORE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[FOO_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[FOO_DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$FOO_LOAD:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[FOO_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[$FOO_STORE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[FOO_DOMAIN]], description = {{.*}}>
 
-// CHECK-DAG: #[[BAR_DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$BAR_LOAD:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[BAR_DOMAIN]], description = {{.*}}>
-// CHECK-DAG: #[[$BAR_STORE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[BAR_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[BAR_DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$BAR_LOAD:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[BAR_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[$BAR_STORE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[BAR_DOMAIN]], description = {{.*}}>
 
 // CHECK-LABEL: llvm.func @foo
 // CHECK: llvm.intr.experimental.noalias.scope.decl #[[$FOO_LOAD]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$FOO_LOAD]]]
 // CHECK-SAME: noalias_scopes = [#[[$FOO_STORE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$FOO_STORE]]]
 // CHECK-SAME: noalias_scopes = [#[[$FOO_LOAD]]]
 llvm.func @foo(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   %0 = llvm.mlir.constant(5 : i64) : i64
   llvm.intr.experimental.noalias.scope.decl #alias_scope
-  %2 = llvm.load %arg1 {alias_scopes = [#alias_scope], alignment = 4 : i64, noalias_scopes = [#alias_scope1]} : !llvm.ptr -> f32
+  %2 = ptr.load %arg1 {alias_scopes = [#alias_scope], alignment = 4 : i64, noalias_scopes = [#alias_scope1]} : !llvm.ptr -> f32
   %3 = llvm.getelementptr inbounds %arg0[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %2, %3 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr
+  ptr.store %2, %3 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr
   llvm.return
 }
 
 // CHECK-LABEL: llvm.func @bar
 // CHECK: llvm.intr.experimental.noalias.scope.decl #[[$BAR_LOAD]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$BAR_LOAD]]]
 // CHECK-SAME: noalias_scopes = [#[[$BAR_STORE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$BAR_STORE]]]
 // CHECK-SAME: noalias_scopes = [#[[$BAR_LOAD]]]
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
@@ -44,52 +44,52 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "hello2">
-#alias_scope_domain1 = #llvm.alias_scope_domain<id = distinct[1]<>, description = "hello">
-#alias_scope = #llvm.alias_scope<id = distinct[2]<>, domain = #alias_scope_domain, description = "hello2: %a">
-#alias_scope1 = #llvm.alias_scope<id = distinct[3]<>, domain = #alias_scope_domain, description = "hello2: %b">
-#alias_scope2 = #llvm.alias_scope<id = distinct[4]<>, domain = #alias_scope_domain1, description = "hello: %a">
+#alias_scope_domain = #ptr.alias_scope_domain<id = distinct[0]<>, description = "hello2">
+#alias_scope_domain1 = #ptr.alias_scope_domain<id = distinct[1]<>, description = "hello">
+#alias_scope = #ptr.alias_scope<id = distinct[2]<>, domain = #alias_scope_domain, description = "hello2: %a">
+#alias_scope1 = #ptr.alias_scope<id = distinct[3]<>, domain = #alias_scope_domain, description = "hello2: %b">
+#alias_scope2 = #ptr.alias_scope<id = distinct[4]<>, domain = #alias_scope_domain1, description = "hello: %a">
 
-// CHECK-DAG: #[[WITH_DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$WITH_DOMAIN_SCOPE1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN]], description = {{.*}}>
-// CHECK-DAG: #[[$WITH_DOMAIN_SCOPE2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[WITH_DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$WITH_DOMAIN_SCOPE1:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[$WITH_DOMAIN_SCOPE2:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN]], description = {{.*}}>
 
-// CHECK-DAG: #[[CALL_DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$CALL_DOMAIN_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[CALL_DOMAIN]], description = {{.*}}>
+// CHECK-DAG: #[[CALL_DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$CALL_DOMAIN_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[CALL_DOMAIN]], description = {{.*}}>
 
-// CHECK-DAG: #[[WITH_DOMAIN_NO_ALIAS:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$WITH_DOMAIN_NO_ALIAS_SCOPE1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_NO_ALIAS]], description = {{.*}}>
-// CHECK-DAG: #[[$WITH_DOMAIN_NO_ALIAS_SCOPE2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_NO_ALIAS]], description = {{.*}}>
+// CHECK-DAG: #[[WITH_DOMAIN_NO_ALIAS:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$WITH_DOMAIN_NO_ALIAS_SCOPE1:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_NO_ALIAS]], description = {{.*}}>
+// CHECK-DAG: #[[$WITH_DOMAIN_NO_ALIAS_SCOPE2:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_NO_ALIAS]], description = {{.*}}>
 
-// CHECK-DAG: #[[WITH_DOMAIN_ALIAS:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$WITH_DOMAIN_ALIAS_SCOPE1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_ALIAS]], description = {{.*}}>
-// CHECK-DAG: #[[$WITH_DOMAIN_ALIAS_SCOPE2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_ALIAS]], description = {{.*}}>
+// CHECK-DAG: #[[WITH_DOMAIN_ALIAS:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$WITH_DOMAIN_ALIAS_SCOPE1:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_ALIAS]], description = {{.*}}>
+// CHECK-DAG: #[[$WITH_DOMAIN_ALIAS_SCOPE2:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[WITH_DOMAIN_ALIAS]], description = {{.*}}>
 
 // CHECK-LABEL: llvm.func @callee_with_metadata(
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_SCOPE1]], #[[$WITH_DOMAIN_SCOPE2]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$WITH_DOMAIN_SCOPE1]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_SCOPE2]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$WITH_DOMAIN_SCOPE2]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_SCOPE1]]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-NOT: {{(no)?}}alias_scopes =
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: {{(no)?}}alias_scopes =
 llvm.func @callee_with_metadata(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
   %0 = llvm.mlir.constant(5 : i64) : i64
   %1 = llvm.mlir.constant(8 : i64) : i64
   %2 = llvm.mlir.constant(7 : i64) : i64
-  %3 = llvm.load %arg2 {alignment = 4 : i64, noalias_scopes = [#alias_scope, #alias_scope1]} : !llvm.ptr -> f32
+  %3 = ptr.load %arg2 {alignment = 4 : i64, noalias_scopes = [#alias_scope, #alias_scope1]} : !llvm.ptr -> f32
   %4 = llvm.getelementptr inbounds %arg0[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %3, %4 {alias_scopes = [#alias_scope], alignment = 4 : i64, noalias_scopes = [#alias_scope1]} : f32, !llvm.ptr
+  ptr.store %3, %4 {alias_scopes = [#alias_scope], alignment = 4 : i64, noalias_scopes = [#alias_scope1]} : f32, !llvm.ptr
   %5 = llvm.getelementptr inbounds %arg1[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %3, %5 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr
-  %6 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32
+  ptr.store %3, %5 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr
+  %6 = ptr.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32
   %7 = llvm.getelementptr inbounds %arg0[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr
   llvm.return
 }
 
@@ -100,95 +100,95 @@ llvm.func @callee_without_metadata(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !l
   %0 = llvm.mlir.constant(5 : i64) : i64
   %1 = llvm.mlir.constant(8 : i64) : i64
   %2 = llvm.mlir.constant(7 : i64) : i64
-  %3 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32
+  %3 = ptr.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32
   %4 = llvm.getelementptr inbounds %arg0[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %3, %4 {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %3, %4 {alignment = 4 : i64} : f32, !llvm.ptr
   %5 = llvm.getelementptr inbounds %arg1[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %3, %5 {alignment = 4 : i64} : f32, !llvm.ptr
-  %6 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32
+  ptr.store %3, %5 {alignment = 4 : i64} : f32, !llvm.ptr
+  %6 = ptr.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32
   %7 = llvm.getelementptr inbounds %arg0[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr
   llvm.return
 }
 
 // CHECK-LABEL: llvm.func @caller(
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
 
 // Inlining @callee_with_metadata with noalias_scopes.
 
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_NO_ALIAS_SCOPE1]], #[[$WITH_DOMAIN_NO_ALIAS_SCOPE2]], #[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$WITH_DOMAIN_NO_ALIAS_SCOPE1]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_NO_ALIAS_SCOPE2]], #[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$WITH_DOMAIN_NO_ALIAS_SCOPE2]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_NO_ALIAS_SCOPE1]], #[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 
 // Inlining @callee_with_metadata with alias_scopes.
 
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_ALIAS_SCOPE1]], #[[$WITH_DOMAIN_ALIAS_SCOPE2]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$WITH_DOMAIN_ALIAS_SCOPE1]], #[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_ALIAS_SCOPE2]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$WITH_DOMAIN_ALIAS_SCOPE2]], #[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$WITH_DOMAIN_ALIAS_SCOPE1]]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
 
 // Inlining @callee_without_metadata with noalias_scopes.
 
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 
 // Inlining @callee_without_metadata with alias_scopes.
 
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$CALL_DOMAIN_SCOPE]]]
 // CHECK-NOT: noalias_scopes
 
 llvm.func @caller(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
-  %0 = llvm.load %arg2 {alias_scopes = [#alias_scope2], alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
+  %0 = ptr.load %arg2 {alias_scopes = [#alias_scope2], alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
   llvm.call @callee_with_metadata(%arg0, %arg1, %0) {noalias_scopes = [#alias_scope2]} : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
   llvm.call @callee_with_metadata(%arg1, %arg1, %arg0) {alias_scopes = [#alias_scope2]} : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
   llvm.call @callee_without_metadata(%arg0, %arg1, %0) {noalias_scopes = [#alias_scope2]} : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
@@ -198,23 +198,23 @@ llvm.func @caller(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
-// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
 
 llvm.func @foo(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noalias}) {
   %0 = llvm.mlir.constant(5 : i64) : i64
-  %1 = llvm.load %arg1 {alignment = 4 : i64} : !llvm.ptr -> f32
+  %1 = ptr.load %arg1 {alignment = 4 : i64} : !llvm.ptr -> f32
   %2 = llvm.getelementptr inbounds %arg0[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %1, %2 {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %1, %2 {alignment = 4 : i64} : f32, !llvm.ptr
   llvm.return
 }
 
 // CHECK-LABEL: llvm.func @bar
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$ARG1_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG0_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$ARG0_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG1_SCOPE]]]
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
@@ -224,16 +224,16 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
-// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
 
 llvm.func @might_return_arg_derived(!llvm.ptr) -> !llvm.ptr
 
 llvm.func @foo(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noalias}) {
   %0 = llvm.mlir.constant(5 : i64) : i32
   %1 = llvm.call @might_return_arg_derived(%arg0) : (!llvm.ptr) -> !llvm.ptr
-  llvm.store %0, %1 : i32, !llvm.ptr
+  ptr.store %0, %1 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -241,7 +241,7 @@ llvm.func @foo(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noalias})
 // CHECK: llvm.call
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$ARG1_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-NOT: noalias_scopes
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
@@ -251,9 +251,9 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
-// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
 
 llvm.func @random() -> i1
 
@@ -263,7 +263,7 @@ llvm.func @block_arg(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noa
   llvm.cond_br %1, ^bb0(%arg0 : !llvm.ptr), ^bb0(%arg1 : !llvm.ptr)
 
 ^bb0(%arg2: !llvm.ptr):
-  llvm.store %0, %arg2 : i32, !llvm.ptr
+  ptr.store %0, %arg2 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -271,7 +271,7 @@ llvm.func @block_arg(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noa
 // CHECK: llvm.call
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$ARG0_SCOPE]], #[[$ARG1_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK: alias_scopes = [#[[$ARG0_SCOPE]], #[[$ARG1_SCOPE]]]
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
   llvm.call @block_arg(%arg0, %arg2) : (!llvm.ptr, !llvm.ptr) -> ()
@@ -280,9 +280,9 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
-// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
 
 llvm.func @random() -> i1
 
@@ -294,7 +294,7 @@ llvm.func @block_arg(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noa
   llvm.cond_br %3, ^bb0(%arg0 : !llvm.ptr), ^bb0(%2 : !llvm.ptr)
 
 ^bb0(%arg2: !llvm.ptr):
-  llvm.store %0, %arg2 : i32, !llvm.ptr
+  ptr.store %0, %arg2 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -302,7 +302,7 @@ llvm.func @block_arg(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noa
 // CHECK: llvm.call
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$ARG0_SCOPE]], #[[$ARG1_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$ARG1_SCOPE]]]
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
@@ -312,9 +312,9 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
-// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
 
 llvm.func @unknown() -> !llvm.ptr
 llvm.func @random() -> i1
@@ -326,7 +326,7 @@ llvm.func @unknown_object(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llv
   llvm.cond_br %1, ^bb0(%arg0 : !llvm.ptr), ^bb0(%2 : !llvm.ptr)
 
 ^bb0(%arg2: !llvm.ptr):
-  llvm.store %0, %arg2 : i32, !llvm.ptr
+  ptr.store %0, %arg2 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -337,7 +337,7 @@ llvm.func @unknown_object(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llv
 // CHECK: llvm.call
 // CHECK-NOT: alias_scopes
 // CHECK-SAME: noalias_scopes = [#[[$ARG0_SCOPE]], #[[$ARG1_SCOPE]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-NOT: alias_scopes
 // CHECK-NOT: noalias_scopes
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
@@ -347,29 +347,29 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
 
 // -----
 
-// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}>
-// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
-// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<{{.*}}>
+// CHECK-DAG: #[[$ARG0_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
+// CHECK-DAG: #[[$ARG1_SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]{{(,.*)?}}>
 
 llvm.func @supported_operations(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.ptr {llvm.noalias}) {
   %0 = llvm.mlir.constant(5 : i64) : i32
-  llvm.store %0, %arg1 : i32, !llvm.ptr
-  %1 = llvm.load %arg1 : !llvm.ptr -> i32
+  ptr.store %0, %arg1 : i32, !llvm.ptr
+  %1 = ptr.load %arg1 : !llvm.ptr -> i32
   "llvm.intr.memcpy"(%arg0, %arg1, %1) <{ isVolatile = false }> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   "llvm.intr.memmove"(%arg0, %arg1, %1) <{ isVolatile = false }> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   "llvm.intr.memcpy.inline"(%arg0, %arg1) <{ isVolatile = false, len = 4 : i32}> : (!llvm.ptr, !llvm.ptr) -> ()
   %2 = llvm.trunc %0 : i32 to i8
   "llvm.intr.memset"(%arg0, %2, %1) <{ isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %3 = llvm.cmpxchg %arg0, %0, %1 seq_cst seq_cst : !llvm.ptr, i32
-  %4 = llvm.atomicrmw add %arg0, %0 seq_cst : !llvm.ptr, i32
+  %3, %4 = ptr.cmpxchg %arg0, %0, %1 seq_cst seq_cst : !llvm.ptr, i32
+  %5 = ptr.atomicrmw add %arg0, %0 seq_cst : !llvm.ptr, i32
   llvm.return
 }
 
 // CHECK-LABEL: llvm.func @bar
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: alias_scopes = [#[[$ARG1_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG0_SCOPE]]]
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: alias_scopes = [#[[$ARG1_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG0_SCOPE]]]
 // CHECK: "llvm.intr.memcpy"
@@ -384,10 +384,10 @@ llvm.func @supported_operations(%arg0: !llvm.ptr {llvm.noalias}, %arg1: !llvm.pt
 // CHECK: "llvm.intr.memset"
 // CHECK-SAME: alias_scopes = [#[[$ARG0_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG1_SCOPE]]]
-// CHECK: llvm.cmpxchg
+// CHECK: ptr.cmpxchg
 // CHECK-SAME: alias_scopes = [#[[$ARG0_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG1_SCOPE]]]
-// CHECK: llvm.atomicrmw
+// CHECK: ptr.atomicrmw
 // CHECK-SAME: alias_scopes = [#[[$ARG0_SCOPE]]]
 // CHECK-SAME: noalias_scopes = [#[[$ARG1_SCOPE]]]
 llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
diff --git a/mlir/test/Dialect/LLVMIR/inlining.mlir b/mlir/test/Dialect/LLVMIR/inlining.mlir
index 3af8753bc318ab..2e64a3e1faf561 100644
--- a/mlir/test/Dialect/LLVMIR/inlining.mlir
+++ b/mlir/test/Dialect/LLVMIR/inlining.mlir
@@ -8,8 +8,8 @@
 func.func @inner_func_inlinable(%ptr : !llvm.ptr) -> i32 {
   %0 = llvm.mlir.constant(42 : i32) : i32
   %stack = llvm.intr.stacksave : !llvm.ptr
-  llvm.store %0, %ptr { alignment = 8 } : i32, !llvm.ptr
-  %1 = llvm.load %ptr { alignment = 8 } : !llvm.ptr -> i32
+  ptr.store %0, %ptr { alignment = 8 } : i32, !llvm.ptr
+  %1 = ptr.load %ptr { alignment = 8 } : !llvm.ptr -> i32
   llvm.intr.dbg.value #variable = %0 : i32
   llvm.intr.dbg.declare #variableAddr = %ptr : !llvm.ptr
   llvm.intr.dbg.label #label
@@ -20,8 +20,8 @@ func.func @inner_func_inlinable(%ptr : !llvm.ptr) -> i32 {
   "llvm.intr.memcpy"(%ptr, %ptr, %0) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   "llvm.intr.assume"(%true) : (i1) -> ()
   llvm.fence release
-  %2 = llvm.atomicrmw add %ptr, %0 monotonic : !llvm.ptr, i32
-  %3 = llvm.cmpxchg %ptr, %0, %1 acq_rel monotonic : !llvm.ptr, i32
+  %2 = ptr.atomicrmw add %ptr, %0 monotonic : !llvm.ptr, i32
+  %3, %4 = ptr.cmpxchg %ptr, %0, %1 acq_rel monotonic : !llvm.ptr, i32
   llvm.inline_asm has_side_effects "foo", "bar" : () -> ()
   llvm.cond_br %true, ^bb1, ^bb2
 ^bb1:
@@ -36,8 +36,8 @@ func.func @inner_func_inlinable(%ptr : !llvm.ptr) -> i32 {
 // CHECK-SAME: %[[PTR:[a-zA-Z0-9_]+]]
 // CHECK: %[[CST:.*]] = llvm.mlir.constant(42
 // CHECK: %[[STACK:.+]] = llvm.intr.stacksave
-// CHECK: llvm.store %[[CST]], %[[PTR]]
-// CHECK: %[[RES:.+]] = llvm.load %[[PTR]]
+// CHECK: ptr.store %[[CST]], %[[PTR]]
+// CHECK: %[[RES:.+]] = ptr.load %[[PTR]]
 // CHECK: llvm.intr.dbg.value #{{.+}} = %[[CST]]
 // CHECK: llvm.intr.dbg.declare #{{.+}} = %[[PTR]]
 // CHECK: llvm.intr.dbg.label #{{.+}}
@@ -46,8 +46,8 @@ func.func @inner_func_inlinable(%ptr : !llvm.ptr) -> i32 {
 // CHECK: "llvm.intr.memcpy"(%[[PTR]], %[[PTR]]
 // CHECK: "llvm.intr.assume"
 // CHECK: llvm.fence release
-// CHECK: llvm.atomicrmw add %[[PTR]], %[[CST]] monotonic
-// CHECK: llvm.cmpxchg %[[PTR]], %[[CST]], %[[RES]] acq_rel monotonic
+// CHECK: ptr.atomicrmw add %[[PTR]], %[[CST]] monotonic
+// CHECK: ptr.cmpxchg %[[PTR]], %[[CST]], %[[RES]] acq_rel monotonic
 // CHECK: llvm.inline_asm has_side_effects "foo", "bar"
 // CHECK: llvm.unreachable
 // CHECK: llvm.intr.stackrestore %[[STACK]]
@@ -208,14 +208,14 @@ llvm.func @caller() {
 llvm.func @static_alloca() -> f32 {
   %0 = llvm.mlir.constant(4 : i32) : i32
   %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
-  %2 = llvm.load %1 : !llvm.ptr -> f32
+  %2 = ptr.load %1 : !llvm.ptr -> f32
   llvm.return %2 : f32
 }
 
 llvm.func @dynamic_alloca(%size : i32) -> f32 {
   %0 = llvm.add %size, %size : i32
   %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
-  %2 = llvm.load %1 : !llvm.ptr -> f32
+  %2 = ptr.load %1 : !llvm.ptr -> f32
   llvm.return %2 : f32
 }
 
@@ -267,7 +267,7 @@ llvm.func @static_alloca_not_in_entry(%cond : i1) -> f32 {
   %3 = llvm.alloca %2 x f32 : (i32) -> !llvm.ptr
   llvm.br ^bb3(%3: !llvm.ptr)
 ^bb3(%ptr : !llvm.ptr):
-  %4 = llvm.load %ptr : !llvm.ptr -> f32
+  %4 = ptr.load %ptr : !llvm.ptr -> f32
   llvm.return %4 : f32
 }
 
@@ -288,7 +288,7 @@ llvm.func @static_alloca(%cond: i1) -> f32 {
   %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
   llvm.cond_br %cond, ^bb1, ^bb2
 ^bb1:
-  %2 = llvm.load %1 : !llvm.ptr -> f32
+  %2 = ptr.load %1 : !llvm.ptr -> f32
   llvm.return %2 : f32
 ^bb2:
   %3 = llvm.mlir.constant(3.14192 : f32) : f32
@@ -312,7 +312,7 @@ llvm.func @test_inline(%cond0 : i1, %cond1 : i1, %funcArg : f32) -> f32 {
   // Make sure the lifetime end intrinsic has been inserted at both former
   // return sites of the callee.
   // CHECK: ^[[BB2]]:
-  // CHECK-NEXT: llvm.load
+  // CHECK-NEXT: ptr.load
   // CHECK-NEXT: llvm.intr.lifetime.end 4, %[[PTR]]
   // CHECK: ^[[BB3]]:
   // CHECK-NEXT: llvm.intr.lifetime.end 4, %[[PTR]]
@@ -327,7 +327,7 @@ llvm.func @test_inline(%cond0 : i1, %cond1 : i1, %funcArg : f32) -> f32 {
 llvm.func @static_alloca() -> f32 {
   %0 = llvm.mlir.constant(4 : i32) : i32
   %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
-  %2 = llvm.load %1 : !llvm.ptr -> f32
+  %2 = ptr.load %1 : !llvm.ptr -> f32
   llvm.return %2 : f32
 }
 
@@ -341,7 +341,7 @@ llvm.func @test_inline(%cond0 : i1) {
   "test.one_region_op"() ({
     %0 = llvm.call @static_alloca() : () -> f32
     // CHECK-NEXT: llvm.intr.lifetime.start 4, %[[ALLOCA]]
-    // CHECK-NEXT: %[[RES:.+]] = llvm.load %[[ALLOCA]]
+    // CHECK-NEXT: %[[RES:.+]] = ptr.load %[[ALLOCA]]
     // CHECK-NEXT: llvm.intr.lifetime.end 4, %[[ALLOCA]]
     // CHECK-NEXT: test.region_yield %[[RES]]
     test.region_yield %0 : f32
@@ -375,7 +375,7 @@ llvm.func @alloca_with_lifetime(%cond: i1) -> f32 {
   %0 = llvm.mlir.constant(4 : i32) : i32
   %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
   llvm.intr.lifetime.start 4, %1 : !llvm.ptr
-  %2 = llvm.load %1 : !llvm.ptr -> f32
+  %2 = ptr.load %1 : !llvm.ptr -> f32
   llvm.intr.lifetime.end 4, %1 : !llvm.ptr
   %3 = llvm.fadd %2, %2 : f32
   llvm.return %3 : f32
@@ -392,7 +392,7 @@ llvm.func @test_inline(%cond0 : i1, %cond1 : i1, %funcArg : f32) -> f32 {
   // Make sure the original lifetime intrinsic has been preserved, rather than
   // inserting a new one with a larger scope.
   // CHECK: llvm.intr.lifetime.start 4, %[[PTR]]
-  // CHECK-NEXT: llvm.load %[[PTR]]
+  // CHECK-NEXT: ptr.load %[[PTR]]
   // CHECK-NEXT: llvm.intr.lifetime.end 4, %[[PTR]]
   // CHECK: llvm.fadd
   // CHECK-NOT: llvm.intr.lifetime.end
@@ -603,19 +603,19 @@ llvm.func @test_disallow_arg_attr(%ptr : !llvm.ptr) {
 
 // -----
 
-#callee = #llvm.access_group<id = distinct[0]<>>
-#caller = #llvm.access_group<id = distinct[1]<>>
+#callee = #ptr.access_group<id = distinct[0]<>>
+#caller = #ptr.access_group<id = distinct[1]<>>
 
 llvm.func @inlinee(%ptr : !llvm.ptr) -> i32 {
-  %0 = llvm.load %ptr { access_groups = [#callee] } : !llvm.ptr -> i32
+  %0 = ptr.load %ptr { access_groups = [#callee] } : !llvm.ptr -> i32
   llvm.return %0 : i32
 }
 
-// CHECK-DAG: #[[$CALLEE:.*]] = #llvm.access_group<id = {{.*}}>
-// CHECK-DAG: #[[$CALLER:.*]] = #llvm.access_group<id = {{.*}}>
+// CHECK-DAG: #[[$CALLEE:.*]] = #ptr.access_group<id = {{.*}}>
+// CHECK-DAG: #[[$CALLER:.*]] = #ptr.access_group<id = {{.*}}>
 
 // CHECK-LABEL: func @caller
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: access_groups = [#[[$CALLEE]], #[[$CALLER]]]
 llvm.func @caller(%ptr : !llvm.ptr) -> i32 {
   %0 = llvm.call @inlinee(%ptr) { access_groups = [#caller] } : (!llvm.ptr) -> (i32)
@@ -624,24 +624,24 @@ llvm.func @caller(%ptr : !llvm.ptr) -> i32 {
 
 // -----
 
-#caller = #llvm.access_group<id = distinct[1]<>>
+#caller = #ptr.access_group<id = distinct[1]<>>
 
 llvm.func @inlinee(%ptr : !llvm.ptr) -> i32 {
-  %0 = llvm.load %ptr : !llvm.ptr -> i32
+  %0 = ptr.load %ptr : !llvm.ptr -> i32
   llvm.return %0 : i32
 }
 
-// CHECK-DAG: #[[$CALLER:.*]] = #llvm.access_group<id = {{.*}}>
+// CHECK-DAG: #[[$CALLER:.*]] = #ptr.access_group<id = {{.*}}>
 
 // CHECK-LABEL: func @caller
-// CHECK: llvm.load
+// CHECK: ptr.load
 // CHECK-SAME: access_groups = [#[[$CALLER]]]
-// CHECK: llvm.store
+// CHECK: ptr.store
 // CHECK-SAME: access_groups = [#[[$CALLER]]]
 llvm.func @caller(%ptr : !llvm.ptr) -> i32 {
   %c5 = llvm.mlir.constant(5 : i32) : i32
   %0 = llvm.call @inlinee(%ptr) { access_groups = [#caller] } : (!llvm.ptr) -> (i32)
-  llvm.store %c5, %ptr { access_groups = [#caller] } : i32, !llvm.ptr
+  ptr.store %c5, %ptr { access_groups = [#caller] } : i32, !llvm.ptr
   llvm.return %0 : i32
 }
 
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index de1ab9db8e8df8..bcccaa0e866fbd 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -126,78 +126,78 @@ func.func @gep_too_few_dynamic(%base : !llvm.ptr) {
 // -----
 
 func.func @load_non_llvm_type(%foo : memref<f32>) {
-  // expected-error at +1 {{op operand #0 must be LLVM pointer type}}
-  llvm.load %foo : memref<f32> -> f32
+  // expected-error at +1 {{'ptr.load' op operand #0 must be pointer type, but got 'memref<f32>'}}
+  ptr.load %foo : memref<f32> -> f32
 }
 
 // -----
 
 func.func @load_syncscope(%ptr : !llvm.ptr) {
   // expected-error at below {{expected syncscope to be null for non-atomic access}}
-  %1 = "llvm.load"(%ptr) {syncscope = "singlethread"} : (!llvm.ptr) -> (f32)
+  %1 = "ptr.load"(%ptr) {syncscope = "singlethread"} : (!llvm.ptr) -> (f32)
 }
 
 // -----
 
 func.func @load_unsupported_ordering(%ptr : !llvm.ptr) {
   // expected-error at below {{unsupported ordering 'release'}}
-  %1 = llvm.load %ptr atomic release {alignment = 4 : i64} : !llvm.ptr -> f32
+  %1 = ptr.load %ptr atomic release {alignment = 4 : i64} : !llvm.ptr -> f32
 }
 
 // -----
 
 func.func @load_unsupported_type(%ptr : !llvm.ptr) {
   // expected-error at below {{unsupported type 'f80' for atomic access}}
-  %1 = llvm.load %ptr atomic monotonic {alignment = 16 : i64} : !llvm.ptr -> f80
+  %1 = ptr.load %ptr atomic monotonic {alignment = 16 : i64} : !llvm.ptr -> f80
 }
 
 // -----
 
 func.func @load_unsupported_type(%ptr : !llvm.ptr) {
   // expected-error at below {{unsupported type 'i1' for atomic access}}
-  %1 = llvm.load %ptr atomic monotonic {alignment = 16 : i64} : !llvm.ptr -> i1
+  %1 = ptr.load %ptr atomic monotonic {alignment = 16 : i64} : !llvm.ptr -> i1
 }
 
 // -----
 
 func.func @load_unaligned_atomic(%ptr : !llvm.ptr) {
   // expected-error at below {{expected alignment for atomic access}}
-  %1 = llvm.load %ptr atomic monotonic : !llvm.ptr -> f32
+  %1 = ptr.load %ptr atomic monotonic : !llvm.ptr -> f32
 }
 
 // -----
 
 func.func @store_syncscope(%val : f32, %ptr : !llvm.ptr) {
   // expected-error at below {{expected syncscope to be null for non-atomic access}}
-  "llvm.store"(%val, %ptr) {syncscope = "singlethread"} : (f32, !llvm.ptr) -> ()
+  "ptr.store"(%val, %ptr) {syncscope = "singlethread"} : (f32, !llvm.ptr) -> ()
 }
 
 // -----
 
 func.func @store_unsupported_ordering(%val : f32, %ptr : !llvm.ptr) {
   // expected-error at below {{unsupported ordering 'acquire'}}
-  llvm.store %val, %ptr atomic acquire {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %val, %ptr atomic acquire {alignment = 4 : i64} : f32, !llvm.ptr
 }
 
 // -----
 
 func.func @store_unsupported_type(%val : f80, %ptr : !llvm.ptr) {
   // expected-error at below {{unsupported type 'f80' for atomic access}}
-  llvm.store %val, %ptr atomic monotonic {alignment = 16 : i64} : f80, !llvm.ptr
+  ptr.store %val, %ptr atomic monotonic {alignment = 16 : i64} : f80, !llvm.ptr
 }
 
 // -----
 
 func.func @store_unsupported_type(%val : i1, %ptr : !llvm.ptr) {
   // expected-error at below {{unsupported type 'i1' for atomic access}}
-  llvm.store %val, %ptr atomic monotonic {alignment = 16 : i64} : i1, !llvm.ptr
+  ptr.store %val, %ptr atomic monotonic {alignment = 16 : i64} : i1, !llvm.ptr
 }
 
 // -----
 
 func.func @store_unaligned_atomic(%val : f32, %ptr : !llvm.ptr) {
   // expected-error at below {{expected alignment for atomic access}}
-  llvm.store %val, %ptr atomic monotonic : f32, !llvm.ptr
+  ptr.store %val, %ptr atomic monotonic : f32, !llvm.ptr
 }
 
 // -----
@@ -599,7 +599,7 @@ func.func @nvvm_invalid_mma_8(%a0 : i32, %a1 : i32,
 
 func.func @atomicrmw_mismatched_operands(%f32_ptr : !llvm.ptr, %f32 : f32) {
   // expected-error at +1 {{op failed to verify that result #0 and operand #1 have the same type}}
-  %0 = "llvm.atomicrmw"(%f32_ptr, %f32) {bin_op=11, ordering=1} : (!llvm.ptr, f32) -> i32
+  %0 = "ptr.atomicrmw"(%f32_ptr, %f32) {bin_op=11, ordering=1} : (!llvm.ptr, f32) -> i32
   llvm.return
 }
 
@@ -607,7 +607,7 @@ func.func @atomicrmw_mismatched_operands(%f32_ptr : !llvm.ptr, %f32 : f32) {
 
 func.func @atomicrmw_expected_float(%i32_ptr : !llvm.ptr, %i32 : i32) {
   // expected-error at +1 {{expected LLVM IR floating point type}}
-  %0 = llvm.atomicrmw fadd %i32_ptr, %i32 unordered : !llvm.ptr, i32
+  %0 = ptr.atomicrmw fadd %i32_ptr, %i32 unordered : !llvm.ptr, i32
   llvm.return
 }
 
@@ -615,7 +615,7 @@ func.func @atomicrmw_expected_float(%i32_ptr : !llvm.ptr, %i32 : i32) {
 
 func.func @atomicrmw_unexpected_xchg_type(%i1_ptr : !llvm.ptr, %i1 : i1) {
   // expected-error at +1 {{unexpected LLVM IR type for 'xchg' bin_op}}
-  %0 = llvm.atomicrmw xchg %i1_ptr, %i1 unordered : !llvm.ptr, i1
+  %0 = ptr.atomicrmw xchg %i1_ptr, %i1 unordered : !llvm.ptr, i1
   llvm.return
 }
 
@@ -623,23 +623,23 @@ func.func @atomicrmw_unexpected_xchg_type(%i1_ptr : !llvm.ptr, %i1 : i1) {
 
 func.func @atomicrmw_expected_int(%f32_ptr : !llvm.ptr, %f32 : f32) {
   // expected-error at +1 {{expected LLVM IR integer type}}
-  %0 = llvm.atomicrmw max %f32_ptr, %f32 unordered : !llvm.ptr, f32
+  %0 = ptr.atomicrmw max %f32_ptr, %f32 unordered : !llvm.ptr, f32
   llvm.return
 }
 
 // -----
 
 func.func @cmpxchg_mismatched_value_operands(%ptr : !llvm.ptr, %i32 : i32, %i64 : i64) {
-  // expected-error at +1 {{op failed to verify that operand #1 and operand #2 have the same type}}
-  %0 = "llvm.cmpxchg"(%ptr, %i32, %i64) {success_ordering=2,failure_ordering=2} : (!llvm.ptr, i32, i64) -> !llvm.struct<(i32, i1)>
+  // expected-error at +1 {{'ptr.cmpxchg' op failed to verify that all of {val, cmp, res} have same type}}
+  %0, %1 = "ptr.cmpxchg"(%ptr, %i32, %i64) {success_ordering=2,failure_ordering=2} : (!llvm.ptr, i32, i64) -> (i32, i1)
   llvm.return
 }
 
 // -----
 
 func.func @cmpxchg_mismatched_result(%ptr : !llvm.ptr, %i64 : i64) {
-  // expected-error at +1 {{op failed to verify that result #0 has an LLVM struct type consisting of the type of operand #2 and a bool}}
-  %0 = "llvm.cmpxchg"(%ptr, %i64, %i64) {success_ordering=2,failure_ordering=2} : (!llvm.ptr, i64, i64) -> !llvm.struct<(i64, i64)>
+  // expected-error at +1 {{'ptr.cmpxchg' op result #1 must be 1-bit signless integer, but got 'i64'}}
+  %0, %1 = "ptr.cmpxchg"(%ptr, %i64, %i64) {success_ordering=2,failure_ordering=2} : (!llvm.ptr, i64, i64) -> (i64, i64)
   llvm.return
 }
 
@@ -647,7 +647,7 @@ func.func @cmpxchg_mismatched_result(%ptr : !llvm.ptr, %i64 : i64) {
 
 func.func @cmpxchg_unexpected_type(%i1_ptr : !llvm.ptr, %i1 : i1) {
   // expected-error at +1 {{unexpected LLVM IR type}}
-  %0 = llvm.cmpxchg %i1_ptr, %i1, %i1 monotonic monotonic : !llvm.ptr, i1
+  %0, %1 = ptr.cmpxchg %i1_ptr, %i1, %i1 monotonic monotonic : !llvm.ptr, i1
   llvm.return
 }
 
@@ -655,7 +655,7 @@ func.func @cmpxchg_unexpected_type(%i1_ptr : !llvm.ptr, %i1 : i1) {
 
 func.func @cmpxchg_at_least_monotonic_success(%i32_ptr : !llvm.ptr, %i32 : i32) {
   // expected-error at +1 {{ordering must be at least 'monotonic'}}
-  %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 unordered monotonic : !llvm.ptr, i32
+  %0, %1 = ptr.cmpxchg %i32_ptr, %i32, %i32 unordered monotonic : !llvm.ptr, i32
   llvm.return
 }
 
@@ -663,7 +663,7 @@ func.func @cmpxchg_at_least_monotonic_success(%i32_ptr : !llvm.ptr, %i32 : i32)
 
 func.func @cmpxchg_at_least_monotonic_failure(%i32_ptr : !llvm.ptr, %i32 : i32) {
   // expected-error at +1 {{ordering must be at least 'monotonic'}}
-  %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 monotonic unordered : !llvm.ptr, i32
+  %0, %1 = ptr.cmpxchg %i32_ptr, %i32, %i32 monotonic unordered : !llvm.ptr, i32
   llvm.return
 }
 
@@ -671,7 +671,7 @@ func.func @cmpxchg_at_least_monotonic_failure(%i32_ptr : !llvm.ptr, %i32 : i32)
 
 func.func @cmpxchg_failure_release(%i32_ptr : !llvm.ptr, %i32 : i32) {
   // expected-error at +1 {{failure ordering cannot be 'release' or 'acq_rel'}}
-  %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 acq_rel release : !llvm.ptr, i32
+  %0, %1 = ptr.cmpxchg %i32_ptr, %i32, %i32 acq_rel release : !llvm.ptr, i32
   llvm.return
 }
 
@@ -679,7 +679,7 @@ func.func @cmpxchg_failure_release(%i32_ptr : !llvm.ptr, %i32 : i32) {
 
 func.func @cmpxchg_failure_acq_rel(%i32_ptr : !llvm.ptr, %i32 : i32) {
   // expected-error at +1 {{failure ordering cannot be 'release' or 'acq_rel'}}
-  %0 = llvm.cmpxchg %i32_ptr, %i32, %i32 acq_rel acq_rel : !llvm.ptr, i32
+  %0, %1 = ptr.cmpxchg %i32_ptr, %i32, %i32 acq_rel acq_rel : !llvm.ptr, i32
   llvm.return
 }
 
@@ -862,8 +862,8 @@ llvm.mlir.global appending @non_array_type_global_appending_linkage() : i32
 
 module {
   llvm.func @accessGroups(%arg0 : !llvm.ptr) {
-      // expected-error at below {{attribute 'access_groups' failed to satisfy constraint: LLVM dialect access group metadata array}}
-      %0 = llvm.load %arg0 { "access_groups" = [@func1] } : !llvm.ptr -> i32
+      // expected-error at below {{attribute 'access_groups' failed to satisfy constraint: Ptr dialect access group metadata array}}
+      %0 = ptr.load %arg0 { "access_groups" = [@func1] } : !llvm.ptr -> i32
       llvm.return
   }
   llvm.func @func1() {
@@ -875,8 +875,8 @@ module {
 
 module {
   llvm.func @accessGroups(%arg0 : !llvm.ptr, %arg1 : i32, %arg2 : i32) {
-      // expected-error at below {{attribute 'access_groups' failed to satisfy constraint: LLVM dialect access group metadata array}}
-      %0 = llvm.cmpxchg %arg0, %arg1, %arg2 acq_rel monotonic { "access_groups" = [@metadata::@scope] } : !llvm.ptr, i32
+      // expected-error at below {{custom op 'ptr.cmpxchg' 'ptr.cmpxchg' op attribute 'access_groups' failed to satisfy constraint: Ptr dialect access group metadata array}}
+      %0, %1 = ptr.cmpxchg %arg0, %arg1, %arg2 acq_rel monotonic { "access_groups" = [@metadata::@scope] } : !llvm.ptr, i32
       llvm.return
   }
   llvm.metadata @metadata {
@@ -888,8 +888,8 @@ module {
 
 module {
   llvm.func @aliasScope(%arg0 : !llvm.ptr, %arg1 : i32, %arg2 : i32) {
-      // expected-error at below {{attribute 'alias_scopes' failed to satisfy constraint: LLVM dialect alias scope array}}
-      %0 = llvm.cmpxchg %arg0, %arg1, %arg2 acq_rel monotonic { "alias_scopes" = "test" } : !llvm.ptr, i32
+      // expected-error at below {{custom op 'ptr.cmpxchg' 'ptr.cmpxchg' op attribute 'alias_scopes' failed to satisfy constraint: Ptr dialect alias scope array}}
+      %0, %1 = ptr.cmpxchg %arg0, %arg1, %arg2 acq_rel monotonic { "alias_scopes" = "test" } : !llvm.ptr, i32
       llvm.return
   }
 }
@@ -898,8 +898,8 @@ module {
 
 module {
   llvm.func @noAliasScopes(%arg0 : !llvm.ptr) {
-      // expected-error at below {{attribute 'noalias_scopes' failed to satisfy constraint: LLVM dialect alias scope array}}
-      %0 = llvm.load %arg0 { "noalias_scopes" = "test" } : !llvm.ptr -> i32
+      // expected-error at below {{custom op 'ptr.load' 'ptr.load' op attribute 'noalias_scopes' failed to satisfy constraint: Ptr dialect alias scope array}}
+      %0 = ptr.load %arg0 { "noalias_scopes" = "test" } : !llvm.ptr -> i32
       llvm.return
   }
 }
@@ -1172,7 +1172,7 @@ llvm.mlir.global internal @side_effecting_global() : !llvm.struct<(i8)> {
   %0 = llvm.mlir.constant(1 : i64) : i64
   // expected-error at below {{ops with side effects not allowed in global initializers}}
   %1 = llvm.alloca %0 x !llvm.struct<(i8)> : (i64) -> !llvm.ptr
-  %2 = llvm.load %1 : !llvm.ptr -> !llvm.struct<(i8)>
+  %2 = ptr.load %1 : !llvm.ptr -> !llvm.struct<(i8)>
   llvm.return %2 : !llvm.struct<(i8)>
 }
 
@@ -1288,14 +1288,14 @@ func.func @invalid_bitcast_ptr_to_vec(%arg : !llvm.ptr) {
 // -----
 
 func.func @invalid_bitcast_addr_cast(%arg : !llvm.ptr<1>) {
-  // expected-error at +1 {{cannot cast pointers of different address spaces, use 'llvm.addrspacecast' instead}}
+  // expected-error at +1 {{cannot cast pointers of different address spaces, use 'ptr.addrspacecast' instead}}
   %0 = llvm.bitcast %arg : !llvm.ptr<1> to !llvm.ptr
 }
 
 // -----
 
 func.func @invalid_bitcast_addr_cast_vec(%arg : !llvm.vec<4 x ptr<1>>) {
-  // expected-error at +1 {{cannot cast pointers of different address spaces, use 'llvm.addrspacecast' instead}}
+  // expected-error at +1 {{cannot cast pointers of different address spaces, use 'ptr.addrspacecast' instead}}
   %0 = llvm.bitcast %arg : !llvm.vec<4 x ptr<1>> to !llvm.vec<4 x ptr>
 }
 
@@ -1310,15 +1310,15 @@ func.func @invalid_target_ext_alloca() {
 // -----
 
 func.func @invalid_target_ext_load(%arg0 : !llvm.ptr) {
-  // expected-error at +1 {{result #0 must be LLVM type with size, but got '!llvm.target<"no_load">'}}
-  %0 = llvm.load %arg0 {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"no_load">
+  // expected-error at +1 {{type must be LLVM type with size, but got '!llvm.target<"no_load">'}}
+  %0 = ptr.load %arg0 {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"no_load">
 }
 
 // -----
 
 func.func @invalid_target_ext_atomic(%arg0 : !llvm.ptr) {
   // expected-error at +1 {{unsupported type '!llvm.target<"spirv.Event">' for atomic access}}
-  %0 = llvm.load %arg0 atomic monotonic {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"spirv.Event">
+  %0 = ptr.load %arg0 atomic monotonic {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"spirv.Event">
 }
 
 // -----
diff --git a/mlir/test/Dialect/LLVMIR/loop-metadata.mlir b/mlir/test/Dialect/LLVMIR/loop-metadata.mlir
index 6b4c3217d5c72d..7eb397e973919c 100644
--- a/mlir/test/Dialect/LLVMIR/loop-metadata.mlir
+++ b/mlir/test/Dialect/LLVMIR/loop-metadata.mlir
@@ -42,10 +42,10 @@
 // CHECK-DAG: #[[UNSWITCH:.*]] = #llvm.loop_unswitch<partialDisable = true>
 #unswitch = #llvm.loop_unswitch<partialDisable = true>
 
-// CHECK-DAG: #[[GROUP1:.*]] = #llvm.access_group<id = {{.*}}>
-// CHECK-DAG: #[[GROUP2:.*]] = #llvm.access_group<id = {{.*}}>
-#group1 = #llvm.access_group<id = distinct[0]<>>
-#group2 = #llvm.access_group<id = distinct[1]<>>
+// CHECK-DAG: #[[GROUP1:.*]] = #ptr.access_group<id = {{.*}}>
+// CHECK-DAG: #[[GROUP2:.*]] = #ptr.access_group<id = {{.*}}>
+#group1 = #ptr.access_group<id = distinct[0]<>>
+#group2 = #ptr.access_group<id = distinct[1]<>>
 
 // CHECK: #[[LOOP_ANNOT:.*]] = #llvm.loop_annotation<
 // CHECK-DAG: disableNonforced = false
@@ -99,10 +99,10 @@ llvm.func @loop_annotation() {
 // CHECK-DAG: #[[END_LOC_FUSED:.*]] = loc(fused<#[[SUBPROGRAM]]>[#[[END_LOC]]]
 #end_loc_fused= loc(fused<#di_subprogram>[#loc2])
 
-// CHECK-DAG: #[[GROUP1:.*]] = #llvm.access_group<id = {{.*}}>
-// CHECK-DAG: #[[GROUP2:.*]] = #llvm.access_group<id = {{.*}}>
-#group1 = #llvm.access_group<id = distinct[0]<>>
-#group2 = #llvm.access_group<id = distinct[1]<>>
+// CHECK-DAG: #[[GROUP1:.*]] = #ptr.access_group<id = {{.*}}>
+// CHECK-DAG: #[[GROUP2:.*]] = #ptr.access_group<id = {{.*}}>
+#group1 = #ptr.access_group<id = distinct[0]<>>
+#group2 = #ptr.access_group<id = distinct[1]<>>
 
 // CHECK: #[[LOOP_ANNOT:.*]] = #llvm.loop_annotation<
 // CHECK-DAG: disableNonforced = false
diff --git a/mlir/test/Dialect/LLVMIR/mem2reg-dbginfo.mlir b/mlir/test/Dialect/LLVMIR/mem2reg-dbginfo.mlir
index f7ddb4a7abe5ad..ae58d131dd1b77 100644
--- a/mlir/test/Dialect/LLVMIR/mem2reg-dbginfo.mlir
+++ b/mlir/test/Dialect/LLVMIR/mem2reg-dbginfo.mlir
@@ -16,15 +16,15 @@ llvm.func @basic_store_load(%arg0: i64) -> i64 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK-NOT: = llvm.alloca
   %1 = llvm.alloca %0 x i64 {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  // CHECK-NOT: llvm.store
-  llvm.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store
+  ptr.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
   // CHECK-NOT: llvm.intr.dbg.declare
   llvm.intr.dbg.declare #di_local_variable = %1 : !llvm.ptr
   // CHECK: llvm.intr.dbg.value #[[$VAR]] = %[[LOADED:.*]] : i64
   // CHECK-NOT: llvm.intr.dbg.value
   // CHECK-NOT: llvm.intr.dbg.declare
-  // CHECK-NOT: llvm.store
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  // CHECK-NOT: ptr.store
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   // CHECK: llvm.return %[[LOADED]] : i64
   llvm.return %2 : i64
 }
@@ -42,12 +42,12 @@ llvm.func @block_argument_value(%arg0: i64, %arg1: i1) -> i64 {
 ^bb1:
   // CHECK: llvm.intr.dbg.value #[[$VAR]] = %[[ARG0]]
   // CHECK-NOT: llvm.intr.dbg.value
-  llvm.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  ptr.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
   llvm.br ^bb2
 // CHECK: ^{{.*}}(%[[BLOCKARG:.*]]: i64):
 ^bb2:
   // CHECK: llvm.intr.dbg.value #[[$VAR]] = %[[BLOCKARG]]
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   llvm.return %2 : i64
 }
 
@@ -63,10 +63,10 @@ llvm.func @double_block_argument_value(%arg0: i64, %arg1: i1) -> i64 {
 // CHECK: ^{{.*}}(%[[BLOCKARG1:.*]]: i64):
 ^bb1:
   // CHECK: llvm.intr.dbg.value #[[$VAR]] = %[[BLOCKARG1]]
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   llvm.call @use(%2) : (i64) -> ()
   // CHECK: llvm.intr.dbg.value #[[$VAR]] = %[[ARG0]]
-  llvm.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  ptr.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
   llvm.br ^bb2
   // CHECK-NOT: llvm.intr.dbg.value
 // CHECK: ^{{.*}}(%[[BLOCKARG2:.*]]: i64):
diff --git a/mlir/test/Dialect/LLVMIR/mem2reg-intrinsics.mlir b/mlir/test/Dialect/LLVMIR/mem2reg-intrinsics.mlir
index 4fc80a87f20df5..7563c1ede9a631 100644
--- a/mlir/test/Dialect/LLVMIR/mem2reg-intrinsics.mlir
+++ b/mlir/test/Dialect/LLVMIR/mem2reg-intrinsics.mlir
@@ -16,7 +16,7 @@ llvm.func @basic_memset(%memset_value: i8) -> i32 {
   // CHECK: %[[SHIFTED_16:.*]] = llvm.shl %[[VALUE_16]], %[[C16]]
   // CHECK: %[[VALUE_32:.*]] = llvm.or %[[VALUE_16]], %[[SHIFTED_16]]
   // CHECK-NOT: "llvm.intr.memset"
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return %[[VALUE_32]] : i32
   llvm.return %2 : i32
 }
@@ -30,7 +30,7 @@ llvm.func @basic_memset_constant() -> i32 {
   %memset_value = llvm.mlir.constant(42 : i8) : i8
   %memset_len = llvm.mlir.constant(4 : i32) : i32
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: %[[C42:.*]] = llvm.mlir.constant(42 : i8) : i8
   // CHECK: %[[VALUE_42:.*]] = llvm.zext %[[C42]] : i8 to i32
   // CHECK: %[[C8:.*]] = llvm.mlir.constant(8 : i32) : i32
@@ -64,7 +64,7 @@ llvm.func @exotic_target_memset(%memset_value: i8) -> i40 {
   // CHECK: %[[SHIFTED_COMPL:.*]] = llvm.shl %[[VALUE_32]], %[[C32]]
   // CHECK: %[[VALUE_COMPL:.*]] = llvm.or %[[VALUE_32]], %[[SHIFTED_COMPL]]
   // CHECK-NOT: "llvm.intr.memset"
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i40
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i40
   // CHECK: llvm.return %[[VALUE_COMPL]] : i40
   llvm.return %2 : i40
 }
@@ -83,7 +83,7 @@ llvm.func @no_volatile_memset() -> i32 {
   %memset_len = llvm.mlir.constant(4 : i32) : i32
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = true}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = true}> : (!llvm.ptr, i8, i32) -> ()
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.return %2 : i32
 }
 
@@ -101,7 +101,7 @@ llvm.func @no_partial_memset() -> i32 {
   %memset_len = llvm.mlir.constant(2 : i32) : i32
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.return %2 : i32
 }
 
@@ -119,7 +119,7 @@ llvm.func @no_overflowing_memset() -> i32 {
   %memset_len = llvm.mlir.constant(6 : i32) : i32
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.return %2 : i32
 }
 
@@ -137,7 +137,7 @@ llvm.func @only_byte_aligned_integers_memset() -> i10 {
   %memset_len = llvm.mlir.constant(2 : i32) : i32
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i10
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i10
   llvm.return %2 : i10
 }
 
@@ -152,9 +152,9 @@ llvm.func @basic_memcpy(%source: !llvm.ptr) -> i32 {
   %memcpy_len = llvm.mlir.constant(4 : i32) : i32
   "llvm.intr.memcpy"(%1, %source, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   // CHECK-NOT: "llvm.intr.memcpy"
-  // CHECK: %[[LOADED:.*]] = llvm.load %[[SOURCE]] : !llvm.ptr -> i32
+  // CHECK: %[[LOADED:.*]] = ptr.load %[[SOURCE]] : !llvm.ptr -> i32
   // CHECK-NOT: "llvm.intr.memcpy"
-  %2 = llvm.load %1 : !llvm.ptr -> i32
+  %2 = ptr.load %1 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[LOADED]] : i32
   llvm.return %2 : i32
 }
@@ -171,13 +171,13 @@ llvm.func @basic_memcpy_dest(%destination: !llvm.ptr) -> i32 {
   %memcpy_len = llvm.mlir.constant(4 : i32) : i32
 
   %1 = llvm.alloca %0 x i32 : (i32) -> !llvm.ptr
-  llvm.store %data, %1 : i32, !llvm.ptr
+  ptr.store %data, %1 : i32, !llvm.ptr
   "llvm.intr.memcpy"(%destination, %1, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   // CHECK-NOT: "llvm.intr.memcpy"
-  // CHECK: llvm.store %[[DATA]], %[[DESTINATION]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[DATA]], %[[DESTINATION]] : i32, !llvm.ptr
   // CHECK-NOT: "llvm.intr.memcpy"
 
-  %2 = llvm.load %1 : !llvm.ptr -> i32
+  %2 = ptr.load %1 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[DATA]] : i32
   llvm.return %2 : i32
 }
@@ -194,10 +194,10 @@ llvm.func @double_memcpy() -> i32 {
 
   %1 = llvm.alloca %0 x i32 : (i32) -> !llvm.ptr
   %2 = llvm.alloca %0 x i32 : (i32) -> !llvm.ptr
-  llvm.store %data, %1 : i32, !llvm.ptr
+  ptr.store %data, %1 : i32, !llvm.ptr
   "llvm.intr.memcpy"(%2, %1, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
 
-  %res = llvm.load %2 : !llvm.ptr -> i32
+  %res = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[DATA]] : i32
   llvm.return %res : i32
 }
@@ -216,7 +216,7 @@ llvm.func @ignore_self_memcpy() -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[ALLOCA]]
   "llvm.intr.memcpy"(%1, %1, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
 
-  %res = llvm.load %1 : !llvm.ptr -> i32
+  %res = ptr.load %1 : !llvm.ptr -> i32
   llvm.return %res : i32
 }
 
@@ -236,7 +236,7 @@ llvm.func @ignore_partial_memcpy(%source: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[SOURCE]], %[[MEMCPY_LEN]]) <{isVolatile = false}>
   "llvm.intr.memcpy"(%1, %source, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
 
-  %res = llvm.load %1 : !llvm.ptr -> i32
+  %res = ptr.load %1 : !llvm.ptr -> i32
   llvm.return %res : i32
 }
 
@@ -256,7 +256,7 @@ llvm.func @ignore_volatile_memcpy(%source: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[SOURCE]], %[[MEMCPY_LEN]]) <{isVolatile = true}>
   "llvm.intr.memcpy"(%1, %source, %memcpy_len) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
 
-  %res = llvm.load %1 : !llvm.ptr -> i32
+  %res = ptr.load %1 : !llvm.ptr -> i32
   llvm.return %res : i32
 }
 
@@ -271,9 +271,9 @@ llvm.func @basic_memmove(%source: !llvm.ptr) -> i32 {
   %memmove_len = llvm.mlir.constant(4 : i32) : i32
   "llvm.intr.memmove"(%1, %source, %memmove_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   // CHECK-NOT: "llvm.intr.memmove"
-  // CHECK: %[[LOADED:.*]] = llvm.load %[[SOURCE]] : !llvm.ptr -> i32
+  // CHECK: %[[LOADED:.*]] = ptr.load %[[SOURCE]] : !llvm.ptr -> i32
   // CHECK-NOT: "llvm.intr.memmove"
-  %2 = llvm.load %1 : !llvm.ptr -> i32
+  %2 = ptr.load %1 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[LOADED]] : i32
   llvm.return %2 : i32
 }
@@ -288,9 +288,9 @@ llvm.func @basic_memcpy_inline(%source: !llvm.ptr) -> i32 {
   %is_volatile = llvm.mlir.constant(false) : i1
   "llvm.intr.memcpy.inline"(%1, %source) <{isVolatile = false, len = 4 : i32}> : (!llvm.ptr, !llvm.ptr) -> ()
   // CHECK-NOT: "llvm.intr.memcpy.inline"
-  // CHECK: %[[LOADED:.*]] = llvm.load %[[SOURCE]] : !llvm.ptr -> i32
+  // CHECK: %[[LOADED:.*]] = ptr.load %[[SOURCE]] : !llvm.ptr -> i32
   // CHECK-NOT: "llvm.intr.memcpy.inline"
-  %2 = llvm.load %1 : !llvm.ptr -> i32
+  %2 = ptr.load %1 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[LOADED]] : i32
   llvm.return %2 : i32
 }
diff --git a/mlir/test/Dialect/LLVMIR/mem2reg.mlir b/mlir/test/Dialect/LLVMIR/mem2reg.mlir
index 90e56c1166edfd..8c6806287e3f02 100644
--- a/mlir/test/Dialect/LLVMIR/mem2reg.mlir
+++ b/mlir/test/Dialect/LLVMIR/mem2reg.mlir
@@ -5,7 +5,7 @@ llvm.func @default_value() -> i32 {
   // CHECK: %[[UNDEF:.*]] = llvm.mlir.undef : i32
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return %[[UNDEF]] : i32
   llvm.return %2 : i32
 }
@@ -19,10 +19,10 @@ llvm.func @store_of_ptr() {
   %2 = llvm.mlir.zero : !llvm.ptr
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca
   %3 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %{{.*}}, %[[ALLOCA]]
-  llvm.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
-  // CHECK: llvm.store %[[ALLOCA]], %{{.*}}
-  llvm.store %3, %2 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %[[ALLOCA]]
+  ptr.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  // CHECK: ptr.store %[[ALLOCA]], %{{.*}}
+  ptr.store %3, %2 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
   llvm.return
 }
 
@@ -39,7 +39,7 @@ llvm.func @unreachable() {
 // CHECK: ^{{.*}}:
 // CHECK-NEXT: llvm.return
 ^bb1:  // no predecessors
-  llvm.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.return
 }
 
@@ -52,14 +52,14 @@ llvm.func @unreachable_in_loop() -> i32 {
   %1 = llvm.mlir.constant(6 : i32) : i32
   %2 = llvm.mlir.constant(5 : i32) : i32
   %3 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  llvm.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
   // CHECK: llvm.br ^[[LOOP:.*]]
   llvm.br ^bb1
 
 // CHECK: ^[[LOOP]]:
 ^bb1:  // 2 preds: ^bb0, ^bb3
   // CHECK-NEXT: llvm.br ^[[ENDOFLOOP:.*]]
-  llvm.store %2, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %2, %3 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb3
 
 // CHECK: ^[[UNREACHABLE:.*]]:
@@ -84,12 +84,12 @@ llvm.func @branching(%arg0: i1, %arg1: i1) -> i32 {
   // CHECK: llvm.cond_br %{{.*}}, ^[[BB2:.*]](%{{.*}} : i32), ^{{.*}}
   llvm.cond_br %arg0, ^bb2, ^bb1
 ^bb1:  // pred: ^bb0
-  llvm.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
   // CHECK: llvm.cond_br %{{.*}}, ^[[BB2]](%{{.*}} : i32), ^[[BB2]](%{{.*}} : i32)
   llvm.cond_br %arg1, ^bb2, ^bb2
 // CHECK: ^[[BB2]](%[[V3:.*]]: i32):
 ^bb2:  // 3 preds: ^bb0, ^bb1, ^bb1
-  %3 = llvm.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %3 = ptr.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return %[[V3]] : i32
   llvm.return %3 : i32
 }
@@ -104,12 +104,12 @@ llvm.func @recursive_alloca() -> i32 {
   %2 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   %3 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   %4 = llvm.alloca %0 x !llvm.ptr {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  llvm.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
-  llvm.store %3, %4 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
-  %5 = llvm.load %4 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
-  %6 = llvm.load %5 {alignment = 4 : i64} : !llvm.ptr -> i32
-  llvm.store %6, %2 {alignment = 4 : i64} : i32, !llvm.ptr
-  %7 = llvm.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %3, %4 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
+  %5 = ptr.load %4 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
+  %6 = ptr.load %5 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %6, %2 {alignment = 4 : i64} : i32, !llvm.ptr
+  %7 = ptr.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.return %7 : i32
 }
 
@@ -123,15 +123,15 @@ llvm.func @reset_in_branch(%arg0: i32, %arg1: i1) {
   %1 = llvm.mlir.constant(true) : i1
   %2 = llvm.mlir.constant(false) : i1
   %3 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  llvm.store %arg0, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %arg0, %3 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.cond_br %arg1, ^bb1, ^bb2
 ^bb1:  // pred: ^bb0
-  llvm.store %arg0, %3 {alignment = 4 : i64} : i32, !llvm.ptr
-  %4 = llvm.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %arg0, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  %4 = ptr.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.call @reset_in_branch(%4, %2) : (i32, i1) -> ()
   llvm.br ^bb3
 ^bb2:  // pred: ^bb0
-  %5 = llvm.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %5 = ptr.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.call @reset_in_branch(%5, %1) : (i32, i1) -> ()
   llvm.br ^bb3
 ^bb3:  // 2 preds: ^bb1, ^bb2
@@ -150,38 +150,38 @@ llvm.func @intertwined_alloca(%arg0: !llvm.ptr, %arg1: i32) {
   %4 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   %5 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   %6 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  llvm.store %arg0, %2 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
-  llvm.store %arg1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
-  llvm.store %1, %4 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %arg0, %2 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
+  ptr.store %arg1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %4 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb1
 ^bb1:  // 2 preds: ^bb0, ^bb4
-  %7 = llvm.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %7 = ptr.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
   %8 = llvm.add %7, %0  : i32
-  %9 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %9 = ptr.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
   %10 = llvm.icmp "sgt" %8, %9 : i32
   %11 = llvm.zext %10 : i1 to i32
   llvm.cond_br %10, ^bb2, ^bb5
 ^bb2:  // pred: ^bb1
-  %12 = llvm.load %6 {alignment = 4 : i64} : !llvm.ptr -> i32
-  llvm.store %12, %5 {alignment = 4 : i64} : i32, !llvm.ptr
-  llvm.store %1, %6 {alignment = 4 : i64} : i32, !llvm.ptr
-  %13 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %12 = ptr.load %6 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %12, %5 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %6 {alignment = 4 : i64} : i32, !llvm.ptr
+  %13 = ptr.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
   %14 = llvm.icmp "sgt" %13, %1 : i32
   %15 = llvm.zext %14 : i1 to i32
   llvm.cond_br %14, ^bb3, ^bb4
 ^bb3:  // pred: ^bb2
-  %16 = llvm.load %2 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
-  %17 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %16 = ptr.load %2 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
+  %17 = ptr.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
   %18 = llvm.sub %17, %0  : i32
   %19 = llvm.getelementptr %16[%18] : (!llvm.ptr, i32) -> !llvm.ptr, i8
-  %20 = llvm.load %5 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %20 = ptr.load %5 {alignment = 4 : i64} : !llvm.ptr -> i32
   %21 = llvm.trunc %20 : i32 to i8
-  llvm.store %21, %19 {alignment = 1 : i64} : i8, !llvm.ptr
+  ptr.store %21, %19 {alignment = 1 : i64} : i8, !llvm.ptr
   llvm.br ^bb4
 ^bb4:  // 2 preds: ^bb2, ^bb3
-  %22 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %22 = ptr.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
   %23 = llvm.add %22, %0  : i32
-  llvm.store %23, %4 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %23, %4 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb1
 ^bb5:  // pred: ^bb1
   llvm.return
@@ -200,7 +200,7 @@ llvm.func @complex_cf(%arg0: i32, ...) {
 ^bb1:  // pred: ^bb0
   llvm.br ^bb2
 ^bb2:  // 2 preds: ^bb0, ^bb1
-  llvm.store %2, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %2, %3 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb3
 ^bb3:  // 2 preds: ^bb2, ^bb16
   llvm.cond_br %1, ^bb4, ^bb17
@@ -233,7 +233,7 @@ llvm.func @complex_cf(%arg0: i32, ...) {
 ^bb17:  // pred: ^bb3
   llvm.br ^bb20
 ^bb18:  // no predecessors
-  %4 = llvm.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %4 = ptr.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.br ^bb24
 ^bb19:  // no predecessors
   llvm.br ^bb20
@@ -268,30 +268,30 @@ llvm.func @llvm_crash() -> i32 {
   %5 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   %6 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   %7 = llvm.bitcast %1 : i32 to i32
-  // CHECK: llvm.store volatile %{{.*}}, %[[VOLATILE_ALLOCA]]
-  llvm.store volatile %1, %5 {alignment = 4 : i64} : i32, !llvm.ptr
+  // CHECK: ptr.store volatile %{{.*}}, %[[VOLATILE_ALLOCA]]
+  ptr.store volatile %1, %5 {alignment = 4 : i64} : i32, !llvm.ptr
   %8 = llvm.call @_setjmp(%2) : (!llvm.ptr) -> i32
   %9 = llvm.icmp "ne" %8, %1 : i32
   %10 = llvm.zext %9 : i1 to i8
   %11 = llvm.icmp "ne" %10, %3 : i8
   llvm.cond_br %11, ^bb1, ^bb2
 ^bb1:  // pred: ^bb0
-  // CHECK: = llvm.load volatile %[[VOLATILE_ALLOCA]]
-  %12 = llvm.load volatile %5 {alignment = 4 : i64} : !llvm.ptr -> i32
-  llvm.store %12, %6 {alignment = 4 : i64} : i32, !llvm.ptr
+  // CHECK: = ptr.load volatile %[[VOLATILE_ALLOCA]]
+  %12 = ptr.load volatile %5 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %12, %6 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb3
 ^bb2:  // pred: ^bb0
-  // CHECK: llvm.store volatile %{{.*}}, %[[VOLATILE_ALLOCA]]
-  llvm.store volatile %0, %5 {alignment = 4 : i64} : i32, !llvm.ptr
+  // CHECK: ptr.store volatile %{{.*}}, %[[VOLATILE_ALLOCA]]
+  ptr.store volatile %0, %5 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.call @g() : () -> ()
-  llvm.store %1, %6 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %6 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb3
 ^bb3:  // 2 preds: ^bb1, ^bb2
-  %13 = llvm.load %6 {alignment = 4 : i64} : !llvm.ptr -> i32
-  llvm.store %13, %4 {alignment = 4 : i64} : i32, !llvm.ptr
+  %13 = ptr.load %6 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %13, %4 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb4
 ^bb4:  // pred: ^bb3
-  %14 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %14 = ptr.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.return %14 : i32
 }
 llvm.mlir.global external @j() {addr_space = 0 : i32} : !llvm.array<1 x struct<"struct.__jmp_buf_tag", (array<6 x i32>, i32, struct<"struct.__sigset_t", (array<32 x i32>)>)>>
@@ -306,7 +306,7 @@ llvm.func amdgpu_kernelcc @addrspace_discard() {
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.mlir.constant(2 : i64) : i64
   %2 = llvm.alloca %0 x i8 {alignment = 8 : i64} : (i32) -> !llvm.ptr<5>
-  %3 = llvm.addrspacecast %2 : !llvm.ptr<5> to !llvm.ptr
+  %3 = ptr.addrspacecast %2 : !llvm.ptr<5> to !llvm.ptr
   llvm.intr.lifetime.start 2, %3 : !llvm.ptr
   llvm.return
 }
@@ -319,8 +319,8 @@ llvm.func @ignore_atomic(%arg0: i32) -> i32 {
   // CHECK-NOT: = llvm.alloca
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  llvm.store %arg0, %1 atomic seq_cst {alignment = 4 : i64} : i32, !llvm.ptr
-  %2 = llvm.load %1 atomic seq_cst {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %arg0, %1 atomic seq_cst {alignment = 4 : i64} : i32, !llvm.ptr
+  %2 = ptr.load %1 atomic seq_cst {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return %[[ARG0]] : i32
   llvm.return %2 : i32
 }
@@ -339,12 +339,12 @@ llvm.func @landing_pad() -> i32 attributes {personality = @__gxx_personality_v0}
   %2 = llvm.invoke @landing_padf() to ^bb1 unwind ^bb3 : () -> i32
 // CHECK: ^{{.*}}:
 ^bb1:// pred: ^bb0
-  llvm.store %2, %1 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %2, %1 {alignment = 4 : i64} : i32, !llvm.ptr
   // CHECK: llvm.br ^[[BB2:.*]](%[[V2]] : i32)
   llvm.br ^bb2
 // CHECK: ^[[BB2]]([[V3:.*]]: i32):
 ^bb2:// 2 preds: ^bb1, ^bb3
-  %3 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %3 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return [[V3]] : i32
   llvm.return %3 : i32
 // CHECK: ^{{.*}}:
@@ -367,12 +367,12 @@ llvm.func @unreachable_defines() -> i32 {
   %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   llvm.br ^bb1
 ^bb1:  // 2 preds: ^bb0, ^bb2
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return %[[UNDEF]] : i32
   llvm.return %2 : i32
 ^bb2:  // no predecessors
-  %3 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
-  llvm.store %3, %1 {alignment = 4 : i64} : i32, !llvm.ptr
+  %3 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %3, %1 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb1
 }
 
@@ -387,15 +387,15 @@ llvm.func @unreachable_jumps_to_merge_point(%arg0: i1) -> i32 {
   %3 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   llvm.cond_br %arg0, ^bb1, ^bb2
 ^bb1:  // 2 preds: ^bb0, ^bb4
-  llvm.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %1, %3 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb4
 ^bb2:  // pred: ^bb0
-  llvm.store %2, %3 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %2, %3 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.br ^bb4
 ^bb3:  // no predecessors
   llvm.br ^bb4
 ^bb4:  // 3 preds: ^bb1, ^bb2, ^bb3
-  %4 = llvm.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %4 = ptr.load %3 {alignment = 4 : i64} : !llvm.ptr -> i32
   llvm.return %4 : i32
 }
 
@@ -407,7 +407,7 @@ llvm.func @ignore_lifetime() {
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
   llvm.intr.lifetime.start 2, %1 : !llvm.ptr
-  llvm.store %0, %1 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %0, %1 {alignment = 4 : i64} : i32, !llvm.ptr
   llvm.intr.lifetime.end 2, %1 : !llvm.ptr
   llvm.return
 }
@@ -426,7 +426,7 @@ llvm.func @ignore_discardable_tree() {
   %6 = llvm.alloca %0 x !llvm.struct<(i8, i16)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %7 = llvm.getelementptr %6[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i8, i16)>
   llvm.intr.lifetime.start 2, %7 : !llvm.ptr
-  llvm.store %5, %6 {alignment = 2 : i64} : !llvm.struct<(i8, i16)>, !llvm.ptr
+  ptr.store %5, %6 {alignment = 2 : i64} : !llvm.struct<(i8, i16)>, !llvm.ptr
   llvm.intr.lifetime.end 2, %7 : !llvm.ptr
   llvm.return
 }
@@ -440,8 +440,8 @@ llvm.func @store_load_forward() -> i32 {
   // CHECK: %[[RES:.*]] = llvm.mlir.constant(0 : i32) : i32
   %1 = llvm.mlir.constant(0 : i32) : i32
   %2 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  llvm.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
-  %3 = llvm.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
+  ptr.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
+  %3 = ptr.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -454,8 +454,8 @@ llvm.func @store_load_wrong_type() -> i16 {
   %1 = llvm.mlir.constant(0 : i32) : i32
   // CHECK: = llvm.alloca
   %2 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
-  llvm.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
-  %3 = llvm.load %2 {alignment = 2 : i64} : !llvm.ptr -> i16
+  ptr.store %1, %2 {alignment = 4 : i64} : i32, !llvm.ptr
+  %3 = ptr.load %2 {alignment = 2 : i64} : !llvm.ptr -> i16
   llvm.return %3 : i16
 }
 
@@ -471,12 +471,12 @@ llvm.func @merge_point_cycle() {
   llvm.br ^bb1
 // CHECK: ^[[BB1]](%[[BARG:.*]]: i32):
 ^bb1:  // 2 preds: ^bb0, ^bb1
-  %3 = llvm.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %3 = ptr.load %2 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: = llvm.call @use(%[[BARG]])
   %4 = llvm.call @use(%3) : (i32) -> i1
   // CHECK: %[[DEF:.*]] = llvm.call @def
   %5 = llvm.call @def(%1) : (i32) -> i32
-  llvm.store %5, %2 {alignment = 4 : i64} : i32, !llvm.ptr
+  ptr.store %5, %2 {alignment = 4 : i64} : i32, !llvm.ptr
   // CHECK: llvm.cond_br %{{.*}}, ^[[BB1]](%[[DEF]] : i32), ^{{.*}}
   llvm.cond_br %4, ^bb1, ^bb2
 ^bb2:  // pred: ^bb1
@@ -497,7 +497,7 @@ llvm.func @no_unnecessary_arguments() {
   llvm.br ^bb1
 // CHECK: ^[[BB1]]:
 ^bb1:  // 2 preds: ^bb0, ^bb1
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i32
   // CHECK: = llvm.call @use(%[[UNDEF]])
   %3 = llvm.call @use(%2) : (i32) -> i1
   // CHECK: llvm.cond_br %{{.*}}, ^[[BB1]], ^{{.*}}
@@ -594,15 +594,15 @@ llvm.func @live_cycle(%arg0: i64, %arg1: i1, %arg2: i64) -> i64 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK-NOT: = llvm.alloca
   %1 = llvm.alloca %0 x i64 {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  llvm.store %arg2, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  ptr.store %arg2, %1 {alignment = 4 : i64} : i64, !llvm.ptr
   // CHECK: llvm.cond_br %{{.*}}, ^[[BB1:.*]](%[[ARG2]] : i64), ^[[BB2:.*]](%[[ARG2]] : i64)
   llvm.cond_br %arg1, ^bb1, ^bb2
 // CHECK: ^[[BB1]](%[[V1:.*]]: i64):
 ^bb1:
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   // CHECK: llvm.call @use(%[[V1]])
   llvm.call @use(%2) : (i64) -> ()
-  llvm.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  ptr.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
   // CHECK: llvm.br ^[[BB2]](%[[ARG0]] : i64)
   llvm.br ^bb2
 // CHECK: ^[[BB2]](%[[V2:.*]]: i64):
@@ -623,17 +623,17 @@ llvm.func @subregion_block_promotion(%arg0: i64, %arg1: i64) -> i64 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca
   %1 = llvm.alloca %0 x i64 {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[ARG1]], %[[ALLOCA]]
-  llvm.store %arg1, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  // CHECK: ptr.store %[[ARG1]], %[[ALLOCA]]
+  ptr.store %arg1, %1 {alignment = 4 : i64} : i64, !llvm.ptr
   // CHECK: scf.execute_region {
   scf.execute_region {
-    // CHECK: llvm.store %[[ARG0]], %[[ALLOCA]]
-    llvm.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+    // CHECK: ptr.store %[[ARG0]], %[[ALLOCA]]
+    ptr.store %arg0, %1 {alignment = 4 : i64} : i64, !llvm.ptr
     scf.yield
   }
   // CHECK: }
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   // CHECK: llvm.return %[[RES]] : i64
   llvm.return %2 : i64
 }
@@ -646,8 +646,8 @@ llvm.func @subregion_simple_transitive_promotion(%arg0: i64, %arg1: i64) -> i64
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK-NOT: = llvm.alloca
   %1 = llvm.alloca %0 x i64 {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  llvm.store %arg1, %1 {alignment = 4 : i64} : i64, !llvm.ptr
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  ptr.store %arg1, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   // CHECK: scf.execute_region {
   scf.execute_region {
     // CHECK: llvm.call @use(%[[ARG1]])
@@ -677,10 +677,10 @@ llvm.func @no_inner_alloca_promotion(%arg: i64) -> i64 {
 ^bb1:
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca
   %1 = llvm.alloca %0 x i64 {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
-  llvm.store %arg, %1 {alignment = 4 : i64} : i64, !llvm.ptr
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %2 = llvm.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
+  // CHECK: ptr.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 {alignment = 4 : i64} : i64, !llvm.ptr
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %2 = ptr.load %1 {alignment = 4 : i64} : !llvm.ptr -> i64
   // CHECK: llvm.return %[[RES]] : i64
   llvm.return %2 : i64
 }
@@ -692,8 +692,8 @@ llvm.func @transitive_reaching_def() -> !llvm.ptr {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK-NOT: alloca
   %1 = llvm.alloca %0 x !llvm.ptr {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  %2 = llvm.load %1 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
-  llvm.store %2, %1 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
-  %3 = llvm.load %1 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
+  %2 = ptr.load %1 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
+  ptr.store %2, %1 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
+  %3 = ptr.load %1 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
   llvm.return %3 : !llvm.ptr
 }
diff --git a/mlir/test/Dialect/LLVMIR/opaque-ptr.mlir b/mlir/test/Dialect/LLVMIR/opaque-ptr.mlir
index 373931c747fc3e..578511bfaa7c3d 100644
--- a/mlir/test/Dialect/LLVMIR/opaque-ptr.mlir
+++ b/mlir/test/Dialect/LLVMIR/opaque-ptr.mlir
@@ -2,22 +2,22 @@
 
 // CHECK-LABEL: @opaque_ptr_load
 llvm.func @opaque_ptr_load(%arg0: !llvm.ptr) -> i32 {
-  // CHECK: = llvm.load %{{.*}} : !llvm.ptr -> i32
-  %0 = llvm.load %arg0 : !llvm.ptr -> i32
+  // CHECK: = ptr.load %{{.*}} : !llvm.ptr -> i32
+  %0 = ptr.load %arg0 : !llvm.ptr -> i32
   llvm.return %0 : i32
 }
 
 // CHECK-LABEL: @opaque_ptr_store
 llvm.func @opaque_ptr_store(%arg0: i32, %arg1: !llvm.ptr){
-  // CHECK: llvm.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
-  llvm.store %arg0, %arg1 : i32, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
+  ptr.store %arg0, %arg1 : i32, !llvm.ptr
   llvm.return
 }
 
 // CHECK-LABEL: @opaque_ptr_ptr_store
 llvm.func @opaque_ptr_ptr_store(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
-  // CHECK: llvm.store %{{.*}}, %{{.*}} : !llvm.ptr, !llvm.ptr
-  llvm.store %arg0, %arg1 : !llvm.ptr, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} : !llvm.ptr, !llvm.ptr
+  ptr.store %arg0, %arg1 : !llvm.ptr, !llvm.ptr
   llvm.return
 }
 
diff --git a/mlir/test/Dialect/LLVMIR/rocdl.mlir b/mlir/test/Dialect/LLVMIR/rocdl.mlir
index 6519186d2cfdcc..ac9a2085f59e05 100644
--- a/mlir/test/Dialect/LLVMIR/rocdl.mlir
+++ b/mlir/test/Dialect/LLVMIR/rocdl.mlir
@@ -220,7 +220,7 @@ llvm.func @rocdl.make.buffer.rsrc(%ptr : !llvm.ptr,
                                   %numRecords : i32,
                                   %flags : i32) -> !llvm.ptr<8> {
   // CHECK-LABEL: rocdl.make.buffer.rsrc
-  // CHECK: %{{.*}} = rocdl.make.buffer.rsrc %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !llvm.ptr to <8>
+  // CHECK: %{{.*}} = rocdl.make.buffer.rsrc %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : !llvm.ptr to !llvm.ptr<8>
   %rsrc = rocdl.make.buffer.rsrc %ptr, %stride, %numRecords, %flags : !llvm.ptr to !llvm.ptr<8>
   llvm.return %rsrc : !llvm.ptr<8>
 }
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 31acf2b95e4638..e81e8c71c739ee 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -61,12 +61,12 @@ func.func @ops(%arg0: i32, %arg1: f32,
 //
 // CHECK-NEXT:  %[[ALLOCA:.*]] = llvm.alloca %[[I32]] x f64 : (i32) -> !llvm.ptr
 // CHECK-NEXT:  %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][%[[I32]]] : (!llvm.ptr, i32) -> !llvm.ptr, f64
-// CHECK-NEXT:  %[[VALUE:.*]] = llvm.load %[[GEP]] : !llvm.ptr -> f64
-// CHECK-NEXT:  llvm.store %[[VALUE]], %[[ALLOCA]] : f64, !llvm.ptr
+// CHECK-NEXT:  %[[VALUE:.*]] = ptr.load %[[GEP]] : !llvm.ptr -> f64
+// CHECK-NEXT:  ptr.store %[[VALUE]], %[[ALLOCA]] : f64, !llvm.ptr
   %13 = llvm.alloca %arg0 x f64 : (i32) -> !llvm.ptr
   %14 = llvm.getelementptr %13[%arg0] : (!llvm.ptr, i32) -> !llvm.ptr, f64
-  %15 = llvm.load %14 : !llvm.ptr -> f64
-  llvm.store %15, %13 : f64, !llvm.ptr
+  %15 = ptr.load %14 : !llvm.ptr -> f64
+  ptr.store %15, %13 : f64, !llvm.ptr
 
 // Function call-related operations.
 //
@@ -150,10 +150,10 @@ func.func @ops(%arg0: i32, %arg1: f32,
 
 // Integer to pointer and pointer to integer conversions.
 //
-// CHECK: %[[PTR:.*]] = llvm.inttoptr %[[I32]] : i32 to !llvm.ptr
-// CHECK: %{{.*}} = llvm.ptrtoint %[[PTR]] : !llvm.ptr to i32
-  %25 = llvm.inttoptr %arg0 : i32 to !llvm.ptr
-  %26 = llvm.ptrtoint %25 : !llvm.ptr to i32
+// CHECK: %[[PTR:.*]] = ptr.inttoptr %[[I32]] : i32 to !llvm.ptr
+// CHECK: %{{.*}} = ptr.ptrtoint %[[PTR]] : !llvm.ptr to i32
+  %25 = ptr.inttoptr %arg0 : i32 to !llvm.ptr
+  %26 = ptr.ptrtoint %25 : !llvm.ptr to i32
 
 // Extended and Quad floating point
 //
@@ -290,8 +290,8 @@ func.func @casts(%arg0: i32, %arg1: i64, %arg2: vector<4xi32>,
   %8 = llvm.fptosi %7 : f32 to i32
 // CHECK:  = llvm.fptoui %[[FLOAT]] : f32 to i32
   %9 = llvm.fptoui %7 : f32 to i32
-// CHECK:  = llvm.addrspacecast %[[PTR]] : !llvm.ptr to !llvm.ptr<2>
-  %10 = llvm.addrspacecast %arg4 : !llvm.ptr to !llvm.ptr<2>
+// CHECK:  = ptr.addrspacecast %[[PTR]] : !llvm.ptr to !llvm.ptr<2>
+  %10 = ptr.addrspacecast %arg4 : !llvm.ptr to !llvm.ptr<2>
 // CHECK:  = llvm.bitcast %[[I64]] : i64 to f64
   %11 = llvm.bitcast %arg1 : i64 to f64
   llvm.return
@@ -374,44 +374,44 @@ func.func @zero() {
 
 // CHECK-LABEL: @atomic_load
 func.func @atomic_load(%ptr : !llvm.ptr) {
-  // CHECK: llvm.load %{{.*}} atomic monotonic {alignment = 4 : i64} : !llvm.ptr -> f32
-  %0 = llvm.load %ptr atomic monotonic {alignment = 4 : i64} : !llvm.ptr -> f32
-  // CHECK: llvm.load volatile %{{.*}} atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr -> f32
-  %1 = llvm.load volatile %ptr atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr -> f32
+  // CHECK: ptr.load %{{.*}} atomic monotonic {alignment = 4 : i64} : !llvm.ptr -> f32
+  %0 = ptr.load %ptr atomic monotonic {alignment = 4 : i64} : !llvm.ptr -> f32
+  // CHECK: ptr.load volatile %{{.*}} atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr -> f32
+  %1 = ptr.load volatile %ptr atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr -> f32
   llvm.return
 }
 
 // CHECK-LABEL: @atomic_store
 func.func @atomic_store(%val : f32, %ptr : !llvm.ptr) {
-  // CHECK: llvm.store %{{.*}}, %{{.*}} atomic monotonic {alignment = 4 : i64} : f32, !llvm.ptr
-  llvm.store %val, %ptr atomic monotonic {alignment = 4 : i64} : f32, !llvm.ptr
-  // CHECK: llvm.store volatile %{{.*}}, %{{.*}} atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : f32, !llvm.ptr
-  llvm.store volatile %val, %ptr atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : f32, !llvm.ptr
+  // CHECK: ptr.store %{{.*}}, %{{.*}} atomic monotonic {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %val, %ptr atomic monotonic {alignment = 4 : i64} : f32, !llvm.ptr
+  // CHECK: ptr.store volatile %{{.*}}, %{{.*}} atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : f32, !llvm.ptr
+  ptr.store volatile %val, %ptr atomic syncscope("singlethread") monotonic {alignment = 16 : i64} : f32, !llvm.ptr
   llvm.return
 }
 
 // CHECK-LABEL: @atomicrmw
 func.func @atomicrmw(%ptr : !llvm.ptr, %val : f32) {
-  // CHECK: llvm.atomicrmw fadd %{{.*}}, %{{.*}} monotonic : !llvm.ptr, f32
-  %0 = llvm.atomicrmw fadd %ptr, %val monotonic : !llvm.ptr, f32
-  // CHECK: llvm.atomicrmw volatile fsub %{{.*}}, %{{.*}} syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr, f32
-  %1 = llvm.atomicrmw volatile fsub %ptr, %val syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr, f32
+  // CHECK: ptr.atomicrmw fadd %{{.*}}, %{{.*}} monotonic : !llvm.ptr, f32
+  %0 = ptr.atomicrmw fadd %ptr, %val monotonic : !llvm.ptr, f32
+  // CHECK: ptr.atomicrmw volatile fsub %{{.*}}, %{{.*}} syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr, f32
+  %1 = ptr.atomicrmw volatile fsub %ptr, %val syncscope("singlethread") monotonic {alignment = 16 : i64} : !llvm.ptr, f32
   llvm.return
 }
 
 // CHECK-LABEL: @cmpxchg
 func.func @cmpxchg(%ptr : !llvm.ptr, %cmp : i32, %new : i32) {
-  // CHECK: llvm.cmpxchg %{{.*}}, %{{.*}}, %{{.*}} acq_rel monotonic : !llvm.ptr, i32
-  %0 = llvm.cmpxchg %ptr, %cmp, %new acq_rel monotonic : !llvm.ptr, i32
-  // CHECK: llvm.cmpxchg weak volatile %{{.*}}, %{{.*}}, %{{.*}} syncscope("singlethread") acq_rel monotonic {alignment = 16 : i64} : !llvm.ptr, i32
-  %1 = llvm.cmpxchg weak volatile %ptr, %cmp, %new syncscope("singlethread") acq_rel monotonic {alignment = 16 : i64} : !llvm.ptr, i32
+  // CHECK: ptr.cmpxchg %{{.*}}, %{{.*}}, %{{.*}} acq_rel monotonic : !llvm.ptr, i32
+  %0, %1 = ptr.cmpxchg %ptr, %cmp, %new acq_rel monotonic : !llvm.ptr, i32
+  // CHECK: ptr.cmpxchg weak volatile %{{.*}}, %{{.*}}, %{{.*}} syncscope("singlethread") acq_rel monotonic {alignment = 16 : i64} : !llvm.ptr, i32
+  %2, %3 = ptr.cmpxchg weak volatile %ptr, %cmp, %new syncscope("singlethread") acq_rel monotonic {alignment = 16 : i64} : !llvm.ptr, i32
   llvm.return
 }
 
 // CHECK-LABEL: @invariant_load
 func.func @invariant_load(%ptr : !llvm.ptr) -> i32 {
-  // CHECK: llvm.load %{{.+}} invariant {alignment = 4 : i64} : !llvm.ptr -> i32
-  %0 = llvm.load %ptr invariant {alignment = 4 : i64} : !llvm.ptr -> i32
+  // CHECK: ptr.load %{{.+}} invariant {alignment = 4 : i64} : !llvm.ptr -> i32
+  %0 = ptr.load %ptr invariant {alignment = 4 : i64} : !llvm.ptr -> i32
   func.return %0 : i32
 }
 
@@ -638,8 +638,8 @@ llvm.func @stackrestore(%arg0: !llvm.ptr)  {
   llvm.return
 }
 
-#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-#alias_scope = #llvm.alias_scope<id = distinct[0]<>, domain = #alias_scope_domain, description = "The domain">
+#alias_scope_domain = #ptr.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#alias_scope = #ptr.alias_scope<id = distinct[0]<>, domain = #alias_scope_domain, description = "The domain">
 
 // CHECK-LABEL: @experimental_noalias_scope_decl
 llvm.func @experimental_noalias_scope_decl() {
diff --git a/mlir/test/Dialect/LLVMIR/sroa-intrinsics.mlir b/mlir/test/Dialect/LLVMIR/sroa-intrinsics.mlir
index ba73025814cc05..72bc70b518b2ce 100644
--- a/mlir/test/Dialect/LLVMIR/sroa-intrinsics.mlir
+++ b/mlir/test/Dialect/LLVMIR/sroa-intrinsics.mlir
@@ -15,7 +15,7 @@ llvm.func @memset() -> i32 {
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -37,7 +37,7 @@ llvm.func @memset_partial() -> i32 {
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -58,7 +58,7 @@ llvm.func @memset_full() -> i32 {
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -78,7 +78,7 @@ llvm.func @memset_too_much() -> i32 {
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -97,7 +97,7 @@ llvm.func @memset_no_volatile() -> i32 {
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = true}>
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = true}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -117,7 +117,7 @@ llvm.func @indirect_memset() -> i32 {
   %2 = llvm.getelementptr %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
   // CHECK: "llvm.intr.memset"(%[[ALLOCA]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%2, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -138,7 +138,7 @@ llvm.func @invalid_indirect_memset() -> i32 {
   %2 = llvm.getelementptr %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
   // CHECK: "llvm.intr.memset"(%[[GEP]], %[[MEMSET_VALUE]], %[[MEMSET_LEN]]) <{isVolatile = false}>
   "llvm.intr.memset"(%2, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -165,9 +165,9 @@ llvm.func @memset_double_use() -> i32 {
   // CHECK-NOT: "llvm.intr.memset"
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   %4 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f32)>
-  %5 = llvm.load %4 : !llvm.ptr -> f32
+  %5 = ptr.load %4 : !llvm.ptr -> f32
   // We use this exotic bitcast to use the f32 easily. Semantics do not matter here.
   %6 = llvm.bitcast %5 : f32 to i32
   %7 = llvm.add %3, %6 : i32
@@ -196,9 +196,9 @@ llvm.func @memset_considers_alignment() -> i32 {
   // CHECK-NOT: "llvm.intr.memset"
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i8, i32, f32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   %4 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i8, i32, f32)>
-  %5 = llvm.load %4 : !llvm.ptr -> f32
+  %5 = ptr.load %4 : !llvm.ptr -> f32
   // We use this exotic bitcast to use the f32 easily. Semantics do not matter here.
   %6 = llvm.bitcast %5 : f32 to i32
   %7 = llvm.add %3, %6 : i32
@@ -228,9 +228,9 @@ llvm.func @memset_considers_packing() -> i32 {
   // CHECK-NOT: "llvm.intr.memset"
   "llvm.intr.memset"(%1, %memset_value, %memset_len) <{isVolatile = false}> : (!llvm.ptr, i8, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i8, i32, f32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   %4 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i8, i32, f32)>
-  %5 = llvm.load %4 : !llvm.ptr -> f32
+  %5 = ptr.load %4 : !llvm.ptr -> f32
   // We use this exotic bitcast to use the f32 easily. Semantics do not matter here.
   %6 = llvm.bitcast %5 : f32 to i32
   %7 = llvm.add %3, %6 : i32
@@ -253,7 +253,7 @@ llvm.func @memcpy_dest(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[SLOT_IN_OTHER]], %[[MEMCPY_LEN]]) <{isVolatile = false}>
   "llvm.intr.memcpy"(%1, %other_array, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -285,7 +285,7 @@ llvm.func @memcpy_src(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[SLOT_IN_OTHER]], %{{.*}}, %[[MEMCPY_LEN]]) <{isVolatile = false}>
   "llvm.intr.memcpy"(%other_array, %1, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<4 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -310,7 +310,7 @@ llvm.func @memcpy_double() -> i32 {
   // CHECK-NOT: "llvm.intr.memcpy"
   "llvm.intr.memcpy"(%1, %2, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %3 = llvm.getelementptr %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<1 x i32>
-  %4 = llvm.load %3 : !llvm.ptr -> i32
+  %4 = ptr.load %3 : !llvm.ptr -> i32
   llvm.return %4 : i32
 }
 
@@ -328,7 +328,7 @@ llvm.func @memcpy_no_partial(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[OTHER_ARRAY]], %[[MEMCPY_LEN]]) <{isVolatile = false}>
   "llvm.intr.memcpy"(%1, %other_array, %memcpy_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -346,7 +346,7 @@ llvm.func @memcpy_no_volatile(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[OTHER_ARRAY]], %[[MEMCPY_LEN]]) <{isVolatile = true}>
   "llvm.intr.memcpy"(%1, %other_array, %memcpy_len) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -366,7 +366,7 @@ llvm.func @memmove_dest(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memmove"(%[[ALLOCA]], %[[SLOT_IN_OTHER]], %[[MEMMOVE_LEN]]) <{isVolatile = false}>
   "llvm.intr.memmove"(%1, %other_array, %memmove_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -397,7 +397,7 @@ llvm.func @memmove_src(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memmove"(%[[SLOT_IN_OTHER]], %{{.*}}, %[[MEMMOVE_LEN]]) <{isVolatile = false}>
   "llvm.intr.memmove"(%other_array, %1, %memmove_len) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<4 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -415,7 +415,7 @@ llvm.func @memcpy_inline_dest(%other_array: !llvm.ptr) -> i32 {
   // CHECK: "llvm.intr.memcpy.inline"(%[[ALLOCA]], %[[SLOT_IN_OTHER]]) <{isVolatile = false, len = 4 : i32}>
   "llvm.intr.memcpy.inline"(%1, %other_array) <{isVolatile = false, len = 40 : i32}> : (!llvm.ptr, !llvm.ptr) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -442,6 +442,6 @@ llvm.func @memcpy_inline_src(%other_array: !llvm.ptr) -> i32 {
   // CHECK-DAG: "llvm.intr.memcpy.inline"(%[[SLOT_IN_OTHER]], %{{.*}}) <{isVolatile = false, len = 4 : i32}>
   "llvm.intr.memcpy.inline"(%other_array, %1) <{isVolatile = false, len = 16 : i32}> : (!llvm.ptr, !llvm.ptr) -> ()
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<4 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
diff --git a/mlir/test/Dialect/LLVMIR/sroa-statistics.mlir b/mlir/test/Dialect/LLVMIR/sroa-statistics.mlir
index 2905e8745ae029..25c44a79704d12 100644
--- a/mlir/test/Dialect/LLVMIR/sroa-statistics.mlir
+++ b/mlir/test/Dialect/LLVMIR/sroa-statistics.mlir
@@ -9,7 +9,7 @@ llvm.func @basic() -> i32 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -24,8 +24,8 @@ llvm.func @basic_no_memory_benefit() -> i32 {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
   %3 = llvm.getelementptr inbounds %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
-  %4 = llvm.load %2 : !llvm.ptr -> i32
-  %5 = llvm.load %3 : !llvm.ptr -> i32
+  %4 = ptr.load %2 : !llvm.ptr -> i32
+  %5 = ptr.load %3 : !llvm.ptr -> i32
   %6 = llvm.add %4, %5 : i32
   llvm.return %6 : i32
 }
@@ -40,7 +40,7 @@ llvm.func @basic_array() -> i32 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.alloca %0 x !llvm.array<10 x i32> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -57,6 +57,6 @@ llvm.func @multi_level_direct() -> i32 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2, 1, 5, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
diff --git a/mlir/test/Dialect/LLVMIR/sroa.mlir b/mlir/test/Dialect/LLVMIR/sroa.mlir
index 3f4d17c6a43f97..de1a28e497d20c 100644
--- a/mlir/test/Dialect/LLVMIR/sroa.mlir
+++ b/mlir/test/Dialect/LLVMIR/sroa.mlir
@@ -7,8 +7,8 @@ llvm.func @basic_struct() -> i32 {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -22,8 +22,8 @@ llvm.func @basic_array() -> i32 {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
   %1 = llvm.alloca %0 x !llvm.array<10 x i32> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -37,8 +37,8 @@ llvm.func @multi_level_direct() -> i32 {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2, 1, 5, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)>
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -58,8 +58,8 @@ llvm.func @multi_level_direct_two_applications() -> i32 {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, array<10 x i32>, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, array<10 x i32>, i8)>
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -74,8 +74,8 @@ llvm.func @multi_level_indirect() -> i32 {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr inbounds %1[0, 2, 1, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)>
   %3 = llvm.getelementptr inbounds %2[0, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %4 = llvm.load %3 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %4 = ptr.load %3 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %4 : i32
 }
@@ -91,10 +91,10 @@ llvm.func @resolve_alias(%arg: i32) -> i32 {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
   %3 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
-  // CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
-  llvm.store %arg, %2 : i32, !llvm.ptr
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %4 = llvm.load %3 : !llvm.ptr -> i32
+  // CHECK: ptr.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %2 : i32, !llvm.ptr
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %4 = ptr.load %3 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %4 : i32
 }
@@ -109,7 +109,7 @@ llvm.func @no_non_single_support() -> i32 {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   // CHECK-NOT: = llvm.alloca
   %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -123,7 +123,7 @@ llvm.func @no_pointer_indexing() -> i32 {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   // CHECK-NOT: = llvm.alloca
   %2 = llvm.getelementptr %1[1, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.return %3 : i32
 }
 
@@ -137,7 +137,7 @@ llvm.func @no_direct_use() -> i32 {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   // CHECK-NOT: = llvm.alloca
   %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   llvm.call @use(%1) : (!llvm.ptr) -> ()
   llvm.return %3 : i32
 }
@@ -153,8 +153,8 @@ llvm.func @direct_promotable_use_is_fine() -> i32 {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // This is a direct use of the slot but it can be removed because it implements PromotableOpInterface.
   llvm.intr.lifetime.start 2, %1 : !llvm.ptr
   // CHECK: llvm.return %[[RES]] : i32
@@ -172,8 +172,8 @@ llvm.func @direct_promotable_use_is_fine_on_accessor() -> i32 {
   %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
   // This does not provide side-effect info but it can be removed because it implements PromotableOpInterface.
   %3 = llvm.intr.invariant.start 2, %2 : !llvm.ptr
-  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %4 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %4 = ptr.load %2 : !llvm.ptr -> i32
   // This does not provide side-effect info but it can be removed because it implements PromotableOpInterface.
   llvm.intr.invariant.end %3, 2, %2 : !llvm.ptr
   // CHECK: llvm.return %[[RES]] : i32
@@ -192,8 +192,8 @@ llvm.func @no_dynamic_indexing(%arg: i32) -> i32 {
   // CHECK-NOT: = llvm.alloca
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, %[[ARG]]]
   %2 = llvm.getelementptr %1[0, %arg] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.array<10 x i32>
-  // CHECK: %[[RES:.*]] = llvm.load %[[GEP]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[GEP]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -210,8 +210,8 @@ llvm.func @no_nested_dynamic_indexing(%arg: i32) -> i32 {
   // CHECK-NOT: = llvm.alloca
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 0, %[[ARG]]]
   %2 = llvm.getelementptr %1[0, 0, %arg] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(array<10 x i32>, i32)>
-  // CHECK: %[[RES:.*]] = llvm.load %[[GEP]]
-  %3 = llvm.load %2 : !llvm.ptr -> i32
+  // CHECK: %[[RES:.*]] = ptr.load %[[GEP]]
+  %3 = ptr.load %2 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %3 : i32
 }
@@ -223,8 +223,8 @@ llvm.func @store_first_field(%arg: i32) {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: llvm.store %{{.*}}, %[[ALLOCA]] : i32
-  llvm.store %arg, %1 : i32, !llvm.ptr
+  // CHECK-NEXT: ptr.store %{{.*}}, %[[ALLOCA]] : i32
+  ptr.store %arg, %1 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -236,8 +236,8 @@ llvm.func @store_first_field_different_type(%arg: f32) {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] : f32
-  llvm.store %arg, %1 : f32, !llvm.ptr
+  // CHECK-NEXT: ptr.store %[[ARG]], %[[ALLOCA]] : f32
+  ptr.store %arg, %1 : f32, !llvm.ptr
   llvm.return
 }
 
@@ -249,8 +249,8 @@ llvm.func @store_sub_field(%arg: f32) {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i64
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i64, i32)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] : f32
-  llvm.store %arg, %1 : f32, !llvm.ptr
+  // CHECK-NEXT: ptr.store %[[ARG]], %[[ALLOCA]] : f32
+  ptr.store %arg, %1 : f32, !llvm.ptr
   llvm.return
 }
 
@@ -261,8 +261,8 @@ llvm.func @load_first_field() -> i32 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: %[[RES:.*]] = llvm.load %[[ALLOCA]] : !llvm.ptr -> i32
-  %2 = llvm.load %1 : !llvm.ptr -> i32
+  // CHECK-NEXT: %[[RES:.*]] = ptr.load %[[ALLOCA]] : !llvm.ptr -> i32
+  %2 = ptr.load %1 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %2 : i32
 }
@@ -274,8 +274,8 @@ llvm.func @load_first_field_different_type() -> f32 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: %[[RES:.*]] = llvm.load %[[ALLOCA]] : !llvm.ptr -> f32
-  %2 = llvm.load %1 : !llvm.ptr -> f32
+  // CHECK-NEXT: %[[RES:.*]] = ptr.load %[[ALLOCA]] : !llvm.ptr -> f32
+  %2 = ptr.load %1 : !llvm.ptr -> f32
   // CHECK: llvm.return %[[RES]] : f32
   llvm.return %2 : f32
 }
@@ -287,8 +287,8 @@ llvm.func @load_sub_field() -> i32 {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i64 : (i32) -> !llvm.ptr
   %1 = llvm.alloca %0 x !llvm.struct<(i64, i32)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: %[[RES:.*]] = llvm.load %[[ALLOCA]]
-  %res = llvm.load %1 : !llvm.ptr -> i32
+  // CHECK-NEXT: %[[RES:.*]] = ptr.load %[[ALLOCA]]
+  %res = ptr.load %1 : !llvm.ptr -> i32
   // CHECK: llvm.return %[[RES]] : i32
   llvm.return %res : i32
 }
@@ -301,8 +301,8 @@ llvm.func @vector_store_type_mismatch(%arg: vector<4xi32>) {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x vector<4xf32>
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (vector<4xf32>)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]]
-  llvm.store %arg, %1 : vector<4xi32>, !llvm.ptr
+  // CHECK-NEXT: ptr.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : vector<4xi32>, !llvm.ptr
   llvm.return
 }
 
@@ -314,7 +314,7 @@ llvm.func @store_to_memory(%arg: !llvm.ptr) {
   %0 = llvm.mlir.constant(1 : i32) : i32
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (vector<4xf32>)> : (i32) -> !llvm.ptr
-  // CHECK-NEXT: llvm.store %[[ALLOCA]], %[[ARG]]
-  llvm.store %1, %arg : !llvm.ptr, !llvm.ptr
+  // CHECK-NEXT: ptr.store %[[ALLOCA]], %[[ARG]]
+  ptr.store %1, %arg : !llvm.ptr, !llvm.ptr
   llvm.return
 }
diff --git a/mlir/test/Dialect/LLVMIR/tbaa-invalid.mlir b/mlir/test/Dialect/LLVMIR/tbaa-invalid.mlir
index 5a58e2098675be..7be6b275a51bc7 100644
--- a/mlir/test/Dialect/LLVMIR/tbaa-invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/tbaa-invalid.mlir
@@ -1,27 +1,27 @@
 // RUN: mlir-opt -split-input-file -verify-diagnostics %s
 
-#tbaa_root = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-#tbaa_desc = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
-#tbaa_tag = #llvm.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_desc, offset = 0>
+#tbaa_root = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+#tbaa_desc = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
+#tbaa_tag = #ptr.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_desc, offset = 0>
 // expected-error at +2 {{invalid kind of attribute specified}}
-// expected-error at below {{failed to parse LLVM_TBAATagAttr parameter 'access_type' which is to be a `TBAATypeDescriptorAttr`}}
-#tbaa_tag2 = #llvm.tbaa_tag<access_type = #tbaa_tag, base_type = #tbaa_desc, offset = 0>
+// expected-error at below {{failed to parse Ptr_TBAATagAttr parameter 'access_type' which is to be a `TBAATypeDescriptorAttr`}}
+#tbaa_tag2 = #ptr.tbaa_tag<access_type = #tbaa_tag, base_type = #tbaa_desc, offset = 0>
 
 // -----
 
-#tbaa_root = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-#tbaa_desc = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
-#tbaa_tag = #llvm.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_desc, offset = 0>
+#tbaa_root = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+#tbaa_desc = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
+#tbaa_tag = #ptr.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_desc, offset = 0>
 // expected-error at +2 {{invalid kind of attribute specified}}
-// expected-error at below {{failed to parse LLVM_TBAATagAttr parameter 'base_type' which is to be a `TBAATypeDescriptorAttr`}}
-#tbaa_tag2 = #llvm.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_tag, offset = 0>
+// expected-error at below {{failed to parse Ptr_TBAATagAttr parameter 'base_type' which is to be a `TBAATypeDescriptorAttr`}}
+#tbaa_tag2 = #ptr.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_tag, offset = 0>
 
 // -----
 
-#tbaa_root = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-#tbaa_desc = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
-#tbaa_tag = #llvm.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_desc, offset = 0>
+#tbaa_root = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+#tbaa_desc = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root, 0>}>
+#tbaa_tag = #ptr.tbaa_tag<access_type = #tbaa_desc, base_type = #tbaa_desc, offset = 0>
 // expected-error at +3 {{invalid kind of attribute specified}}
-// expected-error at +2 {{failed to parse LLVM_TBAAMemberAttr parameter 'typeDesc' which is to be a `TBAANodeAttr`}}
-// expected-error at below {{failed to parse LLVM_TBAATypeDescriptorAttr parameter 'members' which is to be a `::llvm::ArrayRef<TBAAMemberAttr>`}}
-#tbaa_desc2 = #llvm.tbaa_type_desc<id = "long long", members = {<#tbaa_tag, 0>}>
+// expected-error at +2 {{failed to parse Ptr_TBAAMemberAttr parameter 'typeDesc' which is to be a `TBAANodeAttr`}}
+// expected-error at below {{failed to parse Ptr_TBAATypeDescriptorAttr parameter 'members' which is to be a `::llvm::ArrayRef<TBAAMemberAttr>`}}
+#tbaa_desc2 = #ptr.tbaa_type_desc<id = "long long", members = {<#tbaa_tag, 0>}>
diff --git a/mlir/test/Dialect/LLVMIR/tbaa-roundtrip.mlir b/mlir/test/Dialect/LLVMIR/tbaa-roundtrip.mlir
index 472ae609004c00..c436cdc62c064a 100644
--- a/mlir/test/Dialect/LLVMIR/tbaa-roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/tbaa-roundtrip.mlir
@@ -1,49 +1,49 @@
 // RUN: mlir-opt %s | mlir-opt | FileCheck %s
 
-#tbaa_root_0 = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-#tbaa_root_1 = #llvm.tbaa_root<id = "Other language TBAA">
-#tbaa_root_2 = #llvm.tbaa_root
-#tbaa_type_desc_0 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
-#tbaa_tag_0 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_0, base_type = #tbaa_type_desc_0, offset = 0>
-#tbaa_type_desc_1 = #llvm.tbaa_type_desc<id = "long long", members = {<#tbaa_type_desc_0, 0>}>
-#tbaa_type_desc_2 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_0, 0>}>
-#tbaa_type_desc_3 = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_1, 0>, <#tbaa_type_desc_1, 8>}>
-#tbaa_type_desc_4 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 4>}>
-#tbaa_tag_2 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_1, base_type = #tbaa_type_desc_3, offset = 8>
-#tbaa_tag_3 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_4, offset = 0>
-#tbaa_type_desc_5 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_1, 0>}>
-#tbaa_type_desc_6 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_2, 0>}>
-#tbaa_tag_4 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_6, base_type = #tbaa_type_desc_6, offset = 0>
-#tbaa_tag_1 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_5, offset = 0>
+#tbaa_root_0 = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+#tbaa_root_1 = #ptr.tbaa_root<id = "Other language TBAA">
+#tbaa_root_2 = #ptr.tbaa_root
+#tbaa_type_desc_0 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
+#tbaa_tag_0 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_0, base_type = #tbaa_type_desc_0, offset = 0>
+#tbaa_type_desc_1 = #ptr.tbaa_type_desc<id = "long long", members = {<#tbaa_type_desc_0, 0>}>
+#tbaa_type_desc_2 = #ptr.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_0, 0>}>
+#tbaa_type_desc_3 = #ptr.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_1, 0>, <#tbaa_type_desc_1, 8>}>
+#tbaa_type_desc_4 = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 4>}>
+#tbaa_tag_2 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_1, base_type = #tbaa_type_desc_3, offset = 8>
+#tbaa_tag_3 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_4, offset = 0>
+#tbaa_type_desc_5 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_1, 0>}>
+#tbaa_type_desc_6 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_2, 0>}>
+#tbaa_tag_4 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_6, base_type = #tbaa_type_desc_6, offset = 0>
+#tbaa_tag_1 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_5, offset = 0>
 
-// CHECK-DAG: #[[$ROOT_0:.*]] = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-// CHECK-DAG: #[[$ROOT_1:.*]] = #llvm.tbaa_root<id = "Other language TBAA">
-// CHECK-DAG: #[[$ROOT_2:.*]] = #llvm.tbaa_root
+// CHECK-DAG: #[[$ROOT_0:.*]] = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+// CHECK-DAG: #[[$ROOT_1:.*]] = #ptr.tbaa_root<id = "Other language TBAA">
+// CHECK-DAG: #[[$ROOT_2:.*]] = #ptr.tbaa_root
 // CHECK-NOT: <{{.*}}>
-// CHECK-DAG: #[[$DESC_0:.*]] = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#[[$ROOT_0]], 0>}>
-// CHECK-DAG: #[[$DESC_1:.*]] = #llvm.tbaa_type_desc<id = "long long", members = {<#[[$DESC_0]], 0>}>
-// CHECK-DAG: #[[$DESC_2:.*]] = #llvm.tbaa_type_desc<id = "int", members = {<#[[$DESC_0]], 0>}>
-// CHECK-DAG: #[[$DESC_3:.*]] = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#[[$DESC_1]], 0>, <#[[$DESC_1]], 8>}>
-// CHECK-DAG: #[[$DESC_4:.*]] = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#[[$DESC_2]], 0>, <#[[$DESC_2]], 4>}>
-// CHECK-DAG: #[[$DESC_5:.*]] = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#[[$ROOT_1]], 0>}>
-// CHECK-DAG: #[[$DESC_6:.*]] = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#[[$ROOT_2]], 0>}>
-// CHECK-DAG: #[[$TAG_0:.*]] = #llvm.tbaa_tag<base_type = #[[$DESC_0]], access_type = #[[$DESC_0]], offset = 0>
-// CHECK-DAG: #[[$TAG_1:.*]] = #llvm.tbaa_tag<base_type = #[[$DESC_5]], access_type = #[[$DESC_5]], offset = 0>
-// CHECK-DAG: #[[$TAG_2:.*]] = #llvm.tbaa_tag<base_type = #[[$DESC_3]], access_type = #[[$DESC_1]], offset = 8>
-// CHECK-DAG: #[[$TAG_3:.*]] = #llvm.tbaa_tag<base_type = #[[$DESC_4]], access_type = #[[$DESC_2]], offset = 0>
-// CHECK-DAG: #[[$TAG_4:.*]] = #llvm.tbaa_tag<base_type = #[[$DESC_6]], access_type = #[[$DESC_6]], offset = 0>
+// CHECK-DAG: #[[$DESC_0:.*]] = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#[[$ROOT_0]], 0>}>
+// CHECK-DAG: #[[$DESC_1:.*]] = #ptr.tbaa_type_desc<id = "long long", members = {<#[[$DESC_0]], 0>}>
+// CHECK-DAG: #[[$DESC_2:.*]] = #ptr.tbaa_type_desc<id = "int", members = {<#[[$DESC_0]], 0>}>
+// CHECK-DAG: #[[$DESC_3:.*]] = #ptr.tbaa_type_desc<id = "agg2_t", members = {<#[[$DESC_1]], 0>, <#[[$DESC_1]], 8>}>
+// CHECK-DAG: #[[$DESC_4:.*]] = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#[[$DESC_2]], 0>, <#[[$DESC_2]], 4>}>
+// CHECK-DAG: #[[$DESC_5:.*]] = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#[[$ROOT_1]], 0>}>
+// CHECK-DAG: #[[$DESC_6:.*]] = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#[[$ROOT_2]], 0>}>
+// CHECK-DAG: #[[$TAG_0:.*]] = #ptr.tbaa_tag<base_type = #[[$DESC_0]], access_type = #[[$DESC_0]], offset = 0>
+// CHECK-DAG: #[[$TAG_1:.*]] = #ptr.tbaa_tag<base_type = #[[$DESC_5]], access_type = #[[$DESC_5]], offset = 0>
+// CHECK-DAG: #[[$TAG_2:.*]] = #ptr.tbaa_tag<base_type = #[[$DESC_3]], access_type = #[[$DESC_1]], offset = 8>
+// CHECK-DAG: #[[$TAG_3:.*]] = #ptr.tbaa_tag<base_type = #[[$DESC_4]], access_type = #[[$DESC_2]], offset = 0>
+// CHECK-DAG: #[[$TAG_4:.*]] = #ptr.tbaa_tag<base_type = #[[$DESC_6]], access_type = #[[$DESC_6]], offset = 0>
 
 llvm.func @tbaa1(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   %0 = llvm.mlir.constant(1 : i8) : i8
-  llvm.store %0, %arg0 {tbaa = [#tbaa_tag_0]} : i8, !llvm.ptr
-  llvm.store %0, %arg1 {tbaa = [#tbaa_tag_1]} : i8, !llvm.ptr
+  ptr.store %0, %arg0 {tbaa = [#tbaa_tag_0]} : i8, !llvm.ptr
+  ptr.store %0, %arg1 {tbaa = [#tbaa_tag_1]} : i8, !llvm.ptr
   llvm.return
 }
 
 // CHECK:           llvm.func @tbaa1(%[[VAL_0:.*]]: !llvm.ptr, %[[VAL_1:.*]]: !llvm.ptr) {
 // CHECK:             %[[VAL_2:.*]] = llvm.mlir.constant(1 : i8) : i8
-// CHECK:             llvm.store %[[VAL_2]], %[[VAL_0]] {tbaa = [#[[$TAG_0]]]} : i8, !llvm.ptr
-// CHECK:             llvm.store %[[VAL_2]], %[[VAL_1]] {tbaa = [#[[$TAG_1]]]} : i8, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_2]], %[[VAL_0]] {tbaa = [#[[$TAG_0]]]} : i8, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_2]], %[[VAL_1]] {tbaa = [#[[$TAG_1]]]} : i8, !llvm.ptr
 // CHECK:             llvm.return
 // CHECK:           }
 
@@ -51,10 +51,10 @@ llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   %0 = llvm.mlir.constant(0 : i32) : i32
   %1 = llvm.mlir.constant(1 : i32) : i32
   %2 = llvm.getelementptr inbounds %arg1[%0, 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg2_t", (i64, i64)>
-  %3 = llvm.load %2 {tbaa = [#tbaa_tag_2]} : !llvm.ptr -> i64
+  %3 = ptr.load %2 {tbaa = [#tbaa_tag_2]} : !llvm.ptr -> i64
   %4 = llvm.trunc %3 : i64 to i32
   %5 = llvm.getelementptr inbounds %arg0[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
-  llvm.store %4, %5 {tbaa = [#tbaa_tag_3]} : i32, !llvm.ptr
+  ptr.store %4, %5 {tbaa = [#tbaa_tag_3]} : i32, !llvm.ptr
   llvm.return
 }
 
@@ -62,33 +62,33 @@ llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
 // CHECK:             %[[VAL_2:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK:             %[[VAL_3:.*]] = llvm.mlir.constant(1 : i32) : i32
 // CHECK:             %[[VAL_4:.*]] = llvm.getelementptr inbounds %[[VAL_1]]{{\[}}%[[VAL_2]], 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg2_t", (i64, i64)>
-// CHECK:             %[[VAL_5:.*]] = llvm.load %[[VAL_4]] {tbaa = [#[[$TAG_2]]]} : !llvm.ptr -> i64
+// CHECK:             %[[VAL_5:.*]] = ptr.load %[[VAL_4]] {tbaa = [#[[$TAG_2]]]} : !llvm.ptr -> i64
 // CHECK:             %[[VAL_6:.*]] = llvm.trunc %[[VAL_5]] : i64 to i32
 // CHECK:             %[[VAL_7:.*]] = llvm.getelementptr inbounds %[[VAL_0]]{{\[}}%[[VAL_2]], 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
-// CHECK:             llvm.store %[[VAL_6]], %[[VAL_7]] {tbaa = [#[[$TAG_3]]]} : i32, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_6]], %[[VAL_7]] {tbaa = [#[[$TAG_3]]]} : i32, !llvm.ptr
 // CHECK:             llvm.return
 // CHECK:           }
 
 llvm.func @tbaa3(%arg0: !llvm.ptr) {
   %0 = llvm.mlir.constant(1 : i8) : i8
-  llvm.store %0, %arg0 {tbaa = [#tbaa_tag_0, #tbaa_tag_1]} : i8, !llvm.ptr
+  ptr.store %0, %arg0 {tbaa = [#tbaa_tag_0, #tbaa_tag_1]} : i8, !llvm.ptr
   llvm.return
 }
 
 // CHECK:           llvm.func @tbaa3(%[[VAL_0:.*]]: !llvm.ptr) {
 // CHECK:             %[[VAL_1:.*]] = llvm.mlir.constant(1 : i8) : i8
-// CHECK:             llvm.store %[[VAL_1]], %[[VAL_0]] {tbaa = [#[[$TAG_0]], #[[$TAG_1]]]} : i8, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_1]], %[[VAL_0]] {tbaa = [#[[$TAG_0]], #[[$TAG_1]]]} : i8, !llvm.ptr
 // CHECK:             llvm.return
 // CHECK:           }
 
 llvm.func @tbaa4(%arg0: !llvm.ptr) {
   %0 = llvm.mlir.constant(1 : i8) : i8
-  llvm.store %0, %arg0 {tbaa = [#tbaa_tag_4]} : i8, !llvm.ptr
+  ptr.store %0, %arg0 {tbaa = [#tbaa_tag_4]} : i8, !llvm.ptr
   llvm.return
 }
 
 // CHECK:           llvm.func @tbaa4(%[[VAL_0:.*]]: !llvm.ptr) {
 // CHECK:             %[[VAL_1:.*]] = llvm.mlir.constant(1 : i8) : i8
-// CHECK:             llvm.store %[[VAL_1]], %[[VAL_0]] {tbaa = [#[[$TAG_4]]]} : i8, !llvm.ptr
+// CHECK:             ptr.store %[[VAL_1]], %[[VAL_0]] {tbaa = [#[[$TAG_4]]]} : i8, !llvm.ptr
 // CHECK:             llvm.return
 // CHECK:           }
diff --git a/mlir/test/Dialect/LLVMIR/type-consistency.mlir b/mlir/test/Dialect/LLVMIR/type-consistency.mlir
index a6176142f17463..92fa23dcae2342 100644
--- a/mlir/test/Dialect/LLVMIR/type-consistency.mlir
+++ b/mlir/test/Dialect/LLVMIR/type-consistency.mlir
@@ -7,7 +7,7 @@ llvm.func @same_address(%arg: i32) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
   // CHECK: = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32)>
   %7 = llvm.getelementptr %1[8] : (!llvm.ptr) -> !llvm.ptr, i8
-  llvm.store %arg, %7 : i32, !llvm.ptr
+  ptr.store %arg, %7 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -20,7 +20,7 @@ llvm.func @same_address_keep_inbounds(%arg: i32) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
   // CHECK: = llvm.getelementptr inbounds %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32)>
   %7 = llvm.getelementptr inbounds %1[8] : (!llvm.ptr) -> !llvm.ptr, i8
-  llvm.store %arg, %7 : i32, !llvm.ptr
+  ptr.store %arg, %7 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -33,7 +33,7 @@ llvm.func @index_in_final_padding(%arg: i32) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i8)> : (i32) -> !llvm.ptr
   // CHECK: = llvm.getelementptr %[[ALLOCA]][7] : (!llvm.ptr) -> !llvm.ptr, i8
   %7 = llvm.getelementptr %1[7] : (!llvm.ptr) -> !llvm.ptr, i8
-  llvm.store %arg, %7 : i32, !llvm.ptr
+  ptr.store %arg, %7 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -46,7 +46,7 @@ llvm.func @index_out_of_bounds(%arg: i32) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr
   // CHECK: = llvm.getelementptr %[[ALLOCA]][9] : (!llvm.ptr) -> !llvm.ptr, i8
   %7 = llvm.getelementptr %1[9] : (!llvm.ptr) -> !llvm.ptr, i8
-  llvm.store %arg, %7 : i32, !llvm.ptr
+  ptr.store %arg, %7 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -59,7 +59,7 @@ llvm.func @index_in_padding(%arg: i16) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, i32)> : (i32) -> !llvm.ptr
   // CHECK: = llvm.getelementptr %[[ALLOCA]][2] : (!llvm.ptr) -> !llvm.ptr, i8
   %7 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8
-  llvm.store %arg, %7 : i16, !llvm.ptr
+  ptr.store %arg, %7 : i16, !llvm.ptr
   llvm.return
 }
 
@@ -72,7 +72,7 @@ llvm.func @index_not_in_padding_because_packed(%arg: i16) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", packed (i16, i32)> : (i32) -> !llvm.ptr
   // CHECK: = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i16, i32)>
   %7 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8
-  llvm.store %arg, %7 : i16, !llvm.ptr
+  ptr.store %arg, %7 : i16, !llvm.ptr
   llvm.return
 }
 
@@ -86,7 +86,7 @@ llvm.func @no_crash_on_negative_gep_index() {
   %2 = llvm.alloca %1 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
   // CHECK: llvm.getelementptr %[[ALLOCA]][-1] : (!llvm.ptr) -> !llvm.ptr, f32
   %3 = llvm.getelementptr %2[-1] : (!llvm.ptr) -> !llvm.ptr, f32
-  llvm.store %0, %3 : f16, !llvm.ptr
+  ptr.store %0, %3 : f16, !llvm.ptr
   llvm.return
 }
 
@@ -104,13 +104,13 @@ llvm.func @coalesced_store_ints(%arg: i64) {
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
-  // CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[ALLOCA]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -129,13 +129,13 @@ llvm.func @coalesced_store_ints_offset(%arg: i64) {
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32)>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32)>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
-  llvm.store %arg, %3 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
+  ptr.store %arg, %3 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -153,14 +153,14 @@ llvm.func @coalesced_store_floats(%arg: i64) {
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
-  // CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[ALLOCA]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<"foo", (f32, f32)>
   // CHECK: %[[BIT_CAST:.*]] = llvm.bitcast %[[TRUNC]] : i32 to f32
-  // CHECK: llvm.store %[[BIT_CAST]], %[[GEP]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[BIT_CAST]], %[[GEP]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -175,8 +175,8 @@ llvm.func @coalesced_store_padding_inbetween(%arg: i64) {
 
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, i32)>
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, i32)> : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
+  // CHECK: ptr.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
   llvm.return
 }
 
@@ -191,8 +191,8 @@ llvm.func @coalesced_store_padding_end(%arg: i64) {
 
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i16)>
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i16)> : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
+  // CHECK: ptr.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
   llvm.return
 }
 
@@ -205,8 +205,8 @@ llvm.func @coalesced_store_past_end(%arg: i64) {
 
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32)>
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32)> : (i32) -> !llvm.ptr
-  // CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
+  // CHECK: ptr.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
   llvm.return
 }
 
@@ -224,17 +224,17 @@ llvm.func @coalesced_store_packed_struct(%arg: i64) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", packed (i16, i32, i16)> : (i32) -> !llvm.ptr
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
-  // CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[ALLOCA]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST16]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i16, i32, i16)>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST48]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i16, i32, i16)>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -252,22 +252,22 @@ llvm.func @vector_write_split(%arg: vector<4xi32>) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32, i32)> : (i32) -> !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST0]] : i32] : vector<4xi32>
-  // CHECK: llvm.store %[[EXTRACT]], %[[ALLOCA]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[ALLOCA]] : i32, !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST1]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST2]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST3]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
-  llvm.store %arg, %1 : vector<4xi32>, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : vector<4xi32>, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -287,22 +287,22 @@ llvm.func @vector_write_split_offset(%arg: vector<4xi32>) {
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST0]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST1]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST2]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST3]] : i32] : vector<4xi32>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
 
-  llvm.store %arg, %2 : vector<4xi32>, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %2 : vector<4xi32>, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -318,10 +318,10 @@ llvm.func @vector_write_split_struct(%arg: vector<2xi64>) {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32, i32)>
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32, i32)> : (i32) -> !llvm.ptr
 
-  // CHECK-COUNT-4: llvm.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
+  // CHECK-COUNT-4: ptr.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
 
-  llvm.store %arg, %1 : vector<2xi64>, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : vector<2xi64>, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -334,9 +334,9 @@ llvm.func @bitcast_insertion(%arg: i32) {
   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x f32
   %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
   // CHECK: %[[BIT_CAST:.*]] = llvm.bitcast %[[ARG]] : i32 to f32
-  // CHECK: llvm.store %[[BIT_CAST]], %[[ALLOCA]]
-  llvm.store %arg, %1 : i32, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[BIT_CAST]], %[[ALLOCA]]
+  ptr.store %arg, %1 : i32, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -351,9 +351,9 @@ llvm.func @gep_split(%arg: i64) {
   %3 = llvm.getelementptr %1[0, 1, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
   // CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64)>
-  // CHECK: llvm.store %[[ARG]], %[[GEP]]
-  llvm.store %arg, %3 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[ARG]], %[[GEP]]
+  ptr.store %arg, %3 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -372,13 +372,13 @@ llvm.func @coalesced_store_ints_subaggregate(%arg: i64) {
   // CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, struct<(i32, i32)>)>
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
-  // CHECK: llvm.store %[[TRUNC]], %[[TOP_GEP]]
+  // CHECK: ptr.store %[[TRUNC]], %[[TOP_GEP]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<(i32, i32)>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
-  llvm.store %arg, %3 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
+  ptr.store %arg, %3 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -393,9 +393,9 @@ llvm.func @gep_result_ptr_type_dynamic(%arg: i64) {
   %3 = llvm.getelementptr %1[0, %arg, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
   // CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, %[[ARG]]] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64)>
-  // CHECK: llvm.store %[[ARG]], %[[GEP]]
-  llvm.store %arg, %3 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[ARG]], %[[GEP]]
+  ptr.store %arg, %3 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -413,7 +413,7 @@ llvm.func @overlapping_int_aggregate_store(%arg: i64) {
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
-  // CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[ALLOCA]]
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST16]] : i64
   // CHECK: [[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i48
@@ -421,14 +421,14 @@ llvm.func @overlapping_int_aggregate_store(%arg: i64) {
 
   // Normal integer splitting of [[TRUNC]] follows:
 
-  // CHECK: llvm.store %{{.*}}, %[[TOP_GEP]]
+  // CHECK: ptr.store %{{.*}}, %[[TOP_GEP]]
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
-  // CHECK: llvm.store %{{.*}}, %[[GEP]]
+  // CHECK: ptr.store %{{.*}}, %[[GEP]]
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 2] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
-  // CHECK: llvm.store %{{.*}}, %[[GEP]]
+  // CHECK: ptr.store %{{.*}}, %[[GEP]]
 
-  llvm.store %arg, %1 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -447,24 +447,24 @@ llvm.func @overlapping_vector_aggregate_store(%arg: vector<4 x i16>) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)> : (i32) -> !llvm.ptr
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST0]] : i32]
-  // CHECK: llvm.store %[[EXTRACT]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[EXTRACT]], %[[ALLOCA]]
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST1]] : i32]
   // CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP0]]
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP0]]
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST2]] : i32]
   // CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
   // CHECK: %[[GEP1:.*]] = llvm.getelementptr %[[GEP0]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP1]]
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP1]]
 
   // CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST3]] : i32]
   // CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
   // CHECK: %[[GEP1:.*]] = llvm.getelementptr %[[GEP0]][0, 2] : (!llvm.ptr)  -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
-  // CHECK: llvm.store %[[EXTRACT]], %[[GEP1]]
+  // CHECK: ptr.store %[[EXTRACT]], %[[GEP1]]
 
-  llvm.store %arg, %1 : vector<4 x i16>, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  ptr.store %arg, %1 : vector<4 x i16>, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
 
@@ -482,7 +482,7 @@ llvm.func @partially_overlapping_aggregate_store(%arg: i64) {
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
-  // CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[ALLOCA]]
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST16]] : i64
   // CHECK: [[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i48
@@ -490,18 +490,18 @@ llvm.func @partially_overlapping_aggregate_store(%arg: i64) {
 
   // Normal integer splitting of [[TRUNC]] follows:
 
-  // CHECK: llvm.store %{{.*}}, %[[TOP_GEP]]
+  // CHECK: ptr.store %{{.*}}, %[[TOP_GEP]]
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16, i16)>
-  // CHECK: llvm.store %{{.*}}, %[[GEP]]
+  // CHECK: ptr.store %{{.*}}, %[[GEP]]
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16, i16)>
-  // CHECK: llvm.store %{{.*}}, %[[GEP]]
+  // CHECK: ptr.store %{{.*}}, %[[GEP]]
 
   // It is important that there are no more stores at this point.
   // Specifically a store into the fourth field of %[[TOP_GEP]] would
   // incorrectly change the semantics of the code.
-  // CHECK-NOT: llvm.store %{{.*}}, %{{.*}}
+  // CHECK-NOT: ptr.store %{{.*}}, %{{.*}}
 
-  llvm.store %arg, %1 : i64, !llvm.ptr
+  ptr.store %arg, %1 : i64, !llvm.ptr
 
   llvm.return
 }
@@ -518,8 +518,8 @@ llvm.func @undesirable_overlapping_aggregate_store(%arg: i64) {
   %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)> : (i32) -> !llvm.ptr
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)>
   %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)>
-  // CHECK: llvm.store %[[ARG]], %[[GEP]]
-  llvm.store %arg, %2 : i64, !llvm.ptr
+  // CHECK: ptr.store %[[ARG]], %[[GEP]]
+  ptr.store %arg, %2 : i64, !llvm.ptr
 
   llvm.return
 }
@@ -538,12 +538,12 @@ llvm.func @coalesced_store_ints_array(%arg: i64) {
 
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
-  // CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[ALLOCA]]
   // CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
   // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
   // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr)  -> !llvm.ptr, !llvm.array<2 x i32>
-  // CHECK: llvm.store %[[TRUNC]], %[[GEP]]
-  llvm.store %arg, %1 : i64, !llvm.ptr
-  // CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
+  // CHECK: ptr.store %[[TRUNC]], %[[GEP]]
+  ptr.store %arg, %1 : i64, !llvm.ptr
+  // CHECK-NOT: ptr.store %[[ARG]], %[[ALLOCA]]
   llvm.return
 }
diff --git a/mlir/test/Dialect/MemRef/transform-ops.mlir b/mlir/test/Dialect/MemRef/transform-ops.mlir
index acab37e482cfeb..8b1edaaf5d373f 100644
--- a/mlir/test/Dialect/MemRef/transform-ops.mlir
+++ b/mlir/test/Dialect/MemRef/transform-ops.mlir
@@ -369,7 +369,7 @@ module attributes {transform.with_named_sequence} {
       transform.apply_conversion_patterns.dialect_to_llvm "memref"
     } with type_converter {
       transform.apply_conversion_patterns.memref.memref_to_llvm_type_converter
-    } {legal_dialects = ["func", "llvm"]} : !transform.any_op
+    } {legal_dialects = ["func", "ptr", "llvm"]} : !transform.any_op
     transform.yield
   }
 }
diff --git a/mlir/test/Dialect/OpenACC/invalid.mlir b/mlir/test/Dialect/OpenACC/invalid.mlir
index ec5430420524ce..567b80eae68b03 100644
--- a/mlir/test/Dialect/OpenACC/invalid.mlir
+++ b/mlir/test/Dialect/OpenACC/invalid.mlir
@@ -318,7 +318,7 @@ acc.private.recipe @privatization_i32 : !llvm.ptr init {
   %c1 = arith.constant 1 : i32
   %c0 = arith.constant 0 : i32
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
-  llvm.store %c0, %0 : i32, !llvm.ptr
+  ptr.store %c0, %0 : i32, !llvm.ptr
   acc.yield %0 : !llvm.ptr
 } destroy {
 ^bb0(%arg0 : f32):
@@ -349,7 +349,7 @@ acc.firstprivate.recipe @privatization_i32 : !llvm.ptr init {
   %c1 = arith.constant 1 : i32
   %c0 = arith.constant 0 : i32
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
-  llvm.store %c0, %0 : i32, !llvm.ptr
+  ptr.store %c0, %0 : i32, !llvm.ptr
   acc.yield %0 : !llvm.ptr
 } copy {
 }
@@ -362,7 +362,7 @@ acc.firstprivate.recipe @privatization_i32 : !llvm.ptr init {
   %c1 = arith.constant 1 : i32
   %c0 = arith.constant 0 : i32
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
-  llvm.store %c0, %0 : i32, !llvm.ptr
+  ptr.store %c0, %0 : i32, !llvm.ptr
   acc.yield %0 : !llvm.ptr
 } copy {
 ^bb0(%arg0 : f32):
@@ -377,7 +377,7 @@ acc.firstprivate.recipe @privatization_i32 : !llvm.ptr init {
   %c1 = arith.constant 1 : i32
   %c0 = arith.constant 0 : i32
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
-  llvm.store %c0, %0 : i32, !llvm.ptr
+  ptr.store %c0, %0 : i32, !llvm.ptr
   acc.yield %0 : !llvm.ptr
 } copy {
 ^bb0(%arg0 : f32, %arg1 : i32):
@@ -393,7 +393,7 @@ acc.firstprivate.recipe @privatization_i32 : i32 init {
   acc.yield %0 : i32
 } copy {
 ^bb0(%arg0 : i32, %arg1 : !llvm.ptr):
-  llvm.store %arg0, %arg1 : i32, !llvm.ptr
+  ptr.store %arg0, %arg1 : i32, !llvm.ptr
   acc.yield
 } destroy {
 ^bb0(%arg0 : f32):
diff --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir
index 2ef2178cb2b63a..461d94e9b2e214 100644
--- a/mlir/test/Dialect/OpenACC/ops.mlir
+++ b/mlir/test/Dialect/OpenACC/ops.mlir
@@ -1407,7 +1407,7 @@ acc.private.recipe @privatization_i32 : !llvm.ptr init {
   %c1 = arith.constant 1 : i32
   %c0 = arith.constant 0 : i32
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
-  llvm.store %c0, %0 : i32, !llvm.ptr
+  ptr.store %c0, %0 : i32, !llvm.ptr
   acc.yield %0 : !llvm.ptr
 }
 
@@ -1415,7 +1415,7 @@ acc.private.recipe @privatization_i32 : !llvm.ptr init {
 // CHECK: %[[C1:.*]] = arith.constant 1 : i32
 // CHECK: %[[C0:.*]] = arith.constant 0 : i32
 // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[C1]] x i32 : (i32) -> !llvm.ptr
-// CHECK: llvm.store %[[C0]], %[[ALLOCA]] : i32, !llvm.ptr
+// CHECK: ptr.store %[[C0]], %[[ALLOCA]] : i32, !llvm.ptr
 // CHECK: acc.yield %[[ALLOCA]] : !llvm.ptr
 
 // -----
diff --git a/mlir/test/Dialect/OpenMP/canonicalize.mlir b/mlir/test/Dialect/OpenMP/canonicalize.mlir
index de6c931ecc5fd9..8b4848803cc1df 100644
--- a/mlir/test/Dialect/OpenMP/canonicalize.mlir
+++ b/mlir/test/Dialect/OpenMP/canonicalize.mlir
@@ -133,7 +133,7 @@ func.func @constant_hoisting_target(%x : !llvm.ptr) {
   omp.target {
     ^bb0(%arg0: !llvm.ptr):
     %c1 = arith.constant 10 : i32
-    llvm.store %c1, %arg0 : i32, !llvm.ptr
+    ptr.store %c1, %arg0 : i32, !llvm.ptr
     omp.terminator
   }
   return
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index a00383cf44057c..6859a016bfce60 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -494,8 +494,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -1376,8 +1376,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> i32
-  llvm.atomicrmw add %arg2, %2 monotonic : !llvm.ptr, i32
+  %2 = ptr.load %arg3 : !llvm.ptr -> i32
+  ptr.atomicrmw add %arg2, %2 monotonic : !llvm.ptr, i32
   omp.yield
 }
 
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 30ce77423005ac..7b74f8a4c57603 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -616,8 +616,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -630,12 +630,12 @@ func.func @wsloop_reduction(%lb : index, %ub : index, %step : index) {
   for (%iv) : index = (%lb) to (%ub) step (%step) {
     // CHECK: %[[CST:.+]] = arith.constant 2.0{{.*}} : f32
     %cst = arith.constant 2.0 : f32
-    // CHECK: %[[LPRV:.+]] = llvm.load %[[PRV]] : !llvm.ptr -> f32
-    %lprv = llvm.load %prv : !llvm.ptr -> f32
+    // CHECK: %[[LPRV:.+]] = ptr.load %[[PRV]] : !llvm.ptr -> f32
+    %lprv = ptr.load %prv : !llvm.ptr -> f32
     // CHECK: %[[RES:.+]] = llvm.fadd %[[LPRV]], %[[CST]] : f32
     %res = llvm.fadd %lprv, %cst: f32
-    // CHECK: llvm.store %[[RES]], %[[PRV]] :  f32, !llvm.ptr
-    llvm.store %res, %prv :  f32, !llvm.ptr
+    // CHECK: ptr.store %[[RES]], %[[PRV]] :  f32, !llvm.ptr
+    ptr.store %res, %prv :  f32, !llvm.ptr
     omp.yield
   }
   return
@@ -648,10 +648,10 @@ func.func @parallel_reduction() {
   // CHECK: omp.parallel reduction(@add_f32 {{.+}} -> {{.+}} : !llvm.ptr)
   omp.parallel reduction(@add_f32 %0 -> %prv : !llvm.ptr) {
     %1 = arith.constant 2.0 : f32
-    %2 = llvm.load %prv : !llvm.ptr -> f32
+    %2 = ptr.load %prv : !llvm.ptr -> f32
     // CHECK: llvm.fadd %{{.*}}, %{{.*}} : f32
     %3 = llvm.fadd %1, %2 : f32
-    llvm.store %3, %prv : f32, !llvm.ptr
+    ptr.store %3, %prv : f32, !llvm.ptr
     omp.terminator
   }
   return
@@ -666,7 +666,7 @@ func.func @parallel_wsloop_reduction(%lb : index, %ub : index, %step : index) {
     // CHECK: omp.wsloop for (%{{.+}}) : index = (%{{.+}}) to (%{{.+}}) step (%{{.+}})
     omp.wsloop for (%iv) : index = (%lb) to (%ub) step (%step) {
       %1 = arith.constant 2.0 : f32
-      %2 = llvm.load %prv : !llvm.ptr -> f32
+      %2 = ptr.load %prv : !llvm.ptr -> f32
       // CHECK: llvm.fadd %{{.+}}, %{{.+}} : f32
       llvm.fadd %1, %2 : f32
       // CHECK: omp.yield
@@ -832,7 +832,7 @@ func.func @parallel_wsloop_reduction2(%lb : index, %ub : index, %step : index) {
     // CHECK: omp.wsloop for (%{{.+}}) : index = (%{{.+}}) to (%{{.+}}) step (%{{.+}})
     omp.wsloop for (%iv) : index = (%lb) to (%ub) step (%step) {
       %1 = arith.constant 2.0 : f32
-      %2 = llvm.load %prv : !llvm.ptr -> f32
+      %2 = ptr.load %prv : !llvm.ptr -> f32
       // CHECK: llvm.fadd %{{.+}}, %{{.+}} : f32
       %3 = llvm.fadd %1, %2 : f32
       // CHECK: omp.yield
@@ -1763,16 +1763,16 @@ func.func @omp_threadprivate() {
   // CHECK: {{.*}} = omp.threadprivate [[ARG0]] : !llvm.ptr -> !llvm.ptr
   %3 = llvm.mlir.addressof @_QFsubEx : !llvm.ptr
   %4 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
-  llvm.store %0, %4 : i32, !llvm.ptr
+  ptr.store %0, %4 : i32, !llvm.ptr
 
   // CHECK:  omp.parallel
   // CHECK:    {{.*}} = omp.threadprivate [[ARG0]] : !llvm.ptr -> !llvm.ptr
   omp.parallel  {
     %5 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
-    llvm.store %1, %5 : i32, !llvm.ptr
+    ptr.store %1, %5 : i32, !llvm.ptr
     omp.terminator
   }
-  llvm.store %2, %4 : i32, !llvm.ptr
+  ptr.store %2, %4 : i32, !llvm.ptr
   return
 }
 
@@ -2069,14 +2069,14 @@ func.func @omp_requires_multiple() -> ()
 // CHECK-SAME: (%[[v:.*]]: !llvm.ptr, %[[x:.*]]: !llvm.ptr)
 func.func @opaque_pointers_atomic_rwu(%v: !llvm.ptr, %x: !llvm.ptr) {
   // CHECK: omp.atomic.read %[[v]] = %[[x]] : !llvm.ptr, i32
-  // CHECK: %[[VAL:.*]] = llvm.load %[[x]] : !llvm.ptr -> i32
+  // CHECK: %[[VAL:.*]] = ptr.load %[[x]] : !llvm.ptr -> i32
   // CHECK: omp.atomic.write %[[v]] = %[[VAL]] : !llvm.ptr, i32
   // CHECK: omp.atomic.update %[[x]] : !llvm.ptr {
   // CHECK-NEXT: ^{{[[:alnum:]]+}}(%[[XVAL:.*]]: i32):
   // CHECK-NEXT:   omp.yield(%[[XVAL]] : i32)
   // CHECK-NEXT: }
   omp.atomic.read %v = %x : !llvm.ptr, i32
-  %val = llvm.load %x : !llvm.ptr -> i32
+  %val = ptr.load %x : !llvm.ptr -> i32
   omp.atomic.write %v = %val : !llvm.ptr, i32
   omp.atomic.update %x : !llvm.ptr {
     ^bb0(%xval: i32):
@@ -2101,8 +2101,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -2239,10 +2239,10 @@ func.func @parallel_op_privatizers(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   // CHECK-SAME: @x.privatizer %[[ARG0]] -> %[[ARG0_PRIV:[^[:space:]]+]] : !llvm.ptr,
   // CHECK-SAME: @y.privatizer %[[ARG1]] -> %[[ARG1_PRIV:[^[:space:]]+]] : !llvm.ptr)
   omp.parallel private(@x.privatizer %arg0 -> %arg2 : !llvm.ptr, @y.privatizer %arg1 -> %arg3 : !llvm.ptr) {
-    // CHECK: llvm.load %[[ARG0_PRIV]]
-    %0 = llvm.load %arg2 : !llvm.ptr -> i32
-    // CHECK: llvm.load %[[ARG1_PRIV]]
-    %1 = llvm.load %arg3 : !llvm.ptr -> i32
+    // CHECK: ptr.load %[[ARG0_PRIV]]
+    %0 = ptr.load %arg2 : !llvm.ptr -> i32
+    // CHECK: ptr.load %[[ARG1_PRIV]]
+    %1 = ptr.load %arg3 : !llvm.ptr -> i32
     omp.terminator
   }
   return
@@ -2279,14 +2279,14 @@ func.func @parallel_op_reduction_and_private(%priv_var: !llvm.ptr, %priv_var2: !
   // CHECK-SAME: @y.privatizer %[[PRIV_VAR2:[^[:space:]]+]] -> %[[PRIV_ARG2:[^[:space:]]+]] : !llvm.ptr)
   omp.parallel reduction(@add_f32 %reduc_var -> %reduc_arg : !llvm.ptr, @add_f32 %reduc_var2 -> %reduc_arg2 : !llvm.ptr)
                private(@x.privatizer %priv_var -> %priv_arg : !llvm.ptr, @y.privatizer %priv_var2 -> %priv_arg2 : !llvm.ptr) {
-    // CHECK: llvm.load %[[PRIV_ARG]]
-    %0 = llvm.load %priv_arg : !llvm.ptr -> f32
-    // CHECK: llvm.load %[[PRIV_ARG2]]
-    %1 = llvm.load %priv_arg2 : !llvm.ptr -> f32
-    // CHECK: llvm.load %[[REDUC_ARG]]
-    %2 = llvm.load %reduc_arg : !llvm.ptr -> f32
-    // CHECK: llvm.load %[[REDUC_ARG2]]
-    %3 = llvm.load %reduc_arg2 : !llvm.ptr -> f32
+    // CHECK: ptr.load %[[PRIV_ARG]]
+    %0 = ptr.load %priv_arg : !llvm.ptr -> f32
+    // CHECK: ptr.load %[[PRIV_ARG2]]
+    %1 = ptr.load %priv_arg2 : !llvm.ptr -> f32
+    // CHECK: ptr.load %[[REDUC_ARG]]
+    %2 = ptr.load %reduc_arg : !llvm.ptr -> f32
+    // CHECK: ptr.load %[[REDUC_ARG2]]
+    %3 = ptr.load %reduc_arg2 : !llvm.ptr -> f32
     omp.terminator
   }
   return
diff --git a/mlir/test/Integration/GPU/CUDA/sm90/asd b/mlir/test/Integration/GPU/CUDA/sm90/asd
index 353d8e7c16b741..5444a8a75c7f7b 100644
--- a/mlir/test/Integration/GPU/CUDA/sm90/asd
+++ b/mlir/test/Integration/GPU/CUDA/sm90/asd
@@ -29,11 +29,11 @@ module attributes {gpu.container_module} {
     %16 = llvm.mlir.constant(128 : index) : i64
     %17 = llvm.mlir.zero : !llvm.ptr
     %18 = llvm.getelementptr %17[16384] : (!llvm.ptr) -> !llvm.ptr, f16
-    %19 = llvm.ptrtoint %18 : !llvm.ptr to i64
+    %19 = ptr.ptrtoint %18 : !llvm.ptr to i64
     %20 = llvm.call @malloc(%19) : (i64) -> !llvm.ptr
     %21 = llvm.call @malloc(%19) : (i64) -> !llvm.ptr
     %22 = llvm.getelementptr %17[16384] : (!llvm.ptr) -> !llvm.ptr, f32
-    %23 = llvm.ptrtoint %22 : !llvm.ptr to i64
+    %23 = ptr.ptrtoint %22 : !llvm.ptr to i64
     %24 = llvm.call @malloc(%23) : (i64) -> !llvm.ptr
     %25 = llvm.call @malloc(%23) : (i64) -> !llvm.ptr
     llvm.br ^bb1(%15 : i64)
@@ -53,7 +53,7 @@ module attributes {gpu.container_module} {
     %34 = llvm.trunc %33 : i64 to i32
     %35 = llvm.sitofp %34 : i32 to f16
     %36 = llvm.getelementptr %21[%31] : (!llvm.ptr, i64) -> !llvm.ptr, f16
-    llvm.store %35, %36 : f16, !llvm.ptr
+    ptr.store %35, %36 : f16, !llvm.ptr
     %37 = llvm.mul %28, %2  : i64
     %38 = llvm.add %37, %26  : i64
     %39 = llvm.udiv %38, %5  : i64
@@ -63,11 +63,11 @@ module attributes {gpu.container_module} {
     %43 = llvm.mul %28, %16  : i64
     %44 = llvm.add %43, %26  : i64
     %45 = llvm.getelementptr %20[%44] : (!llvm.ptr, i64) -> !llvm.ptr, f16
-    llvm.store %42, %45 : f16, !llvm.ptr
+    ptr.store %42, %45 : f16, !llvm.ptr
     %46 = llvm.getelementptr %24[%31] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %6, %46 : f32, !llvm.ptr
+    ptr.store %6, %46 : f32, !llvm.ptr
     %47 = llvm.getelementptr %25[%31] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %6, %47 : f32, !llvm.ptr
+    ptr.store %6, %47 : f32, !llvm.ptr
     %48 = llvm.add %28, %14  : i64
     llvm.br ^bb3(%48 : i64)
   ^bb5:  // pred: ^bb3
@@ -96,18 +96,18 @@ module attributes {gpu.container_module} {
     llvm.call @mgpuMemcpy(%51, %20, %19, %50) : (!llvm.ptr, !llvm.ptr, i64, !llvm.ptr) -> ()
     llvm.call @mgpuMemcpy(%60, %21, %19, %50) : (!llvm.ptr, !llvm.ptr, i64, !llvm.ptr) -> ()
     %69 = llvm.alloca %14 x !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)> : (i64) -> !llvm.ptr
-    llvm.store %59, %69 : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>, !llvm.ptr
+    ptr.store %59, %69 : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>, !llvm.ptr
     %70 = llvm.alloca %14 x !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)> : (i64) -> !llvm.ptr
-    llvm.store %67, %70 : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>, !llvm.ptr
+    ptr.store %67, %70 : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>, !llvm.ptr
     %71 = llvm.alloca %8 x i64 : (i64) -> !llvm.ptr
-    llvm.store %16, %71 : i64, !llvm.ptr
+    ptr.store %16, %71 : i64, !llvm.ptr
     %72 = llvm.getelementptr %71[1] : (!llvm.ptr) -> !llvm.ptr, !llvm.ptr
-    llvm.store %2, %72 : i64, !llvm.ptr
+    ptr.store %2, %72 : i64, !llvm.ptr
     %73 = llvm.call @mgpuTensorMapEncodeTiledMemref(%0, %69, %7, %9, %10, %9, %9, %71) : (i64, !llvm.ptr, i64, i64, i64, i64, i64, !llvm.ptr) -> !llvm.ptr
     %74 = llvm.alloca %8 x i64 : (i64) -> !llvm.ptr
-    llvm.store %2, %74 : i64, !llvm.ptr
+    ptr.store %2, %74 : i64, !llvm.ptr
     %75 = llvm.getelementptr %74[1] : (!llvm.ptr) -> !llvm.ptr, !llvm.ptr
-    llvm.store %2, %75 : i64, !llvm.ptr
+    ptr.store %2, %75 : i64, !llvm.ptr
     %76 = llvm.call @mgpuTensorMapEncodeTiledMemref(%0, %70, %7, %9, %10, %9, %9, %74) : (i64, !llvm.ptr, i64, i64, i64, i64, i64, !llvm.ptr) -> !llvm.ptr
     gpu.launch_func  @main_kernel::@main_kernel blocks in (%14, %14, %14) threads in (%16, %14, %14) : i64 dynamic_shared_memory_size %3 args(%68 : !llvm.ptr, %68 : !llvm.ptr, %15 : i64, %16 : i64, %16 : i64, %16 : i64, %14 : i64, %73 : !llvm.ptr, %76 : !llvm.ptr)
     llvm.call @mgpuMemcpy(%24, %68, %23, %50) : (!llvm.ptr, !llvm.ptr, i64, !llvm.ptr) -> ()
@@ -129,19 +129,19 @@ module attributes {gpu.container_module} {
     %83 = llvm.mul %77, %16  : i64
     %84 = llvm.add %83, %81  : i64
     %85 = llvm.getelementptr %20[%84] : (!llvm.ptr, i64) -> !llvm.ptr, f16
-    %86 = llvm.load %85 : !llvm.ptr -> f16
+    %86 = ptr.load %85 : !llvm.ptr -> f16
     %87 = llvm.mul %81, %16  : i64
     %88 = llvm.add %87, %79  : i64
     %89 = llvm.getelementptr %21[%88] : (!llvm.ptr, i64) -> !llvm.ptr, f16
-    %90 = llvm.load %89 : !llvm.ptr -> f16
+    %90 = ptr.load %89 : !llvm.ptr -> f16
     %91 = llvm.add %83, %79  : i64
     %92 = llvm.getelementptr %25[%91] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    %93 = llvm.load %92 : !llvm.ptr -> f32
+    %93 = ptr.load %92 : !llvm.ptr -> f32
     %94 = llvm.fpext %86 : f16 to f32
     %95 = llvm.fpext %90 : f16 to f32
     %96 = llvm.fmul %94, %95  : f32
     %97 = llvm.fadd %93, %96  : f32
-    llvm.store %97, %92 : f32, !llvm.ptr
+    ptr.store %97, %92 : f32, !llvm.ptr
     %98 = llvm.add %81, %14  : i64
     llvm.br ^bb11(%98 : i64)
   ^bb13:  // pred: ^bb11
@@ -164,9 +164,9 @@ module attributes {gpu.container_module} {
     %109 = llvm.mul %101, %16  : i64
     %110 = llvm.add %109, %105  : i64
     %111 = llvm.getelementptr %25[%110] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    %112 = llvm.load %111 : !llvm.ptr -> f32
+    %112 = ptr.load %111 : !llvm.ptr -> f32
     %113 = llvm.getelementptr %24[%110] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    %114 = llvm.load %113 : !llvm.ptr -> f32
+    %114 = ptr.load %113 : !llvm.ptr -> f32
     %115 = llvm.fsub %112, %114  : f32
     %116 = llvm.intr.fabs(%115)  : (f32) -> f32
     %117 = llvm.fcmp "ult" %13, %116 : f32
diff --git a/mlir/test/Target/LLVMIR/Import/basic.ll b/mlir/test/Target/LLVMIR/Import/basic.ll
index a059425d978067..7ffb65bd62824b 100644
--- a/mlir/test/Target/LLVMIR/Import/basic.ll
+++ b/mlir/test/Target/LLVMIR/Import/basic.ll
@@ -16,13 +16,13 @@ declare float @fe(i32)
 ; CHECK: %[[c42:[0-9]+]] = llvm.mlir.constant(42 : i32) : i32
 define internal dso_local i32 @f1(i64 %a) norecurse {
 entry:
-; CHECK: %{{[0-9]+}} = llvm.inttoptr %arg0 : i64 to !llvm.ptr
+; CHECK: %{{[0-9]+}} = ptr.inttoptr %arg0 : i64 to !llvm.ptr
   %aa = inttoptr i64 %a to ptr
 ; CHECK-DBG: llvm.mlir.addressof @global : !llvm.ptr loc(#[[UNKNOWN_LOC]])
 ; %[[addrof:[0-9]+]] = llvm.mlir.addressof @global : !llvm.ptr
 ; %[[addrof2:[0-9]+]] = llvm.mlir.addressof @global : !llvm.ptr
-; %{{[0-9]+}} = llvm.inttoptr %arg0 : i64 to !llvm.ptr
-; %{{[0-9]+}} = llvm.ptrtoint %[[addrof2]] : !llvm.ptr to i64
+; %{{[0-9]+}} = ptr.inttoptr %arg0 : i64 to !llvm.ptr
+; %{{[0-9]+}} = ptr.ptrtoint %[[addrof2]] : !llvm.ptr to i64
 ; %{{[0-9]+}} = llvm.getelementptr %[[addrof]][%3] : (!llvm.ptr, i32) -> !llvm.ptr
   %bb = ptrtoint ptr @global to i64
   %cc = getelementptr double, ptr @global, i32 3
diff --git a/mlir/test/Target/LLVMIR/Import/constant.ll b/mlir/test/Target/LLVMIR/Import/constant.ll
index 3c46f5b20c31ca..e43432fb18a5d8 100644
--- a/mlir/test/Target/LLVMIR/Import/constant.ll
+++ b/mlir/test/Target/LLVMIR/Import/constant.ll
@@ -86,7 +86,7 @@ define i64 @const_expr_with_duplicate() {
   ; CHECK-DAG:  %[[ADDR:[0-9]+]] = llvm.mlir.addressof @global : !llvm.ptr
   ; CHECK-DAG:  %[[IDX:[0-9]+]] = llvm.mlir.constant(7 : i32) : i32
   ; CHECK-DAG:  %[[GEP:[0-9]+]] = llvm.getelementptr %[[ADDR]][%[[IDX]]] : (!llvm.ptr, i32) -> !llvm.ptr
-  ; CHECK-DAG:  %[[DUP:[0-9]+]] = llvm.ptrtoint %[[GEP]] : !llvm.ptr to i64
+  ; CHECK-DAG:  %[[DUP:[0-9]+]] = ptr.ptrtoint %[[GEP]] : !llvm.ptr to i64
 
   ; Verify the duplicate sub expression is converted only once.
   ; CHECK-DAG:  %[[SUM:[0-9]+]] = llvm.add %[[DUP]], %[[DUP]] : i64
@@ -106,7 +106,7 @@ define i64 @const_expr_with_aggregate() {
   ; CHECK-DAG:  %[[ADDR:[0-9]+]] = llvm.mlir.addressof @global : !llvm.ptr
   ; CHECK-DAG:  %[[IDX1:[0-9]+]] = llvm.mlir.constant(7 : i32) : i32
   ; CHECK-DAG:  %[[GEP1:[0-9]+]] = llvm.getelementptr %[[ADDR]][%[[IDX1]]] : (!llvm.ptr, i32) -> !llvm.ptr
-  ; CHECK-DAG:  %[[VAL2:[0-9]+]] = llvm.ptrtoint %[[GEP1]] : !llvm.ptr to i64
+  ; CHECK-DAG:  %[[VAL2:[0-9]+]] = ptr.ptrtoint %[[GEP1]] : !llvm.ptr to i64
 
   ; Fill the vector.
   ; CHECK-DAG:  %[[VEC1:[0-9]+]] = llvm.mlir.undef : vector<2xi64>
@@ -118,7 +118,7 @@ define i64 @const_expr_with_aggregate() {
 
   ; Compute the extract index.
   ; CHECK-DAG:  %[[GEP2:[0-9]+]] = llvm.getelementptr %[[ADDR]][%[[IDX4]]] : (!llvm.ptr, i32) -> !llvm.ptr
-  ; CHECK-DAG:  %[[IDX5:[0-9]+]] = llvm.ptrtoint %[[GEP2]] : !llvm.ptr to i64
+  ; CHECK-DAG:  %[[IDX5:[0-9]+]] = ptr.ptrtoint %[[GEP2]] : !llvm.ptr to i64
 
   ; Extract the vector element.
   ; CHECK-DAG:  %[[ELEM:[0-9]+]] = llvm.extractelement %[[VEC3]][%[[IDX5]] : i64] : vector<2xi64>
@@ -137,9 +137,9 @@ define i64 @const_expr_with_aggregate() {
 define i32 @function_address_before_def() {
   %1 = alloca ptr
   ; CHECK:  %[[FUN:.*]] = llvm.mlir.addressof @callee : !llvm.ptr
-  ; CHECK:  llvm.store %[[FUN]], %[[PTR:.*]] : !llvm.ptr, !llvm.ptr
+  ; CHECK:  ptr.store %[[FUN]], %[[PTR:.*]] : !llvm.ptr, !llvm.ptr
   store ptr @callee, ptr %1
-  ; CHECK:  %[[INDIR:.*]] = llvm.load %[[PTR]] : !llvm.ptr -> !llvm.ptr
+  ; CHECK:  %[[INDIR:.*]] = ptr.load %[[PTR]] : !llvm.ptr -> !llvm.ptr
   %2 = load ptr, ptr %1
   ; CHECK:  llvm.call %[[INDIR]]() : !llvm.ptr, () -> i32
   %3 = call i32 %2()
@@ -155,9 +155,9 @@ define i32 @callee() {
 define i32 @function_address_after_def() {
   %1 = alloca ptr
   ; CHECK:  %[[FUN:.*]] = llvm.mlir.addressof @callee : !llvm.ptr
-  ; CHECK:  llvm.store %[[FUN]], %[[PTR:.*]] : !llvm.ptr, !llvm.ptr
+  ; CHECK:  ptr.store %[[FUN]], %[[PTR:.*]] : !llvm.ptr, !llvm.ptr
   store ptr @callee, ptr %1
-  ; CHECK:  %[[INDIR:.*]] = llvm.load %[[PTR]] : !llvm.ptr -> !llvm.ptr
+  ; CHECK:  %[[INDIR:.*]] = ptr.load %[[PTR]] : !llvm.ptr -> !llvm.ptr
   %2 = load ptr, ptr %1
   ; CHECK:  llvm.call %[[INDIR]]() : !llvm.ptr, () -> i32
   %3 = call i32 %2()
@@ -233,6 +233,6 @@ define i64 @const_exprs_with_duplicate() {
 
 ; CHECK-LABEL: @cyclic
 ; CHECK:  %[[ADDR:.+]] = llvm.mlir.addressof @cyclic
-; CHECK:  %[[VAL0:.+]] = llvm.ptrtoint %[[ADDR]]
+; CHECK:  %[[VAL0:.+]] = ptr.ptrtoint %[[ADDR]]
 ; CHECK:  %[[VAL1:.+]] = llvm.add %[[VAL0]], %[[VAL0]]
 ; CHECK:  llvm.return %[[VAL1]]
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 005aafb20a510d..cf8dda16773ab1 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -183,8 +183,8 @@ define void @integer_extension_and_truncation(i32 %arg1) {
 ; CHECK-SAME:  %[[ARG2:[a-zA-Z0-9]+]]
 define ptr @pointer_casts(ptr %arg1, i64 %arg2) {
   ; CHECK:  %[[NULL:[0-9]+]] = llvm.mlir.zero : !llvm.ptr
-  ; CHECK:  llvm.ptrtoint %[[ARG1]] : !llvm.ptr to i64
-  ; CHECK:  llvm.inttoptr %[[ARG2]] : i64 to !llvm.ptr
+  ; CHECK:  ptr.ptrtoint %[[ARG1]] : !llvm.ptr to i64
+  ; CHECK:  ptr.inttoptr %[[ARG2]] : i64 to !llvm.ptr
   ; CHECK:  llvm.bitcast %[[ARG1]] : !llvm.ptr to !llvm.ptr
   ; CHECK:  llvm.return %[[NULL]] : !llvm.ptr
   %1 = ptrtoint ptr %arg1 to i64
@@ -198,7 +198,7 @@ define ptr @pointer_casts(ptr %arg1, i64 %arg2) {
 ; CHECK-LABEL: @addrspace_casts
 ; CHECK-SAME:  %[[ARG1:[a-zA-Z0-9]+]]
 define ptr addrspace(2) @addrspace_casts(ptr addrspace(1) %arg1) {
-  ; CHECK:  llvm.addrspacecast %[[ARG1]] : !llvm.ptr<1> to !llvm.ptr<2>
+  ; CHECK:  ptr.addrspacecast %[[ARG1]] : !llvm.ptr<1> to !llvm.ptr<2>
   ; CHECK:  llvm.return {{.*}} : !llvm.ptr<2>
   %1 = addrspacecast ptr addrspace(1) %arg1 to ptr addrspace(2)
   ret ptr addrspace(2) %1
@@ -251,7 +251,7 @@ define void @integer_arith(i32 %arg1, i32 %arg2, i64 %arg3, i64 %arg4) {
 ; CHECK-SAME:  %[[VEC:[a-zA-Z0-9]+]]
 ; CHECK-SAME:  %[[IDX:[a-zA-Z0-9]+]]
 define half @extract_element(ptr %vec, i32 %idx) {
-  ; CHECK:  %[[V1:.+]] = llvm.load %[[VEC]] {{.*}} : !llvm.ptr -> vector<4xf16>
+  ; CHECK:  %[[V1:.+]] = ptr.load %[[VEC]] {{.*}} : !llvm.ptr -> vector<4xf16>
   ; CHECK:  %[[V2:.+]] = llvm.extractelement %[[V1]][%[[IDX]] : i32] : vector<4xf16>
   ; CHECK:  llvm.return %[[V2]]
   %1 = load <4 x half>, ptr %vec
@@ -266,7 +266,7 @@ define half @extract_element(ptr %vec, i32 %idx) {
 ; CHECK-SAME:  %[[VAL:[a-zA-Z0-9]+]]
 ; CHECK-SAME:  %[[IDX:[a-zA-Z0-9]+]]
 define <4 x half> @insert_element(ptr %vec, half %val, i32 %idx) {
-  ; CHECK:  %[[V1:.+]] = llvm.load %[[VEC]] {{.*}} : !llvm.ptr -> vector<4xf16>
+  ; CHECK:  %[[V1:.+]] = ptr.load %[[VEC]] {{.*}} : !llvm.ptr -> vector<4xf16>
   ; CHECK:  %[[V2:.+]] = llvm.insertelement %[[VAL]], %[[V1]][%[[IDX]] : i32] : vector<4xf16>
   ; CHECK:  llvm.return %[[V2]]
   %1 = load <4 x half>, ptr %vec
@@ -280,7 +280,7 @@ define <4 x half> @insert_element(ptr %vec, half %val, i32 %idx) {
 ; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
 define float @insert_extract_value_struct({{i32},{float, double}}* %ptr) {
   ; CHECK:  %[[C0:.+]] = llvm.mlir.constant(2.000000e+00 : f64)
-  ; CHECK:  %[[VT:.+]] = llvm.load %[[PTR]]
+  ; CHECK:  %[[VT:.+]] = ptr.load %[[PTR]]
   %1 = load {{i32},{float, double}}, {{i32},{float, double}}* %ptr
   ; CHECK:  %[[EV:.+]] = llvm.extractvalue %[[VT]][1, 0] :
   ; CHECK-SAME: !llvm.struct<(struct<(i32)>, struct<(f32, f64)>)>
@@ -288,7 +288,7 @@ define float @insert_extract_value_struct({{i32},{float, double}}* %ptr) {
   ; CHECK:  %[[IV:.+]] = llvm.insertvalue %[[C0]], %[[VT]][1, 1] :
   ; CHECK-SAME: !llvm.struct<(struct<(i32)>, struct<(f32, f64)>)>
   %3 = insertvalue {{i32},{float, double}} %1, double 2.0, 1, 1
-  ; CHECK:  llvm.store %[[IV]], %[[PTR]]
+  ; CHECK:  ptr.store %[[IV]], %[[PTR]]
   store {{i32},{float, double}} %3, {{i32},{float, double}}* %ptr
   ; CHECK:  llvm.return %[[EV]]
   ret float %2
@@ -354,13 +354,13 @@ define ptr @alloca(i64 %size) {
 ; CHECK-LABEL: @load_store
 ; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
 define void @load_store(ptr %ptr) {
-  ; CHECK:  %[[V1:[0-9]+]] = llvm.load %[[PTR]] {alignment = 8 : i64} : !llvm.ptr -> f64
-  ; CHECK:  %[[V2:[0-9]+]] = llvm.load volatile %[[PTR]] {alignment = 16 : i64, nontemporal} : !llvm.ptr -> f64
+  ; CHECK:  %[[V1:[0-9]+]] = ptr.load %[[PTR]] {alignment = 8 : i64} : !llvm.ptr -> f64
+  ; CHECK:  %[[V2:[0-9]+]] = ptr.load volatile %[[PTR]] {alignment = 16 : i64, nontemporal} : !llvm.ptr -> f64
   %1 = load double, ptr %ptr
   %2 = load volatile double, ptr %ptr, align 16, !nontemporal !0
 
-  ; CHECK:  llvm.store %[[V1]], %[[PTR]] {alignment = 8 : i64} : f64, !llvm.ptr
-  ; CHECK:  llvm.store volatile %[[V2]], %[[PTR]] {alignment = 16 : i64, nontemporal} : f64, !llvm.ptr
+  ; CHECK:  ptr.store %[[V1]], %[[PTR]] {alignment = 8 : i64} : f64, !llvm.ptr
+  ; CHECK:  ptr.store volatile %[[V2]], %[[PTR]] {alignment = 16 : i64, nontemporal} : f64, !llvm.ptr
   store double %1, ptr %ptr
   store volatile double %2, ptr %ptr, align 16, !nontemporal !0
   ret void
@@ -373,7 +373,7 @@ define void @load_store(ptr %ptr) {
 ; CHECK-LABEL: @invariant_load
 ; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
 define float @invariant_load(ptr %ptr) {
-  ; CHECK:  %[[V:[0-9]+]] = llvm.load %[[PTR]] invariant {alignment = 4 : i64} : !llvm.ptr -> f32
+  ; CHECK:  %[[V:[0-9]+]] = ptr.load %[[PTR]] invariant {alignment = 4 : i64} : !llvm.ptr -> f32
   %1 = load float, ptr %ptr, align 4, !invariant.load !0
   ; CHECK:  llvm.return %[[V]]
   ret float %1
@@ -386,13 +386,13 @@ define float @invariant_load(ptr %ptr) {
 ; CHECK-LABEL: @atomic_load_store
 ; CHECK-SAME:  %[[PTR:[a-zA-Z0-9]+]]
 define void @atomic_load_store(ptr %ptr) {
-  ; CHECK:  %[[V1:[0-9]+]] = llvm.load %[[PTR]] atomic acquire {alignment = 8 : i64} : !llvm.ptr -> f64
-  ; CHECK:  %[[V2:[0-9]+]] = llvm.load volatile %[[PTR]] atomic syncscope("singlethreaded") acquire {alignment = 16 : i64} : !llvm.ptr -> f64
+  ; CHECK:  %[[V1:[0-9]+]] = ptr.load %[[PTR]] atomic acquire {alignment = 8 : i64} : !llvm.ptr -> f64
+  ; CHECK:  %[[V2:[0-9]+]] = ptr.load volatile %[[PTR]] atomic syncscope("singlethreaded") acquire {alignment = 16 : i64} : !llvm.ptr -> f64
   %1 = load atomic double, ptr %ptr acquire, align 8
   %2 = load atomic volatile double, ptr %ptr syncscope("singlethreaded") acquire, align 16
 
-  ; CHECK:  llvm.store %[[V1]], %[[PTR]] atomic release {alignment = 8 : i64} : f64, !llvm.ptr
-  ; CHECK:  llvm.store volatile %[[V2]], %[[PTR]] atomic syncscope("singlethreaded") release {alignment = 16 : i64} : f64, !llvm.ptr
+  ; CHECK:  ptr.store %[[V1]], %[[PTR]] atomic release {alignment = 8 : i64} : f64, !llvm.ptr
+  ; CHECK:  ptr.store volatile %[[V2]], %[[PTR]] atomic syncscope("singlethreaded") release {alignment = 16 : i64} : f64, !llvm.ptr
   store atomic double %1, ptr %ptr release, align 8
   store atomic volatile double %2, ptr %ptr syncscope("singlethreaded") release, align 16
   ret void
@@ -406,42 +406,42 @@ define void @atomic_load_store(ptr %ptr) {
 ; CHECK-SAME:  %[[PTR2:[a-zA-Z0-9]+]]
 ; CHECK-SAME:  %[[VAL2:[a-zA-Z0-9]+]]
 define void @atomic_rmw(ptr %ptr1, i32 %val1, ptr %ptr2, float %val2) {
-  ; CHECK:  llvm.atomicrmw xchg %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw xchg %[[PTR1]], %[[VAL1]] acquire
   %1 = atomicrmw xchg ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw add %[[PTR1]], %[[VAL1]] release
+  ; CHECK:  ptr.atomicrmw add %[[PTR1]], %[[VAL1]] release
   %2 = atomicrmw add ptr %ptr1, i32 %val1 release
-  ; CHECK:  llvm.atomicrmw sub %[[PTR1]], %[[VAL1]] acq_rel
+  ; CHECK:  ptr.atomicrmw sub %[[PTR1]], %[[VAL1]] acq_rel
   %3 = atomicrmw sub ptr %ptr1, i32 %val1 acq_rel
-  ; CHECK:  llvm.atomicrmw _and %[[PTR1]], %[[VAL1]] seq_cst
+  ; CHECK:  ptr.atomicrmw _and %[[PTR1]], %[[VAL1]] seq_cst
   %4 = atomicrmw and ptr %ptr1, i32 %val1 seq_cst
-  ; CHECK:  llvm.atomicrmw nand %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw nand %[[PTR1]], %[[VAL1]] acquire
   %5 = atomicrmw nand ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw _or %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw _or %[[PTR1]], %[[VAL1]] acquire
   %6 = atomicrmw or ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw _xor %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw _xor %[[PTR1]], %[[VAL1]] acquire
   %7 = atomicrmw xor ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw max %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw max %[[PTR1]], %[[VAL1]] acquire
   %8 = atomicrmw max ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw min %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw min %[[PTR1]], %[[VAL1]] acquire
   %9 = atomicrmw min ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw umax %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw umax %[[PTR1]], %[[VAL1]] acquire
   %10 = atomicrmw umax ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw umin %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw umin %[[PTR1]], %[[VAL1]] acquire
   %11 = atomicrmw umin ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw fadd %[[PTR2]], %[[VAL2]] acquire
+  ; CHECK:  ptr.atomicrmw fadd %[[PTR2]], %[[VAL2]] acquire
   %12 = atomicrmw fadd ptr %ptr2, float %val2 acquire
-  ; CHECK:  llvm.atomicrmw fsub %[[PTR2]], %[[VAL2]] acquire
+  ; CHECK:  ptr.atomicrmw fsub %[[PTR2]], %[[VAL2]] acquire
   %13 = atomicrmw fsub ptr %ptr2, float %val2 acquire
-  ; CHECK:  llvm.atomicrmw fmax %[[PTR2]], %[[VAL2]] acquire
+  ; CHECK:  ptr.atomicrmw fmax %[[PTR2]], %[[VAL2]] acquire
   %14 = atomicrmw fmax ptr %ptr2, float %val2 acquire
-  ; CHECK:  llvm.atomicrmw fmin %[[PTR2]], %[[VAL2]] acquire
+  ; CHECK:  ptr.atomicrmw fmin %[[PTR2]], %[[VAL2]] acquire
   %15 = atomicrmw fmin ptr %ptr2, float %val2 acquire
-  ; CHECK:  llvm.atomicrmw uinc_wrap %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw uinc_wrap %[[PTR1]], %[[VAL1]] acquire
   %16 = atomicrmw uinc_wrap ptr %ptr1, i32 %val1 acquire
-  ; CHECK:  llvm.atomicrmw udec_wrap %[[PTR1]], %[[VAL1]] acquire
+  ; CHECK:  ptr.atomicrmw udec_wrap %[[PTR1]], %[[VAL1]] acquire
   %17 = atomicrmw udec_wrap ptr %ptr1, i32 %val1 acquire
 
-  ; CHECK:  llvm.atomicrmw volatile
+  ; CHECK:  ptr.atomicrmw volatile
   ; CHECK-SAME:  syncscope("singlethread")
   ; CHECK-SAME:  {alignment = 8 : i64}
   %18 = atomicrmw volatile udec_wrap ptr %ptr1, i32 %val1 syncscope("singlethread") acquire, align 8
@@ -455,12 +455,12 @@ define void @atomic_rmw(ptr %ptr1, i32 %val1, ptr %ptr2, float %val2) {
 ; CHECK-SAME:  %[[VAL1:[a-zA-Z0-9]+]]
 ; CHECK-SAME:  %[[VAL2:[a-zA-Z0-9]+]]
 define void @atomic_cmpxchg(ptr %ptr1, i32 %val1, i32 %val2) {
-  ; CHECK:  llvm.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] seq_cst seq_cst
+  ; CHECK:  ptr.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] seq_cst seq_cst
   %1 = cmpxchg ptr %ptr1, i32 %val1, i32 %val2 seq_cst seq_cst
-  ; CHECK:  llvm.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] monotonic seq_cst
+  ; CHECK:  ptr.cmpxchg %[[PTR1]], %[[VAL1]], %[[VAL2]] monotonic seq_cst
   %2 = cmpxchg ptr %ptr1, i32 %val1, i32 %val2 monotonic seq_cst
 
-  ; CHECK:  llvm.cmpxchg weak volatile
+  ; CHECK:  ptr.cmpxchg weak volatile
   ; CHECK-SAME:  syncscope("singlethread")
   ; CHECK-SAME:  {alignment = 8 : i64}
   %3 = cmpxchg weak volatile ptr %ptr1, i32 %val1, i32 %val2 syncscope("singlethread") monotonic seq_cst, align 8
diff --git a/mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll b/mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll
index f5128ff76bc5ff..0bfe92534a31e0 100644
--- a/mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll
+++ b/mlir/test/Target/LLVMIR/Import/metadata-alias-scopes.ll
@@ -1,21 +1,21 @@
 ; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
 
-; CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = {{.*}}, description = "The domain">
-; CHECK: #[[$SCOPE0:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]], description = "The first scope">
-; CHECK: #[[$SCOPE1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
-; CHECK: #[[$SCOPE2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
+; CHECK: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<id = {{.*}}, description = "The domain">
+; CHECK: #[[$SCOPE0:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]], description = "The first scope">
+; CHECK: #[[$SCOPE1:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
+; CHECK: #[[$SCOPE2:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
 
 ; CHECK-LABEL: llvm.func @alias_scope
 define void @alias_scope(ptr %arg1) {
-  ; CHECK: llvm.load
+  ; CHECK: ptr.load
   ; CHECK-SAME:  alias_scopes = [#[[$SCOPE0]]]
   ; CHECK-SAME:  noalias_scopes = [#[[$SCOPE1]], #[[$SCOPE2]]]
   %1 = load i32, ptr %arg1, !alias.scope !4, !noalias !7
-  ; CHECK: llvm.load
+  ; CHECK: ptr.load
   ; CHECK-SAME:  alias_scopes = [#[[$SCOPE1]]]
   ; CHECK-SAME:  noalias_scopes = [#[[$SCOPE0]], #[[$SCOPE2]]]
   %2 = load i32, ptr %arg1, !alias.scope !5, !noalias !8
-  ; CHECK: llvm.load
+  ; CHECK: ptr.load
   ; CHECK-SAME:  alias_scopes = [#[[$SCOPE2]]]
   ; CHECK-SAME:  noalias_scopes = [#[[$SCOPE0]], #[[$SCOPE1]]]
   %3 = load i32, ptr %arg1, !alias.scope !6, !noalias !9
@@ -35,14 +35,14 @@ define void @alias_scope(ptr %arg1) {
 
 ; // -----
 
-; CHECK: #[[DOMAIN0:.*]] = #llvm.alias_scope_domain<id = {{.*}}, description = "The domain">
-; CHECK: #[[DOMAIN1:.*]] = #llvm.alias_scope_domain<id = {{.*}}>
-; CHECK: #[[$SCOPE0:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN0]]>
-; CHECK: #[[$SCOPE1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN1]]>
+; CHECK: #[[DOMAIN0:.*]] = #ptr.alias_scope_domain<id = {{.*}}, description = "The domain">
+; CHECK: #[[DOMAIN1:.*]] = #ptr.alias_scope_domain<id = {{.*}}>
+; CHECK: #[[$SCOPE0:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN0]]>
+; CHECK: #[[$SCOPE1:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN1]]>
 
 ; CHECK-LABEL: llvm.func @two_domains
 define void @two_domains(ptr %arg1) {
-  ; CHECK: llvm.load
+  ; CHECK: ptr.load
   ; CHECK-SAME:  alias_scopes = [#[[$SCOPE0]]]
   ; CHECK-SAME:  noalias_scopes = [#[[$SCOPE1]]]
   %1 = load i32, ptr %arg1, !alias.scope !4, !noalias !5
@@ -58,20 +58,20 @@ define void @two_domains(ptr %arg1) {
 
 ; // -----
 
-; CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = {{.*}}, description = "The domain">
-; CHECK: #[[$SCOPE:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
+; CHECK: #[[DOMAIN:.*]] = #ptr.alias_scope_domain<id = {{.*}}, description = "The domain">
+; CHECK: #[[$SCOPE:.*]] = #ptr.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
 
 ; CHECK-LABEL: llvm.func @supported_ops
 define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
   ; CHECK: llvm.intr.experimental.noalias.scope.decl #[[$SCOPE]]
   call void @llvm.experimental.noalias.scope.decl(metadata !2)
-  ; CHECK: llvm.load {{.*}}alias_scopes = [#[[$SCOPE]]]
+  ; CHECK: ptr.load {{.*}}alias_scopes = [#[[$SCOPE]]]
   %1 = load i32, ptr %arg1, !alias.scope !2
-  ; CHECK: llvm.store {{.*}}alias_scopes = [#[[$SCOPE]]]
+  ; CHECK: ptr.store {{.*}}alias_scopes = [#[[$SCOPE]]]
   store i32 %1, ptr %arg1, !alias.scope !2
-  ; CHECK: llvm.atomicrmw {{.*}}alias_scopes = [#[[$SCOPE]]]
+  ; CHECK: ptr.atomicrmw {{.*}}alias_scopes = [#[[$SCOPE]]]
   %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !alias.scope !2
-  ; CHECK: llvm.cmpxchg {{.*}}alias_scopes = [#[[$SCOPE]]]
+  ; CHECK: ptr.cmpxchg {{.*}}alias_scopes = [#[[$SCOPE]]]
   %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !alias.scope !2
   ; CHECK: "llvm.intr.memcpy"{{.*}}alias_scopes = [#[[$SCOPE]]]
   call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg1, i32 4, i1 false), !alias.scope !2
diff --git a/mlir/test/Target/LLVMIR/Import/metadata-loop.ll b/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
index 3516101a2367de..45bc4d2f1be95f 100644
--- a/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
+++ b/mlir/test/Target/LLVMIR/Import/metadata-loop.ll
@@ -1,9 +1,9 @@
 ; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
 
-; CHECK-DAG: #[[$GROUP0:.*]] = #llvm.access_group<id = {{.*}}>
-; CHECK-DAG: #[[$GROUP1:.*]] = #llvm.access_group<id = {{.*}}>
-; CHECK-DAG: #[[$GROUP2:.*]] = #llvm.access_group<id = {{.*}}>
-; CHECK-DAG: #[[$GROUP3:.*]] = #llvm.access_group<id = {{.*}}>
+; CHECK-DAG: #[[$GROUP0:.*]] = #ptr.access_group<id = {{.*}}>
+; CHECK-DAG: #[[$GROUP1:.*]] = #ptr.access_group<id = {{.*}}>
+; CHECK-DAG: #[[$GROUP2:.*]] = #ptr.access_group<id = {{.*}}>
+; CHECK-DAG: #[[$GROUP3:.*]] = #ptr.access_group<id = {{.*}}>
 
 ; CHECK-LABEL: llvm.func @access_group
 define void @access_group(ptr %arg1) {
@@ -27,13 +27,13 @@ define void @access_group(ptr %arg1) {
 
 ; CHECK-LABEL: llvm.func @supported_ops
 define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
-  ; CHECK: llvm.load {{.*}}access_groups =
+  ; CHECK: ptr.load {{.*}}access_groups =
   %1 = load i32, ptr %arg1, !llvm.access.group !0
-  ; CHECK: llvm.store {{.*}}access_groups =
+  ; CHECK: ptr.store {{.*}}access_groups =
   store i32 %1, ptr %arg1, !llvm.access.group !0
-  ; CHECK: llvm.atomicrmw {{.*}}access_groups =
+  ; CHECK: ptr.atomicrmw {{.*}}access_groups =
   %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !llvm.access.group !0
-  ; CHECK: llvm.cmpxchg {{.*}}access_groups =
+  ; CHECK: ptr.cmpxchg {{.*}}access_groups =
   %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !llvm.access.group !0
   ; CHECK: "llvm.intr.memcpy"{{.*}}access_groups =
   call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg1, i32 4, i1 false), !llvm.access.group !0
@@ -282,7 +282,7 @@ end:
 
 ; // -----
 
-; CHECK: #[[GROUP0:.*]] = #llvm.access_group<id = {{.*}}>
+; CHECK: #[[GROUP0:.*]] = #ptr.access_group<id = {{.*}}>
 ; CHECK: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<parallelAccesses = #[[GROUP0]]>
 
 ; CHECK-LABEL: @parallel_accesses
@@ -301,8 +301,8 @@ end:
 
 ; // -----
 
-; CHECK: #[[GROUP0:.*]] = #llvm.access_group<id = {{.*}}>
-; CHECK: #[[GROUP1:.*]] = #llvm.access_group<id = {{.*}}>
+; CHECK: #[[GROUP0:.*]] = #ptr.access_group<id = {{.*}}>
+; CHECK: #[[GROUP1:.*]] = #ptr.access_group<id = {{.*}}>
 ; CHECK: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<parallelAccesses = #[[GROUP0]], #[[GROUP1]]>
 
 ; CHECK-LABEL: @multiple_parallel_accesses
@@ -324,7 +324,7 @@ end:
 ; // -----
 
 ; Verify the unused access group is not imported.
-; CHECK-COUNT1: #llvm.access_group
+; CHECK-COUNT1: #ptr.access_group
 
 ; CHECK-LABEL: @unused_parallel_access
 define void @unused_parallel_access(ptr %arg) {
diff --git a/mlir/test/Target/LLVMIR/Import/metadata-tbaa.ll b/mlir/test/Target/LLVMIR/Import/metadata-tbaa.ll
index 2a7685c4e02470..158e1ec475b4a5 100644
--- a/mlir/test/Target/LLVMIR/Import/metadata-tbaa.ll
+++ b/mlir/test/Target/LLVMIR/Import/metadata-tbaa.ll
@@ -1,17 +1,17 @@
 ; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
 
-; CHECK-DAG: #[[R0:.*]] = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-; CHECK-DAG: #[[D0:.*]] = #llvm.tbaa_type_desc<id = "scalar type", members = {<#[[R0]], 0>}>
-; CHECK-DAG: #[[$T0:.*]] = #llvm.tbaa_tag<base_type = #[[D0]], access_type = #[[D0]], offset = 0>
-; CHECK-DAG: #[[R1:.*]] = #llvm.tbaa_root<id = "Other language TBAA">
-; CHECK-DAG: #[[D1:.*]] = #llvm.tbaa_type_desc<id = "other scalar type", members = {<#[[R1]], 0>}>
-; CHECK-DAG: #[[$T1:.*]] = #llvm.tbaa_tag<base_type = #[[D1]], access_type = #[[D1]], offset = 0>
+; CHECK-DAG: #[[R0:.*]] = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+; CHECK-DAG: #[[D0:.*]] = #ptr.tbaa_type_desc<id = "scalar type", members = {<#[[R0]], 0>}>
+; CHECK-DAG: #[[$T0:.*]] = #ptr.tbaa_tag<base_type = #[[D0]], access_type = #[[D0]], offset = 0>
+; CHECK-DAG: #[[R1:.*]] = #ptr.tbaa_root<id = "Other language TBAA">
+; CHECK-DAG: #[[D1:.*]] = #ptr.tbaa_type_desc<id = "other scalar type", members = {<#[[R1]], 0>}>
+; CHECK-DAG: #[[$T1:.*]] = #ptr.tbaa_tag<base_type = #[[D1]], access_type = #[[D1]], offset = 0>
 
 ; CHECK-LABEL: llvm.func @tbaa1
-; CHECK:         llvm.store %{{.*}}, %{{.*}} {
+; CHECK:         ptr.store %{{.*}}, %{{.*}} {
 ; CHECK-SAME:        tbaa = [#[[$T0]]]
 ; CHECK-SAME:    } : i8, !llvm.ptr
-; CHECK:         llvm.store %{{.*}}, %{{.*}} {
+; CHECK:         ptr.store %{{.*}}, %{{.*}} {
 ; CHECK-SAME:        tbaa = [#[[$T1]]]
 ; CHECK-SAME:    } : i8, !llvm.ptr
 define dso_local void @tbaa1(ptr %0, ptr %1) {
@@ -30,20 +30,20 @@ define dso_local void @tbaa1(ptr %0, ptr %1) {
 
 ; // -----
 
-; CHECK-DAG: #[[R0:.*]] = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-; CHECK-DAG: #[[$T0:.*]] = #llvm.tbaa_tag<base_type = #[[D2:.*]], access_type = #[[D1:.*]], offset = 8>
-; CHECK-DAG: #[[D1]] = #llvm.tbaa_type_desc<id = "long long", members = {<#[[D0:.*]], 0>}>
-; CHECK-DAG: #[[D0]] = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#[[R0]], 0>}>
-; CHECK-DAG: #[[D2]] = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#[[D1]], 0>, <#[[D1]], 8>}>
-; CHECK-DAG: #[[$T1:.*]] = #llvm.tbaa_tag<base_type = #[[D4:.*]], access_type = #[[D3:.*]], offset = 0>
-; CHECK-DAG: #[[D3]] = #llvm.tbaa_type_desc<id = "int", members = {<#[[D0]], 0>}>
-; CHECK-DAG: #[[D4]] = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#[[D3]], 0>, <#[[D3]], 4>}>
+; CHECK-DAG: #[[R0:.*]] = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+; CHECK-DAG: #[[$T0:.*]] = #ptr.tbaa_tag<base_type = #[[D2:.*]], access_type = #[[D1:.*]], offset = 8>
+; CHECK-DAG: #[[D1]] = #ptr.tbaa_type_desc<id = "long long", members = {<#[[D0:.*]], 0>}>
+; CHECK-DAG: #[[D0]] = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#[[R0]], 0>}>
+; CHECK-DAG: #[[D2]] = #ptr.tbaa_type_desc<id = "agg2_t", members = {<#[[D1]], 0>, <#[[D1]], 8>}>
+; CHECK-DAG: #[[$T1:.*]] = #ptr.tbaa_tag<base_type = #[[D4:.*]], access_type = #[[D3:.*]], offset = 0>
+; CHECK-DAG: #[[D3]] = #ptr.tbaa_type_desc<id = "int", members = {<#[[D0]], 0>}>
+; CHECK-DAG: #[[D4]] = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#[[D3]], 0>, <#[[D3]], 4>}>
 
 ; CHECK-LABEL: llvm.func @tbaa2
-; CHECK:         llvm.load %{{.*}} {
+; CHECK:         ptr.load %{{.*}} {
 ; CHECK-SAME:        tbaa = [#[[$T0]]]
 ; CHECK-SAME:    } : !llvm.ptr -> i64
-; CHECK:         llvm.store %{{.*}}, %{{.*}} {
+; CHECK:         ptr.store %{{.*}}, %{{.*}} {
 ; CHECK-SAME:        tbaa = [#[[$T1]]]
 ; CHECK-SAME:    } : i32, !llvm.ptr
 %struct.agg2_t = type { i64, i64 }
@@ -71,13 +71,13 @@ define dso_local void @tbaa2(ptr %0, ptr %1) {
 
 ; CHECK-LABEL: llvm.func @supported_ops
 define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
-  ; CHECK: llvm.load {{.*}}tbaa =
+  ; CHECK: ptr.load {{.*}}tbaa =
   %1 = load i32, ptr %arg1, !tbaa !0
-  ; CHECK: llvm.store {{.*}}tbaa =
+  ; CHECK: ptr.store {{.*}}tbaa =
   store i32 %1, ptr %arg1, !tbaa !0
-  ; CHECK: llvm.atomicrmw {{.*}}tbaa =
+  ; CHECK: ptr.atomicrmw {{.*}}tbaa =
   %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !tbaa !0
-  ; CHECK: llvm.cmpxchg {{.*}}tbaa =
+  ; CHECK: ptr.cmpxchg {{.*}}tbaa =
   %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !tbaa !0
   ; CHECK: "llvm.intr.memcpy"{{.*}}tbaa =
   call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg1, i32 4, i1 false), !tbaa !0
@@ -98,12 +98,12 @@ declare void @foo(ptr %arg1)
 
 ; // -----
 
-; CHECK: #llvm.tbaa_root
+; CHECK: #ptr.tbaa_root
 ; CHECK-NOT: <{{.*}}>
 ; CHECK: {{[[:space:]]}}
 
 define void @nameless_root(ptr %arg1) {
-  ; CHECK: llvm.load {{.*}}tbaa =
+  ; CHECK: ptr.load {{.*}}tbaa =
   %1 = load i32, ptr %arg1, !tbaa !0
   ret void
 }
diff --git a/mlir/test/Target/LLVMIR/Import/target-ext-type.ll b/mlir/test/Target/LLVMIR/Import/target-ext-type.ll
index 3c575b71038bf0..6499ac13cf3a71 100644
--- a/mlir/test/Target/LLVMIR/Import/target-ext-type.ll
+++ b/mlir/test/Target/LLVMIR/Import/target-ext-type.ll
@@ -37,7 +37,7 @@ define target("spirv.Event") @func2() {
   ; CHECK-NEXT:    %1 = llvm.mlir.poison : !llvm.target<"spirv.Event">
   ; CHECK-NEXT:    %2 = llvm.alloca %0 x !llvm.target<"spirv.Event"> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   %mem = alloca target("spirv.Event")
-  ; CHECK-NEXT:    %3 = llvm.load %2 {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"spirv.Event">
+  ; CHECK-NEXT:    %3 = ptr.load %2 {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"spirv.Event">
   %val = load target("spirv.Event"), ptr %mem
   ; CHECK-NEXT:    llvm.return %1 : !llvm.target<"spirv.Event">
   ret target("spirv.Event") poison
diff --git a/mlir/test/Target/LLVMIR/arm-sve.mlir b/mlir/test/Target/LLVMIR/arm-sve.mlir
index c7cd1b74ccdb5d..5337cfbfe6c6b9 100644
--- a/mlir/test/Target/LLVMIR/arm-sve.mlir
+++ b/mlir/test/Target/LLVMIR/arm-sve.mlir
@@ -249,7 +249,7 @@ llvm.func @memcopy(%arg0: !llvm.ptr, %arg1: !llvm.ptr,
   // CHECK: getelementptr float, ptr
   %19 = llvm.getelementptr %18[%16] : (!llvm.ptr, i64) -> !llvm.ptr, f32
   // CHECK: load <vscale x 4 x float>, ptr
-  %21 = llvm.load %19 : !llvm.ptr -> vector<[4]xf32>
+  %21 = ptr.load %19 : !llvm.ptr -> vector<[4]xf32>
   // CHECK: extractvalue { ptr, ptr, i64, [1 x i64], [1 x i64] }
   %22 = llvm.extractvalue %11[1] : !llvm.struct<(ptr, ptr, i64,
                                                  array<1 x i64>,
@@ -257,7 +257,7 @@ llvm.func @memcopy(%arg0: !llvm.ptr, %arg1: !llvm.ptr,
   // CHECK: getelementptr float, ptr
   %23 = llvm.getelementptr %22[%16] : (!llvm.ptr, i64) -> !llvm.ptr, f32
   // CHECK: store <vscale x 4 x float> %{{[0-9]+}}, ptr %{{[0-9]+}}
-  llvm.store %21, %23 : vector<[4]xf32>, !llvm.ptr
+  ptr.store %21, %23 : vector<[4]xf32>, !llvm.ptr
   %25 = llvm.add %16, %15  : i64
   llvm.br ^bb1(%25 : i64)
 ^bb3:
diff --git a/mlir/test/Target/LLVMIR/attribute-alias-scopes.mlir b/mlir/test/Target/LLVMIR/attribute-alias-scopes.mlir
index fa3395533af220..e67ff0a60c8876 100644
--- a/mlir/test/Target/LLVMIR/attribute-alias-scopes.mlir
+++ b/mlir/test/Target/LLVMIR/attribute-alias-scopes.mlir
@@ -2,10 +2,10 @@
 
 llvm.func @foo(%arg0: !llvm.ptr)
 
-#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-#alias_scope1 = #llvm.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain, description = "The first scope">
-#alias_scope2 = #llvm.alias_scope<id = distinct[2]<>, domain = #alias_scope_domain>
-#alias_scope3 = #llvm.alias_scope<id = distinct[3]<>, domain = #alias_scope_domain>
+#alias_scope_domain = #ptr.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#alias_scope1 = #ptr.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain, description = "The first scope">
+#alias_scope2 = #ptr.alias_scope<id = distinct[2]<>, domain = #alias_scope_domain>
+#alias_scope3 = #ptr.alias_scope<id = distinct[3]<>, domain = #alias_scope_domain>
 
 // CHECK-LABEL: @alias_scopes
 llvm.func @alias_scopes(%arg1 : !llvm.ptr) {
@@ -13,13 +13,13 @@ llvm.func @alias_scopes(%arg1 : !llvm.ptr) {
   // CHECK:  call void @llvm.experimental.noalias.scope.decl(metadata ![[SCOPES1:[0-9]+]])
   llvm.intr.experimental.noalias.scope.decl #alias_scope1
   // CHECK:  store {{.*}}, !alias.scope ![[SCOPES1]], !noalias ![[SCOPES23:[0-9]+]]
-  llvm.store %0, %arg1 {alias_scopes = [#alias_scope1], noalias_scopes = [#alias_scope2, #alias_scope3]} : i32, !llvm.ptr
+  ptr.store %0, %arg1 {alias_scopes = [#alias_scope1], noalias_scopes = [#alias_scope2, #alias_scope3]} : i32, !llvm.ptr
   // CHECK:  load {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
-  %1 = llvm.load %arg1 {alias_scopes = [#alias_scope2], noalias_scopes = [#alias_scope1, #alias_scope3]} : !llvm.ptr -> i32
+  %1 = ptr.load %arg1 {alias_scopes = [#alias_scope2], noalias_scopes = [#alias_scope1, #alias_scope3]} : !llvm.ptr -> i32
   // CHECK:  atomicrmw {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
-  %2 = llvm.atomicrmw add %arg1, %0 monotonic {alias_scopes = [#alias_scope3], noalias_scopes = [#alias_scope1, #alias_scope2]} : !llvm.ptr, i32
+  %2 = ptr.atomicrmw add %arg1, %0 monotonic {alias_scopes = [#alias_scope3], noalias_scopes = [#alias_scope1, #alias_scope2]} : !llvm.ptr, i32
   // CHECK:  cmpxchg {{.*}}, !alias.scope ![[SCOPES3]]
-  %3 = llvm.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [#alias_scope3]} : !llvm.ptr, i32
+  %3, %4 = ptr.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [#alias_scope3]} : !llvm.ptr, i32
   %5 = llvm.mlir.constant(42 : i8) : i8
   // CHECK:  llvm.memcpy{{.*}}, !alias.scope ![[SCOPES3]]
   "llvm.intr.memcpy"(%arg1, %arg1, %0) <{isVolatile = false}> {alias_scopes = [#alias_scope3]} : (!llvm.ptr, !llvm.ptr, i32) -> ()
@@ -55,8 +55,8 @@ llvm.func @alias_scopes(%arg1 : !llvm.ptr) {
 // isolation. It is the only operation using alias scopes attributes without
 // implementing AliasAnalysisOpInterface.
 
-#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-#alias_scope1 = #llvm.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain>
+#alias_scope_domain = #ptr.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#alias_scope1 = #ptr.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain>
 
 // CHECK-LABEL: @noalias_intr_only
 llvm.func @noalias_intr_only() {
@@ -81,8 +81,8 @@ llvm.func @noalias_intr_only() {
 // self-reference, which causes the type list to reference the access
 // group node as well. The use of a temporary placeholder node avoids the issue.
 
-#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>>
-#alias_scope = #llvm.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain>
+#alias_scope_domain = #ptr.alias_scope_domain<id = distinct[0]<>>
+#alias_scope = #ptr.alias_scope<id = distinct[1]<>, domain = #alias_scope_domain>
 
 #di_null_type = #llvm.di_null_type
 #di_subroutine_type = #llvm.di_subroutine_type<types = #di_null_type>
diff --git a/mlir/test/Target/LLVMIR/attribute-tbaa.mlir b/mlir/test/Target/LLVMIR/attribute-tbaa.mlir
index 69b666a1ec3538..7c2e84125da3ec 100644
--- a/mlir/test/Target/LLVMIR/attribute-tbaa.mlir
+++ b/mlir/test/Target/LLVMIR/attribute-tbaa.mlir
@@ -1,24 +1,24 @@
 // RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
 
-#tbaa_root_0 = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-#tbaa_type_desc_1 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
-#tbaa_type_desc_2 = #llvm.tbaa_type_desc<id = "long long", members = {<#tbaa_type_desc_1, 0>}>
-#tbaa_type_desc_3 = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 8>}>
-#tbaa_tag_4 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_3, offset = 8>
-#tbaa_type_desc_5 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_1, 0>}>
-#tbaa_type_desc_6 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_5, 0>, <#tbaa_type_desc_5, 4>}>
-#tbaa_tag_7 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_6, offset = 0, constant = true>
+#tbaa_root_0 = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+#tbaa_type_desc_1 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
+#tbaa_type_desc_2 = #ptr.tbaa_type_desc<id = "long long", members = {<#tbaa_type_desc_1, 0>}>
+#tbaa_type_desc_3 = #ptr.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 8>}>
+#tbaa_tag_4 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_3, offset = 8>
+#tbaa_type_desc_5 = #ptr.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_1, 0>}>
+#tbaa_type_desc_6 = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_5, 0>, <#tbaa_type_desc_5, 4>}>
+#tbaa_tag_7 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_6, offset = 0, constant = true>
 
 llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   %0 = llvm.mlir.constant(0 : i32) : i32
   %1 = llvm.mlir.constant(1 : i32) : i32
   %2 = llvm.getelementptr inbounds %arg1[%0, 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg2_t", (i64, i64)>
   // CHECK: load i64, ptr %{{.*}},{{.*}}!tbaa ![[LTAG:[0-9]*]]
-  %3 = llvm.load %2 {tbaa = [#tbaa_tag_4]} : !llvm.ptr -> i64
+  %3 = ptr.load %2 {tbaa = [#tbaa_tag_4]} : !llvm.ptr -> i64
   %4 = llvm.trunc %3 : i64 to i32
   %5 = llvm.getelementptr inbounds %arg0[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
   // CHECK: store i32 %{{.*}}, ptr %{{.*}},{{.*}}!tbaa ![[STAG:[0-9]*]]
-  llvm.store %4, %5 {tbaa = [#tbaa_tag_7]} : i32, !llvm.ptr
+  ptr.store %4, %5 {tbaa = [#tbaa_tag_7]} : i32, !llvm.ptr
   llvm.return
 }
 
@@ -42,14 +42,14 @@ llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
 // uniquing. To prevent this, we have to use temporary MDNodes
 // instead of !null's.
 
-#tbaa_root_0 = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
-#tbaa_type_desc_1 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
-#tbaa_type_desc_2 = #llvm.tbaa_type_desc<id = "float", members = {<#tbaa_type_desc_1, 0>}>
-#tbaa_type_desc_3 = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 4>}>
-#tbaa_tag_4 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_3, offset = 0>
-#tbaa_type_desc_5 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_1, 0>}>
-#tbaa_type_desc_6 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_5, 0>, <#tbaa_type_desc_5, 4>}>
-#tbaa_tag_7 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_6, offset = 0>
+#tbaa_root_0 = #ptr.tbaa_root<id = "Simple C/C++ TBAA">
+#tbaa_type_desc_1 = #ptr.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
+#tbaa_type_desc_2 = #ptr.tbaa_type_desc<id = "float", members = {<#tbaa_type_desc_1, 0>}>
+#tbaa_type_desc_3 = #ptr.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 4>}>
+#tbaa_tag_4 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_3, offset = 0>
+#tbaa_type_desc_5 = #ptr.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_1, 0>}>
+#tbaa_type_desc_6 = #ptr.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_5, 0>, <#tbaa_type_desc_5, 4>}>
+#tbaa_tag_7 = #ptr.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_6, offset = 0>
 
 
 llvm.func @foo(%arg0: !llvm.ptr)
@@ -58,15 +58,15 @@ llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   %1 = llvm.mlir.constant(1 : i32) : i32
   %2 = llvm.getelementptr inbounds %arg1[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg2_t", (f32, f32)>
   // CHECK: load float, ptr %{{.*}},{{.*}}!tbaa ![[LTAG:[0-9]*]]
-  %3 = llvm.load %2 {tbaa = [#tbaa_tag_4]} : !llvm.ptr -> f32
+  %3 = ptr.load %2 {tbaa = [#tbaa_tag_4]} : !llvm.ptr -> f32
   %4 = llvm.fptosi %3 : f32 to i32
   %5 = llvm.getelementptr inbounds %arg0[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
   // CHECK: store i32 %{{.*}}, ptr %{{.*}},{{.*}}!tbaa ![[STAG:[0-9]*]]
-  llvm.store %4, %5 {tbaa = [#tbaa_tag_7]} : i32, !llvm.ptr
+  ptr.store %4, %5 {tbaa = [#tbaa_tag_7]} : i32, !llvm.ptr
   // CHECK: atomicrmw add ptr %{{.*}}, i32 %{{.*}} !tbaa ![[STAG]]
-  %6 = llvm.atomicrmw add %5, %4 monotonic {tbaa = [#tbaa_tag_7]} : !llvm.ptr, i32
+  %6 = ptr.atomicrmw add %5, %4 monotonic {tbaa = [#tbaa_tag_7]} : !llvm.ptr, i32
   // CHECK: cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} !tbaa ![[STAG]]
-  %7 = llvm.cmpxchg %5, %6, %4 acq_rel monotonic {tbaa = [#tbaa_tag_7]} : !llvm.ptr, i32
+  %7, %8 = ptr.cmpxchg %5, %6, %4 acq_rel monotonic {tbaa = [#tbaa_tag_7]} : !llvm.ptr, i32
   %9 = llvm.mlir.constant(42 : i8) : i8
   // CHECK: llvm.memcpy{{.*}} !tbaa ![[STAG]]
   "llvm.intr.memcpy"(%arg1, %arg1, %0) <{isVolatile = false}> {tbaa = [#tbaa_tag_7]} : (!llvm.ptr, !llvm.ptr, i32) -> ()
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index c38c7ea587d25b..4c5e96ed2bdb49 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -198,14 +198,14 @@ llvm.func @global_refs() {
   // Check load from globals.
   // CHECK: load i32, ptr @i32_global
   %0 = llvm.mlir.addressof @i32_global : !llvm.ptr
-  %1 = llvm.load %0 : !llvm.ptr -> i32
+  %1 = ptr.load %0 : !llvm.ptr -> i32
 
   // Check the contracted form of load from array constants.
   // CHECK: load i8, ptr @string_const
   %2 = llvm.mlir.addressof @string_const : !llvm.ptr
   %c0 = llvm.mlir.constant(0 : index) : i64
   %3 = llvm.getelementptr %2[%c0, %c0] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<6 x i8>
-  %4 = llvm.load %3 : !llvm.ptr -> i8
+  %4 = ptr.load %3 : !llvm.ptr -> i8
 
   llvm.return
 }
@@ -589,7 +589,7 @@ llvm.func @store_load_static() {
   %12 = llvm.mlir.constant(10 : index) : i64
   %13 = llvm.extractvalue %6[0] : !llvm.struct<(ptr)>
   %14 = llvm.getelementptr %13[%10] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %7, %14 : f32, !llvm.ptr
+  ptr.store %7, %14 : f32, !llvm.ptr
   %15 = llvm.mlir.constant(1 : index) : i64
 // CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
   %16 = llvm.add %10, %15 : i64
@@ -614,7 +614,7 @@ llvm.func @store_load_static() {
   %21 = llvm.mlir.constant(10 : index) : i64
   %22 = llvm.extractvalue %6[0] : !llvm.struct<(ptr)>
   %23 = llvm.getelementptr %22[%19] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  %24 = llvm.load %23 : !llvm.ptr -> f32
+  %24 = ptr.load %23 : !llvm.ptr -> f32
   %25 = llvm.mlir.constant(1 : index) : i64
 // CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
   %26 = llvm.add %19, %25 : i64
@@ -657,7 +657,7 @@ llvm.func @store_load_dynamic(%arg0: i64) {
   %11 = llvm.extractvalue %6[1] : !llvm.struct<(ptr, i64)>
   %12 = llvm.extractvalue %6[0] : !llvm.struct<(ptr, i64)>
   %13 = llvm.getelementptr %12[%9] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %7, %13 : f32, !llvm.ptr
+  ptr.store %7, %13 : f32, !llvm.ptr
   %14 = llvm.mlir.constant(1 : index) : i64
 // CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
   %15 = llvm.add %9, %14 : i64
@@ -682,7 +682,7 @@ llvm.func @store_load_dynamic(%arg0: i64) {
   %19 = llvm.extractvalue %6[1] : !llvm.struct<(ptr, i64)>
   %20 = llvm.extractvalue %6[0] : !llvm.struct<(ptr, i64)>
   %21 = llvm.getelementptr %20[%17] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  %22 = llvm.load %21 : !llvm.ptr -> f32
+  %22 = ptr.load %21 : !llvm.ptr -> f32
   %23 = llvm.mlir.constant(1 : index) : i64
 // CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
   %24 = llvm.add %17, %23 : i64
@@ -747,7 +747,7 @@ llvm.func @store_load_mixed(%arg0: i64) {
   %28 = llvm.add %27, %17 : i64
   %29 = llvm.extractvalue %13[0] : !llvm.struct<(ptr, i64, i64)>
   %30 = llvm.getelementptr %29[%28] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %18, %30 : f32, !llvm.ptr
+  ptr.store %18, %30 : f32, !llvm.ptr
 // CHECK-NEXT: %{{[0-9]+}} = extractvalue { ptr, i64, i64 } %{{[0-9]+}}, 1
 // CHECK-NEXT: %{{[0-9]+}} = extractvalue { ptr, i64, i64 } %{{[0-9]+}}, 2
 // CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}
@@ -771,7 +771,7 @@ llvm.func @store_load_mixed(%arg0: i64) {
   %40 = llvm.add %39, %14 : i64
   %41 = llvm.extractvalue %13[0] : !llvm.struct<(ptr, i64, i64)>
   %42 = llvm.getelementptr %41[%40] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  %43 = llvm.load %42 : !llvm.ptr -> f32
+  %43 = ptr.load %42 : !llvm.ptr -> f32
 // CHECK-NEXT: ret void
   llvm.return
 }
@@ -788,7 +788,7 @@ llvm.func @memref_args_rets(%arg0: !llvm.struct<(ptr)>, %arg1: !llvm.struct<(ptr
   %3 = llvm.mlir.constant(10 : index) : i64
   %4 = llvm.extractvalue %arg0[0] : !llvm.struct<(ptr)>
   %5 = llvm.getelementptr %4[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %2, %5 : f32, !llvm.ptr
+  ptr.store %2, %5 : f32, !llvm.ptr
 // CHECK-NEXT: %{{[0-9]+}} = extractvalue { ptr, i64 } %{{[0-9]+}}, 1
 // CHECK-NEXT: %{{[0-9]+}} = extractvalue { ptr, i64 } %{{[0-9]+}}, 0
 // CHECK-NEXT: %{{[0-9]+}} = getelementptr float, ptr %{{[0-9]+}}, i64 7
@@ -796,7 +796,7 @@ llvm.func @memref_args_rets(%arg0: !llvm.struct<(ptr)>, %arg1: !llvm.struct<(ptr
   %6 = llvm.extractvalue %arg1[1] : !llvm.struct<(ptr, i64)>
   %7 = llvm.extractvalue %arg1[0] : !llvm.struct<(ptr, i64)>
   %8 = llvm.getelementptr %7[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %2, %8 : f32, !llvm.ptr
+  ptr.store %2, %8 : f32, !llvm.ptr
 // CHECK-NEXT: %{{[0-9]+}} = extractvalue { ptr, i64 } %{{[0-9]+}}, 1
 // CHECK-NEXT: %{{[0-9]+}} = mul i64 7, %{{[0-9]+}}
 // CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, %{{[0-9]+}}
@@ -809,7 +809,7 @@ llvm.func @memref_args_rets(%arg0: !llvm.struct<(ptr)>, %arg1: !llvm.struct<(ptr
   %12 = llvm.add %11, %1 : i64
   %13 = llvm.extractvalue %arg2[0] : !llvm.struct<(ptr, i64)>
   %14 = llvm.getelementptr %13[%12] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %2, %14 : f32, !llvm.ptr
+  ptr.store %2, %14 : f32, !llvm.ptr
 // CHECK-NEXT: %{{[0-9]+}} = mul i64 10, %{{[0-9]+}}
 // CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
 // CHECK-NEXT: %{{[0-9]+}} = call ptr @malloc(i64 %{{[0-9]+}})
@@ -901,7 +901,7 @@ llvm.func @multireturn_caller() {
   %18 = llvm.add %17, %8 : i64
   %19 = llvm.extractvalue %3[0] : !llvm.struct<(ptr, i64, i64)>
   %20 = llvm.getelementptr %19[%18] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  %21 = llvm.load %20 : !llvm.ptr -> f32
+  %21 = ptr.load %20 : !llvm.ptr -> f32
   llvm.return
 }
 
@@ -1246,8 +1246,8 @@ llvm.func @indirect_varargs_call(%arg0 : !llvm.ptr, %arg1 : i32) {
 llvm.func @intpointerconversion(%arg0 : i32) -> i32 {
 // CHECK:      %2 = inttoptr i32 %0 to ptr
 // CHECK-NEXT: %3 = ptrtoint ptr %2 to i32
-  %1 = llvm.inttoptr %arg0 : i32 to !llvm.ptr
-  %2 = llvm.ptrtoint %1 : !llvm.ptr to i32
+  %1 = ptr.inttoptr %arg0 : i32 to !llvm.ptr
+  %2 = ptr.ptrtoint %1 : !llvm.ptr to i32
   llvm.return %2 : i32
 }
 
@@ -1266,7 +1266,7 @@ llvm.func @fpconversion(%arg0 : i32) -> i32 {
 // CHECK-LABEL: @addrspace
 llvm.func @addrspace(%arg0 : !llvm.ptr) -> !llvm.ptr<2> {
 // CHECK: %2 = addrspacecast ptr %0 to ptr addrspace(2)
-  %1 = llvm.addrspacecast %arg0 : !llvm.ptr to !llvm.ptr<2>
+  %1 = ptr.addrspacecast %arg0 : !llvm.ptr to !llvm.ptr<2>
   llvm.return %1 : !llvm.ptr<2>
 }
 
@@ -1468,60 +1468,56 @@ llvm.func @atomicrmw(
     %f32_ptr : !llvm.ptr, %f32 : f32,
     %i32_ptr : !llvm.ptr, %i32 : i32) {
   // CHECK: atomicrmw fadd ptr %{{.*}}, float %{{.*}} monotonic
-  %0 = llvm.atomicrmw fadd %f32_ptr, %f32 monotonic : !llvm.ptr, f32
+  %0 = ptr.atomicrmw fadd %f32_ptr, %f32 monotonic : !llvm.ptr, f32
   // CHECK: atomicrmw fsub ptr %{{.*}}, float %{{.*}} monotonic
-  %1 = llvm.atomicrmw fsub %f32_ptr, %f32 monotonic : !llvm.ptr, f32
+  %1 = ptr.atomicrmw fsub %f32_ptr, %f32 monotonic : !llvm.ptr, f32
   // CHECK: atomicrmw fmax ptr %{{.*}}, float %{{.*}} monotonic
-  %2 = llvm.atomicrmw fmax %f32_ptr, %f32 monotonic : !llvm.ptr, f32
+  %2 = ptr.atomicrmw fmax %f32_ptr, %f32 monotonic : !llvm.ptr, f32
   // CHECK: atomicrmw fmin ptr %{{.*}}, float %{{.*}} monotonic
-  %3 = llvm.atomicrmw fmin %f32_ptr, %f32 monotonic : !llvm.ptr, f32
+  %3 = ptr.atomicrmw fmin %f32_ptr, %f32 monotonic : !llvm.ptr, f32
   // CHECK: atomicrmw xchg ptr %{{.*}}, float %{{.*}} monotonic
-  %4 = llvm.atomicrmw xchg %f32_ptr, %f32 monotonic : !llvm.ptr, f32
+  %4 = ptr.atomicrmw xchg %f32_ptr, %f32 monotonic : !llvm.ptr, f32
   // CHECK: atomicrmw add ptr %{{.*}}, i32 %{{.*}} acquire
-  %5 = llvm.atomicrmw add %i32_ptr, %i32 acquire : !llvm.ptr, i32
+  %5 = ptr.atomicrmw add %i32_ptr, %i32 acquire : !llvm.ptr, i32
   // CHECK: atomicrmw sub ptr %{{.*}}, i32 %{{.*}} release
-  %6 = llvm.atomicrmw sub %i32_ptr, %i32 release : !llvm.ptr, i32
+  %6 = ptr.atomicrmw sub %i32_ptr, %i32 release : !llvm.ptr, i32
   // CHECK: atomicrmw and ptr %{{.*}}, i32 %{{.*}} acq_rel
-  %7 = llvm.atomicrmw _and %i32_ptr, %i32 acq_rel : !llvm.ptr, i32
+  %7 = ptr.atomicrmw _and %i32_ptr, %i32 acq_rel : !llvm.ptr, i32
   // CHECK: atomicrmw nand ptr %{{.*}}, i32 %{{.*}} seq_cst
-  %8 = llvm.atomicrmw nand %i32_ptr, %i32 seq_cst : !llvm.ptr, i32
+  %8 = ptr.atomicrmw nand %i32_ptr, %i32 seq_cst : !llvm.ptr, i32
   // CHECK: atomicrmw or ptr %{{.*}}, i32 %{{.*}} monotonic
-  %9 = llvm.atomicrmw _or %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %9 = ptr.atomicrmw _or %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw xor ptr %{{.*}}, i32 %{{.*}} monotonic
-  %10 = llvm.atomicrmw _xor %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %10 = ptr.atomicrmw _xor %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw max ptr %{{.*}}, i32 %{{.*}} monotonic
-  %11 = llvm.atomicrmw max %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %11 = ptr.atomicrmw max %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw min ptr %{{.*}}, i32 %{{.*}} monotonic
-  %12 = llvm.atomicrmw min %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %12 = ptr.atomicrmw min %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw umax ptr %{{.*}}, i32 %{{.*}} monotonic
-  %13 = llvm.atomicrmw umax %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %13 = ptr.atomicrmw umax %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw umin ptr %{{.*}}, i32 %{{.*}} monotonic
-  %14 = llvm.atomicrmw umin %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %14 = ptr.atomicrmw umin %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw uinc_wrap ptr %{{.*}}, i32 %{{.*}} monotonic
-  %15 = llvm.atomicrmw uinc_wrap %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %15 = ptr.atomicrmw uinc_wrap %i32_ptr, %i32 monotonic : !llvm.ptr, i32
   // CHECK: atomicrmw udec_wrap ptr %{{.*}}, i32 %{{.*}} monotonic
-  %16 = llvm.atomicrmw udec_wrap %i32_ptr, %i32 monotonic : !llvm.ptr, i32
+  %16 = ptr.atomicrmw udec_wrap %i32_ptr, %i32 monotonic : !llvm.ptr, i32
 
   // CHECK: atomicrmw volatile
   // CHECK-SAME:  syncscope("singlethread")
   // CHECK-SAME:  align 8
-  %17 = llvm.atomicrmw volatile udec_wrap %i32_ptr, %i32 syncscope("singlethread") monotonic {alignment = 8 : i64} : !llvm.ptr, i32
+  %17 = ptr.atomicrmw volatile udec_wrap %i32_ptr, %i32 syncscope("singlethread") monotonic {alignment = 8 : i64} : !llvm.ptr, i32
   llvm.return
 }
 
 // CHECK-LABEL: @cmpxchg
 llvm.func @cmpxchg(%ptr : !llvm.ptr, %cmp : i32, %val: i32) {
   // CHECK: cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} acq_rel monotonic
-  %0 = llvm.cmpxchg %ptr, %cmp, %val acq_rel monotonic : !llvm.ptr, i32
-  // CHECK: %{{[0-9]+}} = extractvalue { i32, i1 } %{{[0-9]+}}, 0
-  %1 = llvm.extractvalue %0[0] : !llvm.struct<(i32, i1)>
-  // CHECK: %{{[0-9]+}} = extractvalue { i32, i1 } %{{[0-9]+}}, 1
-  %2 = llvm.extractvalue %0[1] : !llvm.struct<(i32, i1)>
+  %0, %1 = ptr.cmpxchg %ptr, %cmp, %val acq_rel monotonic : !llvm.ptr, i32
 
   // CHECK:  cmpxchg weak volatile
   // CHECK-SAME:  syncscope("singlethread")
   // CHECK-SAME:  align 8
-  %3 = llvm.cmpxchg weak volatile %ptr, %cmp, %val syncscope("singlethread") acq_rel monotonic {alignment = 8 : i64} : !llvm.ptr, i32
+  %2, %3 = ptr.cmpxchg weak volatile %ptr, %cmp, %val syncscope("singlethread") acq_rel monotonic {alignment = 8 : i64} : !llvm.ptr, i32
   llvm.return
 }
 
@@ -1593,7 +1589,7 @@ llvm.func @invoke_result(%arg0 : !llvm.ptr) attributes { personality = @__gxx_pe
 // CHECK-NEXT: store i8 %[[a1]], ptr %[[a0]]
 // CHECK-NEXT: ret void
 ^bb1:
-    llvm.store %0, %arg0 : i8, !llvm.ptr
+    ptr.store %0, %arg0 : i8, !llvm.ptr
     llvm.return
 
 // CHECK: [[unwind]]:
@@ -1887,9 +1883,9 @@ llvm.func @volatile_store_and_load() {
   %size = llvm.mlir.constant(1 : i64) : i64
   %0 = llvm.alloca %size x i32 : (i64) -> (!llvm.ptr)
   // CHECK: store volatile i32 5, ptr %{{.*}}
-  llvm.store volatile %val, %0 : i32, !llvm.ptr
+  ptr.store volatile %val, %0 : i32, !llvm.ptr
   // CHECK: %{{.*}} = load volatile i32, ptr %{{.*}}
-  %1 = llvm.load volatile %0: !llvm.ptr -> i32
+  %1 = ptr.load volatile %0: !llvm.ptr -> i32
   llvm.return
 }
 
@@ -1901,9 +1897,9 @@ llvm.func @nontemporal_store_and_load() {
   %size = llvm.mlir.constant(1 : i64) : i64
   %0 = llvm.alloca %size x i32 : (i64) -> (!llvm.ptr)
   // CHECK: !nontemporal ![[NODE:[0-9]+]]
-  llvm.store %val, %0 {nontemporal} : i32, !llvm.ptr
+  ptr.store %val, %0 {nontemporal} : i32, !llvm.ptr
   // CHECK: !nontemporal ![[NODE]]
-  %1 = llvm.load %0 {nontemporal} : !llvm.ptr -> i32
+  %1 = ptr.load %0 {nontemporal} : !llvm.ptr -> i32
   llvm.return
 }
 
@@ -1914,7 +1910,7 @@ llvm.func @nontemporal_store_and_load() {
 // Check that invariantLoad attribute is exported as metadata node.
 llvm.func @nontemporal_store_and_load(%ptr : !llvm.ptr) -> i32 {
   // CHECK: !invariant.load ![[NODE:[0-9]+]]
-  %1 = llvm.load %ptr invariant : !llvm.ptr -> i32
+  %1 = ptr.load %ptr invariant : !llvm.ptr -> i32
   llvm.return %1 : i32
 }
 
@@ -1925,17 +1921,17 @@ llvm.func @nontemporal_store_and_load(%ptr : !llvm.ptr) -> i32 {
 llvm.func @atomic_store_and_load(%ptr : !llvm.ptr) {
   // CHECK: load atomic
   // CHECK-SAME:  acquire, align 4
-  %1 = llvm.load %ptr atomic acquire {alignment = 4 : i64} : !llvm.ptr -> f32
+  %1 = ptr.load %ptr atomic acquire {alignment = 4 : i64} : !llvm.ptr -> f32
   // CHECK: load atomic
   // CHECK-SAME:  syncscope("singlethread") acquire, align 4
-  %2 = llvm.load %ptr atomic syncscope("singlethread") acquire {alignment = 4 : i64} : !llvm.ptr -> f32
+  %2 = ptr.load %ptr atomic syncscope("singlethread") acquire {alignment = 4 : i64} : !llvm.ptr -> f32
 
   // CHECK: store atomic
   // CHECK-SAME:  release, align 4
-  llvm.store %1, %ptr atomic release {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %1, %ptr atomic release {alignment = 4 : i64} : f32, !llvm.ptr
   // CHECK: store atomic
   // CHECK-SAME:  syncscope("singlethread") release, align 4
-  llvm.store %2, %ptr atomic syncscope("singlethread") release {alignment = 4 : i64} : f32, !llvm.ptr
+  ptr.store %2, %ptr atomic syncscope("singlethread") release {alignment = 4 : i64} : f32, !llvm.ptr
   llvm.return
 }
 
@@ -2386,7 +2382,7 @@ llvm.func @zeroinit_complex_local_aggregate() {
 
   // CHECK: store [1000 x { i32, [3 x { double, <4 x ptr>, [2 x ptr] }], [6 x ptr] }] zeroinitializer, ptr %[[#VAR]], align 32
   %2 = llvm.mlir.zero : !llvm.array<1000 x !llvm.struct<(i32, !llvm.array<3 x !llvm.struct<(f64, !llvm.vec<4 x ptr>, !llvm.array<2 x ptr>)>>, !llvm.array<6 x ptr>)>>
-  llvm.store %2, %1 : !llvm.array<1000 x !llvm.struct<(i32, !llvm.array<3 x !llvm.struct<(f64, !llvm.vec<4 x ptr>, !llvm.array<2 x ptr>)>>, !llvm.array<6 x ptr>)>>, !llvm.ptr
+  ptr.store %2, %1 : !llvm.array<1000 x !llvm.struct<(i32, !llvm.array<3 x !llvm.struct<(f64, !llvm.vec<4 x ptr>, !llvm.array<2 x ptr>)>>, !llvm.array<6 x ptr>)>>, !llvm.ptr
 
   llvm.return
 }
diff --git a/mlir/test/Target/LLVMIR/loop-metadata.mlir b/mlir/test/Target/LLVMIR/loop-metadata.mlir
index 2fe4a994aeb66a..2a6f0c1a7642ce 100644
--- a/mlir/test/Target/LLVMIR/loop-metadata.mlir
+++ b/mlir/test/Target/LLVMIR/loop-metadata.mlir
@@ -235,8 +235,8 @@ llvm.func @unswitchOptions() {
 
 llvm.func @foo(%arg0: i32)
 
-#group1 = #llvm.access_group<id = distinct[0]<>>
-#group2 = #llvm.access_group<id = distinct[1]<>>
+#group1 = #ptr.access_group<id = distinct[0]<>>
+#group2 = #ptr.access_group<id = distinct[1]<>>
 
 // CHECK-LABEL: @loopOptions
 llvm.func @loopOptions(%arg1 : i32, %arg2 : i32) {
@@ -254,13 +254,13 @@ llvm.func @loopOptions(%arg1 : i32, %arg2 : i32) {
   ^bb4:
     %3 = llvm.add %1, %arg2  : i32
     // CHECK: = load i32, ptr %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE:[0-9]+]]
-    %5 = llvm.load %4 {access_groups = [#group1, #group2]} : !llvm.ptr -> i32
+    %5 = ptr.load %4 {access_groups = [#group1, #group2]} : !llvm.ptr -> i32
     // CHECK: store i32 %{{.*}}, ptr %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
-    llvm.store %5, %4 {access_groups = [#group1, #group2]} : i32, !llvm.ptr
+    ptr.store %5, %4 {access_groups = [#group1, #group2]} : i32, !llvm.ptr
     // CHECK: = atomicrmw add ptr %{{.*}}, i32 %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
-    %6 = llvm.atomicrmw add %4, %5 monotonic {access_groups = [#group1, #group2]} : !llvm.ptr, i32
+    %6 = ptr.atomicrmw add %4, %5 monotonic {access_groups = [#group1, #group2]} : !llvm.ptr, i32
     // CHECK: = cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
-    %7 = llvm.cmpxchg %4, %5, %6 acq_rel monotonic {access_groups = [#group1, #group2]} : !llvm.ptr, i32
+    %7, %8 = ptr.cmpxchg %4, %5, %6 acq_rel monotonic {access_groups = [#group1, #group2]} : !llvm.ptr, i32
     %9 = llvm.mlir.constant(42 : i8) : i8
     // CHECK: llvm.memcpy{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
     "llvm.intr.memcpy"(%4, %4, %0) <{isVolatile = false}> {access_groups = [#group1, #group2]} : (!llvm.ptr, !llvm.ptr, i32) -> ()
diff --git a/mlir/test/Target/LLVMIR/omptarget-array-sectioning-host.mlir b/mlir/test/Target/LLVMIR/omptarget-array-sectioning-host.mlir
index 08ccbf04014a9b..614c621ee51908 100644
--- a/mlir/test/Target/LLVMIR/omptarget-array-sectioning-host.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-array-sectioning-host.mlir
@@ -23,9 +23,9 @@ module attributes {omp.is_target_device = false} {
       %9 = llvm.mlir.constant(0 : i64) : i64
       %10 = llvm.mlir.constant(1 : i64) : i64
       %11 = llvm.getelementptr %arg0[0, %10, %9, %9] : (!llvm.ptr, i64, i64, i64) -> !llvm.ptr, !llvm.array<3 x array<3 x array<3 x i32>>>
-      %12 = llvm.load %11 : !llvm.ptr -> i32
+      %12 = ptr.load %11 : !llvm.ptr -> i32
       %13 = llvm.getelementptr %arg1[0, %10, %9, %9] : (!llvm.ptr, i64, i64, i64) -> !llvm.ptr, !llvm.array<3 x array<3 x array<3 x i32>>>
-      llvm.store %12, %13 : i32, !llvm.ptr
+      ptr.store %12, %13 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-device.mlir b/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-device.mlir
index 5931da7582fd78..04e9cab4fa588c 100644
--- a/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-device.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-device.mlir
@@ -8,8 +8,8 @@ module attributes {omp.is_target_device = true} {
     %3 = omp.map.info var_ptr(%0 : !llvm.ptr, i32) map_clauses(to) capture(ByCopy) -> !llvm.ptr {name = "i"}
     omp.target map_entries(%2 -> %arg0, %3 -> %arg1 : !llvm.ptr, !llvm.ptr) {
       ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-      %4 = llvm.load %arg1 : !llvm.ptr -> i32
-      llvm.store %4, %arg0 : i32, !llvm.ptr
+      %4 = ptr.load %arg1 : !llvm.ptr -> i32
+      ptr.store %4, %arg0 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-host.mlir b/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-host.mlir
index 8635ea49567067..27676debd02c62 100644
--- a/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-host.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-byref-bycopy-generation-host.mlir
@@ -8,8 +8,8 @@ module attributes {omp.is_target_device = false} {
     %3 = omp.map.info var_ptr(%0 : !llvm.ptr, i32) map_clauses(to) capture(ByCopy) -> !llvm.ptr {name = "i"}
     omp.target map_entries(%2 -> %arg0, %3 -> %arg1 : !llvm.ptr, !llvm.ptr) {
       ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-      %4 = llvm.load %arg1 : !llvm.ptr -> i32
-      llvm.store %4, %arg0 : i32, !llvm.ptr
+      %4 = ptr.load %arg1 : !llvm.ptr -> i32
+      ptr.store %4, %arg0 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-constant-alloca-raise.mlir b/mlir/test/Target/LLVMIR/omptarget-constant-alloca-raise.mlir
index 7a785301eb16b6..6773f5750e1af1 100644
--- a/mlir/test/Target/LLVMIR/omptarget-constant-alloca-raise.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-constant-alloca-raise.mlir
@@ -22,10 +22,10 @@ module attributes {omp.is_target_device = true} {
       %6 = llvm.mlir.constant(50 : i32) : i32
       %7 = llvm.mlir.constant(1 : i64) : i64
       %8 = llvm.alloca %7 x i32 : (i64) -> !llvm.ptr
-      llvm.store %6, %8 : i32, !llvm.ptr
+      ptr.store %6, %8 : i32, !llvm.ptr
       %9 = llvm.mlir.undef : !llvm.struct<(ptr)>
       %10 = llvm.insertvalue %8, %9[0] : !llvm.struct<(ptr)> 
-      llvm.store %10, %5 : !llvm.struct<(ptr)>, !llvm.ptr
+      ptr.store %10, %5 : !llvm.struct<(ptr)>, !llvm.ptr
       %88 = llvm.call @_ExternalCall(%arg0, %5) : (!llvm.ptr, !llvm.ptr) -> !llvm.struct<()>
       omp.terminator
     }
diff --git a/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir b/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir
index be8145dc9075ec..c60d809214f201 100644
--- a/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir
@@ -14,11 +14,11 @@ module attributes {omp.is_target_device = true} {
       %7 = llvm.mlir.constant(20 : i32) : i32
       %8 = llvm.mlir.constant(0 : i64) : i64
       %9 = llvm.getelementptr %arg0[0, %8] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<10 x i32>
-      llvm.store %7, %9 : i32, !llvm.ptr
+      ptr.store %7, %9 : i32, !llvm.ptr
       %10 = llvm.mlir.constant(10 : i32) : i32
       %11 = llvm.mlir.constant(4 : i64) : i64
       %12 = llvm.getelementptr %arg0[0, %11] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<10 x i32>
-      llvm.store %10, %12 : i32, !llvm.ptr
+      ptr.store %10, %12 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-device.mlir b/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-device.mlir
index bb32000cc9457f..1c674c2640951e 100644
--- a/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-device.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-device.mlir
@@ -25,7 +25,7 @@ module attributes {omp.is_target_device = true} {
     omp.target   map_entries(%map -> %arg0 : !llvm.ptr) {
       ^bb0(%arg0: !llvm.ptr):
       %1 = llvm.mlir.constant(1 : i32) : i32
-      llvm.store %1, %arg0 : i32, !llvm.ptr
+      ptr.store %1, %arg0 : i32, !llvm.ptr
       omp.terminator
     }
 
diff --git a/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-host.mlir b/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-host.mlir
index 2baa20010d0558..5078ef8f54d1f8 100644
--- a/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-host.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-declare-target-llvm-host.mlir
@@ -143,7 +143,7 @@ module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu", omp.is_targe
     %1 = llvm.mlir.constant(9 : i32) : i32
     %2 = llvm.mlir.zero : !llvm.ptr
     %3 = llvm.getelementptr %2[1] : (!llvm.ptr) -> !llvm.ptr, i32
-    %4 = llvm.ptrtoint %3 : !llvm.ptr to i64
+    %4 = ptr.ptrtoint %3 : !llvm.ptr to i64
     %5 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
     %6 = llvm.insertvalue %4, %5[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
     %7 = llvm.mlir.constant(20180515 : i32) : i32
diff --git a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
index 7cb22dbb10b18c..5776d2f07d712d 100644
--- a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
@@ -18,22 +18,22 @@ module attributes {omp.is_target_device = false} {
     %6 = llvm.mlir.addressof @_QFEsect_arr : !llvm.ptr
     %7 = llvm.mlir.constant(0 : i64) : i64
     %8 = llvm.getelementptr %3[0, 7, %7, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-    %9 = llvm.load %8 : !llvm.ptr -> i64
+    %9 = ptr.load %8 : !llvm.ptr -> i64
     %10 = llvm.getelementptr %3[0, 7, %7, 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-    %11 = llvm.load %10 : !llvm.ptr -> i64
+    %11 = ptr.load %10 : !llvm.ptr -> i64
     %12 = llvm.getelementptr %3[0, 7, %7, 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-    %13 = llvm.load %12 : !llvm.ptr -> i64
+    %13 = ptr.load %12 : !llvm.ptr -> i64
     %14 = llvm.sub %11, %2  : i64
     %15 = omp.map.bounds lower_bound(%7 : i64) upper_bound(%14 : i64) extent(%11 : i64) stride(%13 : i64) start_idx(%9 : i64) {stride_in_bytes = true}
     %16 = llvm.getelementptr %3[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
     %17 = omp.map.info var_ptr(%3 : !llvm.ptr, f32) var_ptr_ptr(%16 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%15) -> !llvm.ptr {name = "full_arr"}
     %18 = omp.map.info var_ptr(%3 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) members(%17 : !llvm.ptr) -> !llvm.ptr {name = "full_arr"}
     %19 = llvm.getelementptr %6[0, 7, %7, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-    %20 = llvm.load %19 : !llvm.ptr -> i64
+    %20 = ptr.load %19 : !llvm.ptr -> i64
     %21 = llvm.getelementptr %6[0, 7, %7, 1] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-    %22 = llvm.load %21 : !llvm.ptr -> i64
+    %22 = ptr.load %21 : !llvm.ptr -> i64
     %23 = llvm.getelementptr %6[0, 7, %7, 2] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
-    %24 = llvm.load %23 : !llvm.ptr -> i64
+    %24 = ptr.load %23 : !llvm.ptr -> i64
     %25 = llvm.sub %1, %20  : i64
     %26 = llvm.sub %0, %20  : i64
     %27 = omp.map.bounds lower_bound(%25 : i64) upper_bound(%26 : i64) extent(%22 : i64) stride(%24 : i64) start_idx(%20 : i64) {stride_in_bytes = true}
diff --git a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
index 2f629675442d0c..9fa90ed4345f95 100644
--- a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
@@ -6,7 +6,7 @@ llvm.func @_QPopenmp_target_data() {
   %2 = omp.map.info var_ptr(%1 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
   omp.target_data map_entries(%2 : !llvm.ptr) {
     %3 = llvm.mlir.constant(99 : i32) : i32
-    llvm.store %3, %1 : i32, !llvm.ptr
+    ptr.store %3, %1 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -51,7 +51,7 @@ llvm.func @_QPopenmp_target_data_region(%0 : !llvm.ptr) {
     %9 = llvm.mlir.constant(1 : i64) : i64
     %10 = llvm.mlir.constant(0 : i64) : i64
     %11 = llvm.getelementptr %0[0, %10] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<1024 x i32>
-    llvm.store %7, %11 : i32, !llvm.ptr
+    ptr.store %7, %11 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -91,13 +91,13 @@ llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr, %3 : !llvm.ptr) {
   %6 = llvm.mlir.constant(1 : i64) : i64
   %7 = llvm.alloca %6 x i32 {bindc_name = "i", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_enter_exitEi"} : (i64) -> !llvm.ptr
   %8 = llvm.mlir.constant(5 : i32) : i32
-  llvm.store %8, %7 : i32, !llvm.ptr
+  ptr.store %8, %7 : i32, !llvm.ptr
   %9 = llvm.mlir.constant(2 : i32) : i32
-  llvm.store %9, %5 : i32, !llvm.ptr
-  %10 = llvm.load %7 : !llvm.ptr -> i32
+  ptr.store %9, %5 : i32, !llvm.ptr
+  %10 = ptr.load %7 : !llvm.ptr -> i32
   %11 = llvm.mlir.constant(10 : i32) : i32
   %12 = llvm.icmp "slt" %10, %11 : i32
-  %13 = llvm.load %5 : !llvm.ptr -> i32
+  %13 = ptr.load %5 : !llvm.ptr -> i32
   %14 = llvm.mlir.constant(1023 : index) : i64
   %15 = llvm.mlir.constant(0 : index) : i64
   %16 = llvm.mlir.constant(1024 : index) : i64
@@ -111,10 +111,10 @@ llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr, %3 : !llvm.ptr) {
   %23 = omp.map.bounds   lower_bound(%20 : i64) upper_bound(%19 : i64) extent(%21 : i64) stride(%22 : i64) start_idx(%22 : i64)
   %map2 = omp.map.info var_ptr(%3 : !llvm.ptr, !llvm.array<512 x i32>)   map_clauses(exit_release_or_enter_alloc) capture(ByRef) bounds(%23) -> !llvm.ptr {name = ""}
   omp.target_enter_data   if(%12 : i1) device(%13 : i32) map_entries(%map1, %map2 : !llvm.ptr, !llvm.ptr)
-  %24 = llvm.load %7 : !llvm.ptr -> i32
+  %24 = ptr.load %7 : !llvm.ptr -> i32
   %25 = llvm.mlir.constant(10 : i32) : i32
   %26 = llvm.icmp "sgt" %24, %25 : i32
-  %27 = llvm.load %5 : !llvm.ptr -> i32
+  %27 = ptr.load %5 : !llvm.ptr -> i32
   %28 = llvm.mlir.constant(1023 : index) : i64
   %29 = llvm.mlir.constant(0 : index) : i64
   %30 = llvm.mlir.constant(1024 : index) : i64
@@ -212,8 +212,8 @@ llvm.func @_QPopenmp_target_use_dev_ptr() {
   omp.target_data  map_entries(%map1 : !llvm.ptr) use_device_ptr(%a : !llvm.ptr)  {
   ^bb0(%arg0: !llvm.ptr):
     %1 = llvm.mlir.constant(10 : i32) : i32
-    %2 = llvm.load %arg0 : !llvm.ptr -> !llvm.ptr
-    llvm.store %1, %2 : i32, !llvm.ptr
+    %2 = ptr.load %arg0 : !llvm.ptr -> !llvm.ptr
+    ptr.store %1, %2 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -256,8 +256,8 @@ llvm.func @_QPopenmp_target_use_dev_addr() {
   omp.target_data  map_entries(%map : !llvm.ptr) use_device_addr(%a : !llvm.ptr)  {
   ^bb0(%arg0: !llvm.ptr):
     %1 = llvm.mlir.constant(10 : i32) : i32
-    %2 = llvm.load %arg0 : !llvm.ptr -> !llvm.ptr
-    llvm.store %1, %2 : i32, !llvm.ptr
+    %2 = ptr.load %arg0 : !llvm.ptr -> !llvm.ptr
+    ptr.store %1, %2 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -298,7 +298,7 @@ llvm.func @_QPopenmp_target_use_dev_addr_no_ptr() {
   omp.target_data  map_entries(%map : !llvm.ptr) use_device_addr(%a : !llvm.ptr)  {
   ^bb0(%arg0: !llvm.ptr):
     %1 = llvm.mlir.constant(10 : i32) : i32
-    llvm.store %1, %arg0 : i32, !llvm.ptr
+    ptr.store %1, %arg0 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -340,11 +340,11 @@ llvm.func @_QPopenmp_target_use_dev_addr_nomap() {
   omp.target_data  map_entries(%map : !llvm.ptr) use_device_addr(%a : !llvm.ptr)  {
   ^bb0(%arg0: !llvm.ptr):
     %2 = llvm.mlir.constant(10 : i32) : i32
-    %3 = llvm.load %arg0 : !llvm.ptr -> !llvm.ptr
-    llvm.store %2, %3 : i32, !llvm.ptr
+    %3 = ptr.load %arg0 : !llvm.ptr -> !llvm.ptr
+    ptr.store %2, %3 : i32, !llvm.ptr
     %4 = llvm.mlir.constant(20 : i32) : i32
-    %5 = llvm.load %b : !llvm.ptr -> !llvm.ptr
-    llvm.store %4, %5 : i32, !llvm.ptr
+    %5 = ptr.load %b : !llvm.ptr -> !llvm.ptr
+    ptr.store %4, %5 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -397,11 +397,11 @@ llvm.func @_QPopenmp_target_use_dev_both() {
   omp.target_data  map_entries(%map, %map1 : !llvm.ptr, !llvm.ptr) use_device_ptr(%a : !llvm.ptr) use_device_addr(%b : !llvm.ptr)  {
   ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
     %2 = llvm.mlir.constant(10 : i32) : i32
-    %3 = llvm.load %arg0 : !llvm.ptr -> !llvm.ptr
-    llvm.store %2, %3 : i32, !llvm.ptr
+    %3 = ptr.load %arg0 : !llvm.ptr -> !llvm.ptr
+    ptr.store %2, %3 : i32, !llvm.ptr
     %4 = llvm.mlir.constant(20 : i32) : i32
-    %5 = llvm.load %arg1 : !llvm.ptr -> !llvm.ptr
-    llvm.store %4, %5 : i32, !llvm.ptr
+    %5 = ptr.load %arg1 : !llvm.ptr -> !llvm.ptr
+    ptr.store %4, %5 : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -453,7 +453,7 @@ llvm.func @_QPopenmp_target_data_update() {
   %2 = omp.map.info var_ptr(%1 : !llvm.ptr, i32)   map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
   omp.target_data map_entries(%2 : !llvm.ptr) {
     %3 = llvm.mlir.constant(99 : i32) : i32
-    llvm.store %3, %1 : i32, !llvm.ptr
+    ptr.store %3, %1 : i32, !llvm.ptr
     omp.terminator
   }
 
diff --git a/mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir
index f22bc12d6b94c2..c1e2073a048a6b 100644
--- a/mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-parallel-llvm.mlir
@@ -10,7 +10,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
     ^bb0(%arg2: !llvm.ptr):
       omp.parallel {
         %1 = llvm.mlir.constant(1 : i32) : i32
-        llvm.store %1, %arg2 : i32, !llvm.ptr
+        ptr.store %1, %arg2 : i32, !llvm.ptr
         omp.terminator
       }
     omp.terminator
@@ -25,7 +25,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
       %1 = llvm.mlir.constant(156 : i32) : i32
       omp.parallel num_threads(%1 : i32) {
         %2 = llvm.mlir.constant(1 : i32) : i32
-        llvm.store %2, %arg2 : i32, !llvm.ptr
+        ptr.store %2, %arg2 : i32, !llvm.ptr
         omp.terminator
       }
     omp.terminator
@@ -41,11 +41,11 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
     omp.target map_entries(%2 -> %arg1, %3 -> %arg2 : !llvm.ptr, !llvm.ptr) {
     ^bb0(%arg1: !llvm.ptr, %arg2: !llvm.ptr):
       %4 = llvm.mlir.constant(10 : i32) : i32
-      %5 = llvm.load %arg2 : !llvm.ptr -> i32
+      %5 = ptr.load %arg2 : !llvm.ptr -> i32
       %6 = llvm.mlir.constant(0 : i64) : i32
       %7 = llvm.icmp "ne" %5, %6 : i32
       omp.parallel if(%7 : i1) {
-        llvm.store %4, %arg1 : i32, !llvm.ptr
+        ptr.store %4, %arg1 : i32, !llvm.ptr
         omp.terminator
       }
       omp.terminator
diff --git a/mlir/test/Target/LLVMIR/omptarget-parallel-wsloop.mlir b/mlir/test/Target/LLVMIR/omptarget-parallel-wsloop.mlir
index 8ab50f05f07167..fec5a565792a4a 100644
--- a/mlir/test/Target/LLVMIR/omptarget-parallel-wsloop.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-parallel-wsloop.mlir
@@ -14,7 +14,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
       %loop_step = llvm.mlir.constant(1 : i32) : i32
       omp.wsloop for  (%loop_cnt) : i32 = (%loop_lb) to (%loop_ub) inclusive step (%loop_step) {
         %gep = llvm.getelementptr %arg0[0, %loop_cnt] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.array<10 x i32>
-        llvm.store %loop_cnt, %gep : i32, !llvm.ptr
+        ptr.store %loop_cnt, %gep : i32, !llvm.ptr
         omp.yield
       }
      omp.terminator
diff --git a/mlir/test/Target/LLVMIR/omptarget-region-device-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-region-device-llvm.mlir
index ca8a2e6a5b98c8..5af24ee18fd628 100644
--- a/mlir/test/Target/LLVMIR/omptarget-region-device-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-region-device-llvm.mlir
@@ -10,17 +10,17 @@ module attributes {omp.is_target_device = true} {
     %5 = llvm.alloca %4 x i32 {bindc_name = "b", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_regionEb"} : (i64) -> !llvm.ptr
     %6 = llvm.mlir.constant(1 : i64) : i64
     %7 = llvm.alloca %6 x i32 {bindc_name = "c", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_regionEc"} : (i64) -> !llvm.ptr
-    llvm.store %1, %3 : i32, !llvm.ptr
-    llvm.store %0, %5 : i32, !llvm.ptr
+    ptr.store %1, %3 : i32, !llvm.ptr
+    ptr.store %0, %5 : i32, !llvm.ptr
     %map1 = omp.map.info var_ptr(%3 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     %map2 = omp.map.info var_ptr(%5 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     %map3 = omp.map.info var_ptr(%7 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     omp.target map_entries(%map1 -> %arg0, %map2 -> %arg1, %map3 -> %arg2 : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
     ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr):
-      %8 = llvm.load %arg0 : !llvm.ptr -> i32
-      %9 = llvm.load %arg1 : !llvm.ptr -> i32
+      %8 = ptr.load %arg0 : !llvm.ptr -> i32
+      %9 = ptr.load %arg1 : !llvm.ptr -> i32
       %10 = llvm.add %8, %9  : i32
-      llvm.store %10, %arg2 : i32, !llvm.ptr
+      ptr.store %10, %arg2 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-region-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-region-llvm.mlir
index a32ee3e184e26b..d833d6d626b080 100644
--- a/mlir/test/Target/LLVMIR/omptarget-region-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-region-llvm.mlir
@@ -10,17 +10,17 @@ module attributes {omp.is_target_device = false} {
     %5 = llvm.alloca %4 x i32 {bindc_name = "b", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_regionEb"} : (i64) -> !llvm.ptr
     %6 = llvm.mlir.constant(1 : i64) : i64
     %7 = llvm.alloca %6 x i32 {bindc_name = "c", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_regionEc"} : (i64) -> !llvm.ptr
-    llvm.store %1, %3 : i32, !llvm.ptr
-    llvm.store %0, %5 : i32, !llvm.ptr
+    ptr.store %1, %3 : i32, !llvm.ptr
+    ptr.store %0, %5 : i32, !llvm.ptr
     %map1 = omp.map.info var_ptr(%3 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     %map2 = omp.map.info var_ptr(%5 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     %map3 = omp.map.info var_ptr(%7 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     omp.target map_entries(%map1 -> %arg0, %map2 -> %arg1, %map3 -> %arg2 : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
     ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr):
-      %8 = llvm.load %arg0 : !llvm.ptr -> i32
-      %9 = llvm.load %arg1 : !llvm.ptr -> i32
+      %8 = ptr.load %arg0 : !llvm.ptr -> i32
+      %9 = ptr.load %arg1 : !llvm.ptr -> i32
       %10 = llvm.add %8, %9  : i32
-      llvm.store %10, %arg2 : i32, !llvm.ptr
+      ptr.store %10, %arg2 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-region-parallel-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-region-parallel-llvm.mlir
index 4072150a8eab83..baffcd601c7cea 100644
--- a/mlir/test/Target/LLVMIR/omptarget-region-parallel-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-region-parallel-llvm.mlir
@@ -10,18 +10,18 @@ module attributes {omp.is_target_device = false} {
     %5 = llvm.alloca %4 x i32 {bindc_name = "b", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_regionEb"} : (i64) -> !llvm.ptr
     %6 = llvm.mlir.constant(1 : i64) : i64
     %7 = llvm.alloca %6 x i32 {bindc_name = "c", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFomp_target_regionEc"} : (i64) -> !llvm.ptr
-    llvm.store %1, %3 : i32, !llvm.ptr
-    llvm.store %0, %5 : i32, !llvm.ptr
+    ptr.store %1, %3 : i32, !llvm.ptr
+    ptr.store %0, %5 : i32, !llvm.ptr
     %map1 = omp.map.info var_ptr(%3 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     %map2 = omp.map.info var_ptr(%5 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     %map3 = omp.map.info var_ptr(%7 : !llvm.ptr, i32)   map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
     omp.target map_entries( %map1 -> %arg0, %map2 -> %arg1, %map3 -> %arg2 : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
     ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr):
       omp.parallel {
-        %8 = llvm.load %arg0 : !llvm.ptr -> i32
-        %9 = llvm.load %arg1 : !llvm.ptr -> i32
+        %8 = ptr.load %arg0 : !llvm.ptr -> i32
+        %9 = ptr.load %arg1 : !llvm.ptr -> i32
         %10 = llvm.add %8, %9  : i32
-        llvm.store %10, %arg2 : i32, !llvm.ptr
+        ptr.store %10, %arg2 : i32, !llvm.ptr
         omp.terminator
         }
       omp.terminator
diff --git a/mlir/test/Target/LLVMIR/omptarget-wsloop-collapsed.mlir b/mlir/test/Target/LLVMIR/omptarget-wsloop-collapsed.mlir
index e246c551886cfa..f1aa362c98cee4 100644
--- a/mlir/test/Target/LLVMIR/omptarget-wsloop-collapsed.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-wsloop-collapsed.mlir
@@ -13,7 +13,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
       %2 = llvm.mul %arg2, %loop_ub overflow<nsw>  : i32
       %3 = llvm.add %arg1, %2 :i32
       %4 = llvm.getelementptr %arg0[%3] : (!llvm.ptr, i32) -> !llvm.ptr, i32
-      llvm.store %1, %4 : i32, !llvm.ptr
+      ptr.store %1, %4 : i32, !llvm.ptr
       omp.yield
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/omptarget-wsloop.mlir b/mlir/test/Target/LLVMIR/omptarget-wsloop.mlir
index 220eb85b3483ec..fa078c269fe652 100644
--- a/mlir/test/Target/LLVMIR/omptarget-wsloop.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-wsloop.mlir
@@ -10,7 +10,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.alloca_memo
       %loop_step = llvm.mlir.constant(1 : i32) : i32
       omp.wsloop for  (%loop_cnt) : i32 = (%loop_lb) to (%loop_ub) inclusive step (%loop_step) {
         %gep = llvm.getelementptr %arg0[0, %loop_cnt] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.array<10 x i32>
-        llvm.store %loop_cnt, %gep : i32, !llvm.ptr
+        ptr.store %loop_cnt, %gep : i32, !llvm.ptr
         omp.yield
       }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/opaque-ptr.mlir b/mlir/test/Target/LLVMIR/opaque-ptr.mlir
index c21f9b0542debc..30a1e5e7207668 100644
--- a/mlir/test/Target/LLVMIR/opaque-ptr.mlir
+++ b/mlir/test/Target/LLVMIR/opaque-ptr.mlir
@@ -3,21 +3,21 @@
 // CHECK-LABEL: @opaque_ptr_load
 llvm.func @opaque_ptr_load(%arg0: !llvm.ptr) -> i32 {
   // CHECK: load i32, ptr %{{.*}}
-  %0 = llvm.load %arg0 : !llvm.ptr -> i32
+  %0 = ptr.load %arg0 : !llvm.ptr -> i32
   llvm.return %0 : i32
 }
 
 // CHECK-LABEL: @opaque_ptr_store
 llvm.func @opaque_ptr_store(%arg0: i32, %arg1: !llvm.ptr){
   // CHECK: store i32 %{{.*}}, ptr %{{.*}}
-  llvm.store %arg0, %arg1 : i32, !llvm.ptr
+  ptr.store %arg0, %arg1 : i32, !llvm.ptr
   llvm.return
 }
 
 // CHECK-LABEL: @opaque_ptr_ptr_store
 llvm.func @opaque_ptr_ptr_store(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   // CHECK: store ptr %{{.*}}, ptr %{{.*}}
-  llvm.store %arg0, %arg1 : !llvm.ptr, !llvm.ptr
+  ptr.store %arg0, %arg1 : !llvm.ptr, !llvm.ptr
   llvm.return
 }
 
diff --git a/mlir/test/Target/LLVMIR/openacc-llvm.mlir b/mlir/test/Target/LLVMIR/openacc-llvm.mlir
index 897311c6e81bea..34fc4c16dce388 100644
--- a/mlir/test/Target/LLVMIR/openacc-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openacc-llvm.mlir
@@ -136,7 +136,7 @@ llvm.func @testdataop(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) {
   %1 = acc.create varPtr(%arg1 : !llvm.ptr) -> !llvm.ptr
   acc.data dataOperands(%0, %1 : !llvm.ptr, !llvm.ptr) {
     %9 = llvm.mlir.constant(2 : i32) : i32
-    llvm.store %9, %arg2 : i32, !llvm.ptr
+    ptr.store %9, %arg2 : i32, !llvm.ptr
     acc.terminator
   }
   acc.copyout accPtr(%0 : !llvm.ptr) to varPtr(%arg0 : !llvm.ptr)
diff --git a/mlir/test/Target/LLVMIR/openmp-firstprivate.mlir b/mlir/test/Target/LLVMIR/openmp-firstprivate.mlir
index 65ae98b2a74c6e..8d61e2a2124e55 100644
--- a/mlir/test/Target/LLVMIR/openmp-firstprivate.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-firstprivate.mlir
@@ -5,7 +5,7 @@
 
 llvm.func @parallel_op_firstprivate(%arg0: !llvm.ptr) {
   omp.parallel private(@x.privatizer %arg0 -> %arg2 : !llvm.ptr) {
-    %0 = llvm.load %arg2 : !llvm.ptr -> f32
+    %0 = ptr.load %arg2 : !llvm.ptr -> f32
     omp.terminator
   }
   llvm.return
@@ -18,8 +18,8 @@ omp.private {type = firstprivate} @x.privatizer : !llvm.ptr alloc {
   omp.yield(%0 : !llvm.ptr)
 } copy {
 ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-  %0 = llvm.load %arg0 : !llvm.ptr -> f32
-  llvm.store %0, %arg1 : f32, !llvm.ptr
+  %0 = ptr.load %arg0 : !llvm.ptr -> f32
+  ptr.store %0, %arg1 : f32, !llvm.ptr
   omp.yield(%arg1 : !llvm.ptr)
 }
 
@@ -53,7 +53,7 @@ omp.private {type = firstprivate} @x.privatizer : !llvm.ptr alloc {
 
 llvm.func @parallel_op_firstprivate_multi_block(%arg0: !llvm.ptr) {
   omp.parallel private(@multi_block.privatizer %arg0 -> %arg2 : !llvm.ptr) {
-    %0 = llvm.load %arg2 : !llvm.ptr -> f32
+    %0 = ptr.load %arg2 : !llvm.ptr -> f32
     omp.terminator
   }
   llvm.return
@@ -107,10 +107,10 @@ omp.private {type = firstprivate} @multi_block.privatizer : !llvm.ptr alloc {
 
 } copy {
 ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-  %0 = llvm.load %arg0 : !llvm.ptr -> f32
+  %0 = ptr.load %arg0 : !llvm.ptr -> f32
   llvm.br ^bb1(%0, %arg1 : f32, !llvm.ptr)
 
 ^bb1(%arg2: f32, %arg3: !llvm.ptr):
-  llvm.store %arg2, %arg3 : f32, !llvm.ptr
+  ptr.store %arg2, %arg3 : f32, !llvm.ptr
   omp.yield(%arg3 : !llvm.ptr)
 }
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm-invalid.mlir b/mlir/test/Target/LLVMIR/openmp-llvm-invalid.mlir
index 3c6ca1ef0c6bf5..8dfd62853c468c 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm-invalid.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm-invalid.mlir
@@ -78,14 +78,14 @@ llvm.func @omp_threadprivate() {
   // expected-error @below {{LLVM Translation failed for operation: omp.threadprivate}}
   %5 = omp.threadprivate %4 : !llvm.ptr -> !llvm.ptr
 
-  llvm.store %1, %5 : i32, !llvm.ptr
+  ptr.store %1, %5 : i32, !llvm.ptr
 
   omp.parallel  {
     %6 = omp.threadprivate %4 : !llvm.ptr -> !llvm.ptr
-    llvm.store %2, %6 : i32, !llvm.ptr
+    ptr.store %2, %6 : i32, !llvm.ptr
     omp.terminator
   }
 
-  llvm.store %3, %5 : i32, !llvm.ptr
+  ptr.store %3, %5 : i32, !llvm.ptr
   llvm.return
 }
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index 4cb99c1f1a285b..efaef2af5588b0 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -35,7 +35,7 @@ llvm.func @test_flush_construct(%arg0: !llvm.ptr) {
   // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
   omp.flush
   //  CHECK: load i32, ptr
-  %2 = llvm.load %1 : !llvm.ptr -> i32
+  %2 = ptr.load %1 : !llvm.ptr -> i32
 
   // CHECK-NEXT:    ret void
   llvm.return
@@ -328,7 +328,7 @@ llvm.func @wsloop_simple(%arg0: !llvm.ptr) {
       // CHECK: call void @__kmpc_for_static_init_{{.*}}(ptr @[[$loc_struct]],
       %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
       %4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-      llvm.store %3, %4 : f32, !llvm.ptr
+      ptr.store %3, %4 : f32, !llvm.ptr
       omp.yield
       // CHECK: call void @__kmpc_for_static_fini(ptr @[[$loc_struct]],
     }) {operandSegmentSizes = array<i32: 1, 1, 1, 0, 0, 0, 0>} : (i64, i64, i64) -> ()
@@ -349,7 +349,7 @@ llvm.func @wsloop_inclusive_1(%arg0: !llvm.ptr) {
   ^bb0(%arg1: i64):
     %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
     %4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %3, %4 : f32, !llvm.ptr
+    ptr.store %3, %4 : f32, !llvm.ptr
     omp.yield
   }) {operandSegmentSizes = array<i32: 1, 1, 1, 0, 0, 0, 0>} : (i64, i64, i64) -> ()
   llvm.return
@@ -367,7 +367,7 @@ llvm.func @wsloop_inclusive_2(%arg0: !llvm.ptr) {
   ^bb0(%arg1: i64):
     %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
     %4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %3, %4 : f32, !llvm.ptr
+    ptr.store %3, %4 : f32, !llvm.ptr
     omp.yield
   }) {inclusive, operandSegmentSizes = array<i32: 1, 1, 1, 0, 0, 0, 0>} : (i64, i64, i64) -> ()
   llvm.return
@@ -465,7 +465,7 @@ llvm.func @body(i32)
 llvm.func @test_omp_wsloop_dynamic_chunk_var(%lb : i32, %ub : i32, %step : i32) -> () {
  %1 = llvm.mlir.constant(1 : i64) : i64
  %chunk_size_alloca = llvm.alloca %1 x i16 {bindc_name = "chunk_size", in_type = i16, uniq_name = "_QFsub1Echunk_size"} : (i64) -> !llvm.ptr
- %chunk_size_var = llvm.load %chunk_size_alloca : !llvm.ptr -> i16
+ %chunk_size_var = ptr.load %chunk_size_alloca : !llvm.ptr -> i16
  omp.wsloop schedule(dynamic = %chunk_size_var : i16)
  for (%iv) : i32 = (%lb) to (%ub) step (%step) {
   // CHECK: %[[CHUNK_SIZE:.*]] = sext i16 %{{.*}} to i32
@@ -486,7 +486,7 @@ llvm.func @body(i32)
 llvm.func @test_omp_wsloop_dynamic_chunk_var2(%lb : i32, %ub : i32, %step : i32) -> () {
  %1 = llvm.mlir.constant(1 : i64) : i64
  %chunk_size_alloca = llvm.alloca %1 x i64 {bindc_name = "chunk_size", in_type = i64, uniq_name = "_QFsub1Echunk_size"} : (i64) -> !llvm.ptr
- %chunk_size_var = llvm.load %chunk_size_alloca : !llvm.ptr -> i64
+ %chunk_size_var = ptr.load %chunk_size_alloca : !llvm.ptr -> i64
  omp.wsloop schedule(dynamic = %chunk_size_var : i64)
  for (%iv) : i32 = (%lb) to (%ub) step (%step) {
   // CHECK: %[[CHUNK_SIZE:.*]] = trunc i64 %{{.*}} to i32
@@ -647,7 +647,7 @@ llvm.func @simdloop_simple(%lb : i64, %ub : i64, %step : i64, %arg0: !llvm.ptr)
       // tested there. Just check that the right metadata is added.
       // CHECK: llvm.access.group
       %4 = llvm.getelementptr %arg0[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-      llvm.store %3, %4 : f32, !llvm.ptr
+      ptr.store %3, %4 : f32, !llvm.ptr
       omp.yield
   }) {operandSegmentSizes = array<i32: 1,1,1,0,0,0>} :
     (i64, i64, i64) -> ()
@@ -684,8 +684,8 @@ llvm.func @simdloop_simple_multiple(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 :
     // CHECK-NEXT: llvm.access.group
     %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
     %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %3, %4 : f32, !llvm.ptr
-    llvm.store %3, %5 : f32, !llvm.ptr
+    ptr.store %3, %4 : f32, !llvm.ptr
+    ptr.store %3, %5 : f32, !llvm.ptr
     omp.yield
   }
   llvm.return
@@ -705,8 +705,8 @@ llvm.func @simdloop_simple_multiple_simdlen(%lb1 : i64, %ub1 : i64, %step1 : i64
     // CHECK-NEXT: llvm.access.group
     %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
     %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %3, %4 : f32, !llvm.ptr
-    llvm.store %3, %5 : f32, !llvm.ptr
+    ptr.store %3, %4 : f32, !llvm.ptr
+    ptr.store %3, %5 : f32, !llvm.ptr
     omp.yield
   }
   llvm.return
@@ -723,8 +723,8 @@ llvm.func @simdloop_simple_multiple_safelen(%lb1 : i64, %ub1 : i64, %step1 : i64
     %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
     %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
     %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %3, %4 : f32, !llvm.ptr
-    llvm.store %3, %5 : f32, !llvm.ptr
+    ptr.store %3, %4 : f32, !llvm.ptr
+    ptr.store %3, %5 : f32, !llvm.ptr
     omp.yield
   }
   llvm.return
@@ -740,8 +740,8 @@ llvm.func @simdloop_simple_multiple_simdlen_safelen(%lb1 : i64, %ub1 : i64, %ste
     %3 = llvm.mlir.constant(2.000000e+00 : f32) : f32
     %4 = llvm.getelementptr %arg0[%iv1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
     %5 = llvm.getelementptr %arg1[%iv2] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-    llvm.store %3, %4 : f32, !llvm.ptr
-    llvm.store %3, %5 : f32, !llvm.ptr
+    ptr.store %3, %4 : f32, !llvm.ptr
+    ptr.store %3, %5 : f32, !llvm.ptr
     omp.yield
   }
   llvm.return
@@ -758,16 +758,16 @@ llvm.func @simdloop_if(%arg0: !llvm.ptr {fir.bindc_name = "n"}, %arg1: !llvm.ptr
   %2 = llvm.mlir.constant(1 : i64) : i64
   %3 = llvm.alloca %2 x i32 {bindc_name = "i", in_type = i32, operandSegmentSizes = array<i32: 0, 0>, uniq_name = "_QFtest_simdEi"} : (i64) -> !llvm.ptr
   %4 = llvm.mlir.constant(0 : i32) : i32
-  %5 = llvm.load %arg0 : !llvm.ptr -> i32
+  %5 = ptr.load %arg0 : !llvm.ptr -> i32
   %6 = llvm.mlir.constant(1 : i32) : i32
-  %7 = llvm.load %arg0 : !llvm.ptr -> i32
-  %8 = llvm.load %arg1 : !llvm.ptr -> i32
+  %7 = ptr.load %arg0 : !llvm.ptr -> i32
+  %8 = ptr.load %arg1 : !llvm.ptr -> i32
   %9 = llvm.icmp "sge" %7, %8 : i32
   omp.simdloop   if(%9) for  (%arg2) : i32 = (%4) to (%5) inclusive step (%6) {
     // The form of the emitted IR is controlled by OpenMPIRBuilder and
     // tested there. Just check that the right metadata is added.
     // CHECK: llvm.access.group
-    llvm.store %arg2, %1 : i32, !llvm.ptr
+    ptr.store %arg2, %1 : i32, !llvm.ptr
     omp.yield
   }
   llvm.return
@@ -959,7 +959,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_.var{{.*}})
@@ -969,7 +969,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_none) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_none.var{{.*}})
@@ -979,7 +979,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_uncontended) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_uncontended.var{{.*}})
@@ -989,7 +989,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_contended) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_contended.var{{.*}})
@@ -999,7 +999,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_nonspeculative) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_nonspeculative.var{{.*}})
@@ -1009,7 +1009,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_nonspeculative_uncontended) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_nonspeculative_uncontended.var{{.*}})
@@ -1019,7 +1019,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_nonspeculative_contended) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_nonspeculative_contended.var{{.*}})
@@ -1029,7 +1029,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_speculative) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_speculative.var{{.*}})
@@ -1039,7 +1039,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_speculative_uncontended) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_speculative_uncontended.var{{.*}})
@@ -1049,7 +1049,7 @@ llvm.func @omp_critical(%x : !llvm.ptr, %xval : i32) -> () {
   // CHECK: omp.critical.region
   omp.critical(@mutex_speculative_contended) {
   // CHECK: store
-    llvm.store %xval, %x : i32, !llvm.ptr
+    ptr.store %xval, %x : i32, !llvm.ptr
     omp.terminator
   }
   // CHECK: call void @__kmpc_end_critical({{.*}}critical_user_mutex_speculative_contended.var{{.*}})
@@ -1105,11 +1105,11 @@ llvm.func @collapse_wsloop(
     // CHECK: call void @__kmpc_for_static_init_4u
     omp.wsloop
     for (%arg0, %arg1, %arg2) : i32 = (%0, %1, %2) to (%3, %4, %5) step (%6, %7, %8) {
-      %31 = llvm.load %20 : !llvm.ptr -> i32
+      %31 = ptr.load %20 : !llvm.ptr -> i32
       %32 = llvm.add %31, %arg0 : i32
       %33 = llvm.add %32, %arg1 : i32
       %34 = llvm.add %33, %arg2 : i32
-      llvm.store %34, %20 : i32, !llvm.ptr
+      ptr.store %34, %20 : i32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -1166,11 +1166,11 @@ llvm.func @collapse_wsloop_dynamic(
     // CHECK: call void @__kmpc_dispatch_init_4u
     omp.wsloop schedule(dynamic)
     for (%arg0, %arg1, %arg2) : i32 = (%0, %1, %2) to (%3, %4, %5) step (%6, %7, %8) {
-      %31 = llvm.load %20 : !llvm.ptr -> i32
+      %31 = ptr.load %20 : !llvm.ptr -> i32
       %32 = llvm.add %31, %arg0 : i32
       %33 = llvm.add %32, %arg1 : i32
       %34 = llvm.add %33, %arg2 : i32
-      llvm.store %34, %20 : i32, !llvm.ptr
+      ptr.store %34, %20 : i32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -2085,7 +2085,7 @@ llvm.func @omp_sections(%arg0 : i32, %arg1 : i32, %arg2 : !llvm.ptr) -> () {
       %add = llvm.add %arg0, %arg1 : i32
       // CHECK:   store i32 %{{.*}}, ptr %{{.*}}, align 4
       // CHECK:   br label %{{.*}}
-      llvm.store %add, %arg2 : i32, !llvm.ptr
+      ptr.store %add, %arg2 : i32, !llvm.ptr
       omp.terminator
     }
     omp.terminator
@@ -2138,13 +2138,13 @@ llvm.func @single(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
   // CHECK: %[[a:.*]] = sub i32 %[[x]], %[[y]]
   %a = llvm.sub %x, %y : i32
   // CHECK: store i32 %[[a]], ptr %[[zaddr]]
-  llvm.store %a, %zaddr : i32, !llvm.ptr
+  ptr.store %a, %zaddr : i32, !llvm.ptr
   // CHECK: call i32 @__kmpc_single
   omp.single {
     // CHECK: %[[z:.*]] = add i32 %[[x]], %[[y]]
     %z = llvm.add %x, %y : i32
     // CHECK: store i32 %[[z]], ptr %[[zaddr]]
-    llvm.store %z, %zaddr : i32, !llvm.ptr
+    ptr.store %z, %zaddr : i32, !llvm.ptr
     // CHECK: call void @__kmpc_end_single
     // CHECK: call void @__kmpc_barrier
     omp.terminator
@@ -2152,7 +2152,7 @@ llvm.func @single(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
   // CHECK: %[[b:.*]] = mul i32 %[[x]], %[[y]]
   %b = llvm.mul %x, %y : i32
   // CHECK: store i32 %[[b]], ptr %[[zaddr]]
-  llvm.store %b, %zaddr : i32, !llvm.ptr
+  ptr.store %b, %zaddr : i32, !llvm.ptr
   // CHECK: ret void
   llvm.return
 }
@@ -2165,13 +2165,13 @@ llvm.func @single_nowait(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
   // CHECK: %[[a:.*]] = sub i32 %[[x]], %[[y]]
   %a = llvm.sub %x, %y : i32
   // CHECK: store i32 %[[a]], ptr %[[zaddr]]
-  llvm.store %a, %zaddr : i32, !llvm.ptr
+  ptr.store %a, %zaddr : i32, !llvm.ptr
   // CHECK: call i32 @__kmpc_single
   omp.single nowait {
     // CHECK: %[[z:.*]] = add i32 %[[x]], %[[y]]
     %z = llvm.add %x, %y : i32
     // CHECK: store i32 %[[z]], ptr %[[zaddr]]
-    llvm.store %z, %zaddr : i32, !llvm.ptr
+    ptr.store %z, %zaddr : i32, !llvm.ptr
     // CHECK: call void @__kmpc_end_single
     // CHECK-NOT: call void @__kmpc_barrier
     omp.terminator
@@ -2179,7 +2179,7 @@ llvm.func @single_nowait(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
   // CHECK: %[[t:.*]] = mul i32 %[[x]], %[[y]]
   %t = llvm.mul %x, %y : i32
   // CHECK: store i32 %[[t]], ptr %[[zaddr]]
-  llvm.store %t, %zaddr : i32, !llvm.ptr
+  ptr.store %t, %zaddr : i32, !llvm.ptr
   // CHECK: ret void
   llvm.return
 }
@@ -2197,17 +2197,17 @@ llvm.func @single_copyprivate(%ip: !llvm.ptr, %fp: !llvm.ptr) {
   // CHECK: call i32 @__kmpc_single
   omp.single copyprivate(%ip -> @copy_i32 : !llvm.ptr, %fp -> @copy_f32 : !llvm.ptr) {
     // CHECK: %[[i:.*]] = load i32, ptr %[[ip]]
-    %i = llvm.load %ip : !llvm.ptr -> i32
+    %i = ptr.load %ip : !llvm.ptr -> i32
     // CHECK: %[[i2:.*]] = add i32 %[[i]], %[[i]]
     %i2 = llvm.add %i, %i : i32
     // CHECK: store i32 %[[i2]], ptr %[[ip]]
-    llvm.store %i2, %ip : i32, !llvm.ptr
+    ptr.store %i2, %ip : i32, !llvm.ptr
     // CHECK: %[[f:.*]] = load float, ptr %[[fp]]
-    %f = llvm.load %fp : !llvm.ptr -> f32
+    %f = ptr.load %fp : !llvm.ptr -> f32
     // CHECK: %[[f2:.*]] = fadd float %[[f]], %[[f]]
     %f2 = llvm.fadd %f, %f : f32
     // CHECK: store float %[[f2]], ptr %[[fp]]
-    llvm.store %f2, %fp : f32, !llvm.ptr
+    ptr.store %f2, %fp : f32, !llvm.ptr
     // CHECK: store i32 1, ptr %[[didit_addr]]
     // CHECK: call void @__kmpc_end_single
     // CHECK: %[[didit:.*]] = load i32, ptr %[[didit_addr]]
@@ -2245,15 +2245,15 @@ llvm.func @omp_threadprivate() {
   %3 = llvm.mlir.addressof @_QFsubEx : !llvm.ptr
   %4 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
 
-  llvm.store %0, %4 : i32, !llvm.ptr
+  ptr.store %0, %4 : i32, !llvm.ptr
 
   omp.parallel  {
     %5 = omp.threadprivate %3 : !llvm.ptr -> !llvm.ptr
-    llvm.store %1, %5 : i32, !llvm.ptr
+    ptr.store %1, %5 : i32, !llvm.ptr
     omp.terminator
   }
 
-  llvm.store %2, %4 : i32, !llvm.ptr
+  ptr.store %2, %4 : i32, !llvm.ptr
   llvm.return
 }
 
@@ -2272,9 +2272,9 @@ llvm.func @omp_task(%x: i32, %y: i32, %zaddr: !llvm.ptr) {
   omp.task {
     %n = llvm.mlir.constant(1 : i64) : i64
     %valaddr = llvm.alloca %n x i32 : (i64) -> !llvm.ptr
-    %val = llvm.load %valaddr : !llvm.ptr -> i32
+    %val = ptr.load %valaddr : !llvm.ptr -> i32
     %double = llvm.add %val, %val : i32
-    llvm.store %double, %valaddr : i32, !llvm.ptr
+    ptr.store %double, %valaddr : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -2338,9 +2338,9 @@ llvm.func @omp_task_with_deps(%zaddr: !llvm.ptr) {
   omp.task depend(taskdependin -> %zaddr : !llvm.ptr) {
     %n = llvm.mlir.constant(1 : i64) : i64
     %valaddr = llvm.alloca %n x i32 : (i64) -> !llvm.ptr
-    %val = llvm.load %valaddr : !llvm.ptr -> i32
+    %val = ptr.load %valaddr : !llvm.ptr -> i32
     %double = llvm.add %val, %val : i32
-    llvm.store %double, %valaddr : i32, !llvm.ptr
+    ptr.store %double, %valaddr : i32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -2369,7 +2369,7 @@ module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu"} {
     // CHECK: %[[diff:.+]] = sub i32 %[[x]], %[[y]]
     %diff = llvm.sub %x, %y : i32
     // CHECK: store i32 %[[diff]], ptr %2
-    llvm.store %diff, %zaddr : i32, !llvm.ptr
+    ptr.store %diff, %zaddr : i32, !llvm.ptr
     // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num({{.+}})
     // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc
     // CHECK-SAME: (ptr @{{.+}}, i32 %[[omp_global_thread_num]], i32 1, i64 40, i64 16,
@@ -2379,13 +2379,13 @@ module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu"} {
     // CHECK: call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]])
     omp.task {
       %z = llvm.add %x, %y : i32
-      llvm.store %z, %zaddr : i32, !llvm.ptr
+      ptr.store %z, %zaddr : i32, !llvm.ptr
       omp.terminator
     }
     // CHECK: %[[prod:.+]] = mul i32 %[[x]], %[[y]]
     %b = llvm.mul %x, %y : i32
     // CHECK: store i32 %[[prod]], ptr %[[zaddr]]
-    llvm.store %b, %zaddr : i32, !llvm.ptr
+    ptr.store %b, %zaddr : i32, !llvm.ptr
     llvm.return
   }
 }
@@ -2409,7 +2409,7 @@ llvm.func @par_task_(%arg0: !llvm.ptr {fir.bindc_name = "a"}) {
   %0 = llvm.mlir.constant(1 : i32) : i32
   omp.task   {
     omp.parallel   {
-      llvm.store %0, %arg0 : i32, !llvm.ptr
+      ptr.store %0, %arg0 : i32, !llvm.ptr
       omp.terminator
     }
     omp.terminator
diff --git a/mlir/test/Target/LLVMIR/openmp-nested.mlir b/mlir/test/Target/LLVMIR/openmp-nested.mlir
index e1fdfdd24a3cb0..02e80dd49249c1 100644
--- a/mlir/test/Target/LLVMIR/openmp-nested.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-nested.mlir
@@ -14,12 +14,12 @@ module {
       omp.wsloop for (%arg2) : i64 = (%2) to (%1) step (%0)  {
         omp.parallel   {
           omp.wsloop for (%arg3) : i64 = (%2) to (%0) step (%0)  {
-            llvm.store %2, %12 : i64, !llvm.ptr
+            ptr.store %2, %12 : i64, !llvm.ptr
             omp.yield
           }
           omp.terminator
         }
-        %19 = llvm.load %12 : !llvm.ptr -> i64
+        %19 = ptr.load %12 : !llvm.ptr -> i64
         %20 = llvm.trunc %19 : i64 to i32
         %5 = llvm.mlir.addressof @str0 : !llvm.ptr
         %6 = llvm.getelementptr %5[%4, %4] : (!llvm.ptr, i32, i32) -> !llvm.ptr, !llvm.array<29 x i8>
diff --git a/mlir/test/Target/LLVMIR/openmp-private.mlir b/mlir/test/Target/LLVMIR/openmp-private.mlir
index 58bda87c3b7bea..d1c962344279b6 100644
--- a/mlir/test/Target/LLVMIR/openmp-private.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-private.mlir
@@ -5,7 +5,7 @@
 
 llvm.func @parallel_op_1_private(%arg0: !llvm.ptr) {
   omp.parallel private(@x.privatizer %arg0 -> %arg2 : !llvm.ptr) {
-    %0 = llvm.load %arg2 : !llvm.ptr -> f32
+    %0 = ptr.load %arg2 : !llvm.ptr -> f32
     omp.terminator
   }
   llvm.return
@@ -36,8 +36,8 @@ llvm.func @parallel_op_1_private(%arg0: !llvm.ptr) {
 
 llvm.func @parallel_op_2_privates(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   omp.parallel private(@x.privatizer %arg0 -> %arg2 : !llvm.ptr, @y.privatizer %arg1 -> %arg3 : !llvm.ptr) {
-    %0 = llvm.load %arg2 : !llvm.ptr -> f32
-    %1 = llvm.load %arg3 : !llvm.ptr -> i32
+    %0 = ptr.load %arg2 : !llvm.ptr -> f32
+    %1 = ptr.load %arg3 : !llvm.ptr -> i32
     omp.terminator
   }
   llvm.return
@@ -76,8 +76,8 @@ omp.private {type = private} @x.privatizer : !llvm.ptr alloc {
 ^bb0(%arg0: !llvm.ptr):
   %c1 = llvm.mlir.constant(1 : i32) : i32
   %0 = llvm.alloca %c1 x f32 : (i32) -> !llvm.ptr
-  %1 = llvm.load %arg0 : !llvm.ptr -> f32
-  llvm.store %1, %0 : f32, !llvm.ptr
+  %1 = ptr.load %arg0 : !llvm.ptr -> f32
+  ptr.store %1, %0 : f32, !llvm.ptr
   omp.yield(%0 : !llvm.ptr)
 }
 
@@ -85,8 +85,8 @@ omp.private {type = private} @y.privatizer : !llvm.ptr alloc {
 ^bb0(%arg0: !llvm.ptr):
   %c1 = llvm.mlir.constant(1 : i32) : i32
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
-  %1 = llvm.load %arg0 : !llvm.ptr -> i32
-  llvm.store %1, %0 : i32, !llvm.ptr
+  %1 = ptr.load %arg0 : !llvm.ptr -> i32
+  ptr.store %1, %0 : i32, !llvm.ptr
   omp.yield(%0 : !llvm.ptr)
 }
 
@@ -94,7 +94,7 @@ omp.private {type = private} @y.privatizer : !llvm.ptr alloc {
 
 llvm.func @parallel_op_private_multi_block(%arg0: !llvm.ptr) {
   omp.parallel private(@multi_block.privatizer %arg0 -> %arg2 : !llvm.ptr) {
-    %0 = llvm.load %arg2 : !llvm.ptr -> f32
+    %0 = ptr.load %arg2 : !llvm.ptr -> f32
     omp.terminator
   }
   llvm.return
@@ -136,7 +136,7 @@ omp.private {type = private} @multi_block.privatizer : !llvm.ptr alloc {
   llvm.br ^bb1(%arg0, %0 : !llvm.ptr, !llvm.ptr)
 
 ^bb1(%arg1: !llvm.ptr, %arg2: !llvm.ptr):
-  %1 = llvm.load %arg1 : !llvm.ptr -> f32
-  llvm.store %1, %arg2 : f32, !llvm.ptr
+  %1 = ptr.load %arg1 : !llvm.ptr -> f32
+  ptr.store %1, %arg2 : f32, !llvm.ptr
   omp.yield(%arg2 : !llvm.ptr)
 }
diff --git a/mlir/test/Target/LLVMIR/openmp-reduction-byref.mlir b/mlir/test/Target/LLVMIR/openmp-reduction-byref.mlir
index e720969e82c112..e5b1970a39db51 100644
--- a/mlir/test/Target/LLVMIR/openmp-reduction-byref.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-reduction-byref.mlir
@@ -5,14 +5,14 @@
     %0 = llvm.mlir.constant(0 : i32) : i32
     %1 = llvm.mlir.constant(1 : i64) : i64
     %2 = llvm.alloca %1 x i32 : (i64) -> !llvm.ptr
-    llvm.store %0, %2 : i32, !llvm.ptr
+    ptr.store %0, %2 : i32, !llvm.ptr
     omp.yield(%2 : !llvm.ptr)
   } combiner {
   ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-    %0 = llvm.load %arg0 : !llvm.ptr -> i32
-    %1 = llvm.load %arg1 : !llvm.ptr -> i32
+    %0 = ptr.load %arg0 : !llvm.ptr -> i32
+    %1 = ptr.load %arg1 : !llvm.ptr -> i32
     %2 = llvm.add %0, %1  : i32
-    llvm.store %2, %arg0 : i32, !llvm.ptr
+    ptr.store %2, %arg0 : i32, !llvm.ptr
     omp.yield(%arg0 : !llvm.ptr)
   } 
 
@@ -21,7 +21,7 @@
     %0 = llvm.mlir.constant(-1 : i32) : i32
     %1 = llvm.mlir.addressof @i : !llvm.ptr
     omp.parallel byref reduction(@add_reduction_i_32 %1 -> %arg0 : !llvm.ptr) {
-      llvm.store %0, %arg0 : i32, !llvm.ptr
+      ptr.store %0, %arg0 : i32, !llvm.ptr
       omp.terminator
     }
     llvm.return
diff --git a/mlir/test/Target/LLVMIR/openmp-reduction-call.mlir b/mlir/test/Target/LLVMIR/openmp-reduction-call.mlir
index da240f4a6fff37..b500b00f77e700 100644
--- a/mlir/test/Target/LLVMIR/openmp-reduction-call.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-reduction-call.mlir
@@ -21,9 +21,9 @@ llvm.func @simple_reduction(%lb : i64, %ub : i64, %step : i64) {
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
   omp.parallel reduction(@add_f32 %0 -> %prv : !llvm.ptr) {
     %1 = llvm.mlir.constant(2.0 : f32) : f32
-    %2 = llvm.load %prv : !llvm.ptr -> f32
+    %2 = ptr.load %prv : !llvm.ptr -> f32
     %3 = llvm.fadd %1, %2 : f32
-    llvm.store %3, %prv : f32, !llvm.ptr
+    ptr.store %3, %prv : f32, !llvm.ptr
     omp.terminator
   }
   llvm.return
diff --git a/mlir/test/Target/LLVMIR/openmp-reduction.mlir b/mlir/test/Target/LLVMIR/openmp-reduction.mlir
index 39b64d71a2274b..4c2032cd2d6a9a 100644
--- a/mlir/test/Target/LLVMIR/openmp-reduction.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-reduction.mlir
@@ -16,8 +16,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -29,9 +29,9 @@ llvm.func @simple_reduction(%lb : i64, %ub : i64, %step : i64) {
     omp.wsloop reduction(@add_f32 %0 -> %prv : !llvm.ptr)
     for (%iv) : i64 = (%lb) to (%ub) step (%step) {
       %1 = llvm.mlir.constant(2.0 : f32) : f32
-      %2 = llvm.load %prv : !llvm.ptr -> f32
+      %2 = ptr.load %prv : !llvm.ptr -> f32
       %3 = llvm.fadd %1, %2 : f32
-      llvm.store %3, %prv : f32, !llvm.ptr
+      ptr.store %3, %prv : f32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -91,8 +91,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -108,12 +108,12 @@ llvm.func @reuse_declaration(%lb : i64, %ub : i64, %step : i64) {
     omp.wsloop reduction(@add_f32 %0 -> %prv0 : !llvm.ptr, @add_f32 %2 -> %prv1 : !llvm.ptr)
     for (%iv) : i64 = (%lb) to (%ub) step (%step) {
       %1 = llvm.mlir.constant(2.0 : f32) : f32
-      %3 = llvm.load %prv0 : !llvm.ptr -> f32
+      %3 = ptr.load %prv0 : !llvm.ptr -> f32
       %4 = llvm.fadd %3, %1 : f32
-      llvm.store %4, %prv0 : f32, !llvm.ptr
-      %5 = llvm.load %prv1 : !llvm.ptr -> f32
+      ptr.store %4, %prv0 : f32, !llvm.ptr
+      %5 = ptr.load %prv1 : !llvm.ptr -> f32
       %6 = llvm.fadd %5, %1 : f32
-      llvm.store %6, %prv1 : f32, !llvm.ptr
+      ptr.store %6, %prv1 : f32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -183,8 +183,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -198,9 +198,9 @@ llvm.func @missing_omp_reduction(%lb : i64, %ub : i64, %step : i64) {
     omp.wsloop reduction(@add_f32 %0 -> %prv0 : !llvm.ptr, @add_f32 %2 -> %prv1 : !llvm.ptr)
     for (%iv) : i64 = (%lb) to (%ub) step (%step) {
       %1 = llvm.mlir.constant(2.0 : f32) : f32
-      %3 = llvm.load %prv0 : !llvm.ptr -> f32
+      %3 = ptr.load %prv0 : !llvm.ptr -> f32
       %4 = llvm.fadd %3, %1 : f32
-      llvm.store %4, %prv0 : f32, !llvm.ptr
+      ptr.store %4, %prv0 : f32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -268,8 +268,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -283,12 +283,12 @@ llvm.func @double_reference(%lb : i64, %ub : i64, %step : i64) {
     omp.wsloop reduction(@add_f32 %0 -> %prv : !llvm.ptr)
     for (%iv) : i64 = (%lb) to (%ub) step (%step) {
       %1 = llvm.mlir.constant(2.0 : f32) : f32
-      %2 = llvm.load %prv : !llvm.ptr -> f32
+      %2 = ptr.load %prv : !llvm.ptr -> f32
       %3 = llvm.fadd %2, %1 : f32
-      llvm.store %3, %prv : f32, !llvm.ptr
-      %4 = llvm.load %prv : !llvm.ptr -> f32
+      ptr.store %3, %prv : f32, !llvm.ptr
+      %4 = ptr.load %prv : !llvm.ptr -> f32
       %5 = llvm.fadd %4, %1 : f32
-      llvm.store %5, %prv : f32, !llvm.ptr
+      ptr.store %5, %prv : f32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -351,8 +351,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -377,12 +377,12 @@ llvm.func @no_atomic(%lb : i64, %ub : i64, %step : i64) {
     omp.wsloop reduction(@add_f32 %0 -> %prv0 : !llvm.ptr, @mul_f32 %2 -> %prv1 : !llvm.ptr)
     for (%iv) : i64 = (%lb) to (%ub) step (%step) {
       %1 = llvm.mlir.constant(2.0 : f32) : f32
-      %3 = llvm.load %prv0 : !llvm.ptr -> f32
+      %3 = ptr.load %prv0 : !llvm.ptr -> f32
       %4 = llvm.fadd %3, %1 : f32
-      llvm.store %4, %prv0 : f32, !llvm.ptr
-      %5 = llvm.load %prv1 : !llvm.ptr -> f32
+      ptr.store %4, %prv0 : f32, !llvm.ptr
+      %5 = ptr.load %prv1 : !llvm.ptr -> f32
       %6 = llvm.fmul %5, %1 : f32
-      llvm.store %6, %prv1 : f32, !llvm.ptr
+      ptr.store %6, %prv1 : f32, !llvm.ptr
       omp.yield
     }
     omp.terminator
@@ -448,8 +448,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> f32
-  llvm.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
+  %2 = ptr.load %arg3 : !llvm.ptr -> f32
+  ptr.atomicrmw fadd %arg2, %2 monotonic : !llvm.ptr, f32
   omp.yield
 }
 
@@ -459,9 +459,9 @@ llvm.func @simple_reduction_parallel() {
   %0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr
   omp.parallel reduction(@add_f32 %0 -> %prv : !llvm.ptr) {
     %1 = llvm.mlir.constant(2.0 : f32) : f32
-    %2 = llvm.load %prv : !llvm.ptr -> f32
+    %2 = ptr.load %prv : !llvm.ptr -> f32
     %3 = llvm.fadd %2, %1 : f32
-    llvm.store %3, %prv : f32, !llvm.ptr
+    ptr.store %3, %prv : f32, !llvm.ptr
     omp.terminator
   }
   llvm.return
@@ -517,8 +517,8 @@ combiner {
 }
 atomic {
 ^bb2(%arg2: !llvm.ptr, %arg3: !llvm.ptr):
-  %2 = llvm.load %arg3 : !llvm.ptr -> i32
-  llvm.atomicrmw add %arg2, %2 monotonic : !llvm.ptr, i32
+  %2 = ptr.load %arg3 : !llvm.ptr -> i32
+  ptr.atomicrmw add %arg2, %2 monotonic : !llvm.ptr, i32
   omp.yield
 }
 
@@ -533,9 +533,9 @@ llvm.func @parallel_nested_workshare_reduction(%ub : i64) {
   omp.parallel reduction(@add_i32 %0 -> %prv : !llvm.ptr) {
     omp.wsloop for (%iv) : i64 = (%lb) to (%ub) step (%step) {
       %ival = llvm.trunc %iv : i64 to i32
-      %lprv = llvm.load %prv : !llvm.ptr -> i32
+      %lprv = ptr.load %prv : !llvm.ptr -> i32
       %add = llvm.add %lprv, %ival : i32
-      llvm.store %add, %prv : i32, !llvm.ptr
+      ptr.store %add, %prv : i32, !llvm.ptr
       omp.yield
     }
     omp.terminator
diff --git a/mlir/test/Target/LLVMIR/openmp-teams.mlir b/mlir/test/Target/LLVMIR/openmp-teams.mlir
index 4690b51122beba..d98ac961cb1f58 100644
--- a/mlir/test/Target/LLVMIR/openmp-teams.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-teams.mlir
@@ -106,7 +106,7 @@ llvm.func @bar()
 // CHECK: ret void
 llvm.func @omp_teams_branching_shared(%condition: i1, %arg0: i32, %arg1: f32, %arg2: !llvm.ptr, %arg3: f128) {
     %allocated = llvm.call @my_alloca_fn(): () -> !llvm.ptr
-    %loaded = llvm.load %allocated : !llvm.ptr -> i32
+    %loaded = ptr.load %allocated : !llvm.ptr -> i32
     llvm.br ^codegenBlock
 ^codegenBlock:
     omp.teams {
diff --git a/mlir/test/Target/LLVMIR/target-ext-type.mlir b/mlir/test/Target/LLVMIR/target-ext-type.mlir
index 6b2d2ea3d4c231..f23acbdd64c33a 100644
--- a/mlir/test/Target/LLVMIR/target-ext-type.mlir
+++ b/mlir/test/Target/LLVMIR/target-ext-type.mlir
@@ -14,7 +14,7 @@ llvm.func @func2() -> !llvm.target<"spirv.Event"> {
   %0 = llvm.mlir.constant(1 : i32) : i32
   %1 = llvm.mlir.poison : !llvm.target<"spirv.Event">
   %2 = llvm.alloca %0 x !llvm.target<"spirv.Event"> {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  %3 = llvm.load %2 {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"spirv.Event">
+  %3 = ptr.load %2 {alignment = 8 : i64} : !llvm.ptr -> !llvm.target<"spirv.Event">
   llvm.return %1 : !llvm.target<"spirv.Event">
 }
 
diff --git a/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp b/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
index 66578b246afab1..db131207c19c8d 100644
--- a/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
+++ b/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
@@ -193,6 +193,11 @@ struct TestOpAsmInterface : public OpAsmDialectInterface {
                   StringRef("test_alias_conflict0_"))
             .Case("alias_test:tensor_encoding", StringRef("test_encoding"))
             .Default(std::nullopt);
+
+    // Create a dialect alias for strings starting with "test_dialect_alias:"
+    if (strAttr.getValue().starts_with("test_dialect_alias:"))
+      return AliasResult::DialectAlias;
+
     if (!aliasName)
       return AliasResult::NoAlias;
 
@@ -200,6 +205,35 @@ struct TestOpAsmInterface : public OpAsmDialectInterface {
     return AliasResult::FinalAlias;
   }
 
+  LogicalResult printDialectAlias(DialectAsmPrinter &printer,
+                                  Attribute attr) const override {
+    if (StringAttr strAttr = dyn_cast<StringAttr>(attr)) {
+      // Drop "test_dialect_alias:" from the front of the string
+      StringRef value = strAttr.getValue();
+      value.consume_front("test_dialect_alias:");
+      printer << "test_string<\"" << value << "\">";
+      return success();
+    }
+    return failure();
+  }
+
+  LogicalResult parseDialectAlias(DialectAsmParser &parser, Attribute &attr,
+                                  Type type) const override {
+    return AsmParser::KeywordSwitch<LogicalResult>(parser)
+        // Alias !test.test_string<"..."> to StringAttr
+        .Case("test_string",
+              [&](llvm::StringRef, llvm::SMLoc) {
+                std::string str;
+                if (parser.parseLess() || parser.parseString(&str) ||
+                    parser.parseGreater())
+                  return success();
+                attr = parser.getBuilder().getStringAttr("test_dialect_alias:" +
+                                                         str);
+                return success();
+              })
+        .Default([&](StringRef keyword, SMLoc) { return failure(); });
+  }
+
   AliasResult getAlias(Type type, raw_ostream &os) const final {
     if (auto tupleType = dyn_cast<TupleType>(type)) {
       if (tupleType.size() > 0 &&
@@ -229,9 +263,47 @@ struct TestOpAsmInterface : public OpAsmDialectInterface {
       os << recAliasType.getName();
       return AliasResult::FinalAlias;
     }
+    // Create a dialect alias for tensor<3x!test.int<...>>
+    if (auto tensorTy = dyn_cast<TensorType>(type);
+        tensorTy && isa<TestIntegerType>(tensorTy.getElementType()) &&
+        tensorTy.hasRank()) {
+      ArrayRef<int64_t> shape = tensorTy.getShape();
+      if (shape.size() == 1 && shape[0] == 3)
+        return AliasResult::DialectAlias;
+    }
     return AliasResult::NoAlias;
   }
 
+  LogicalResult printDialectAlias(DialectAsmPrinter &printer,
+                                  Type type) const override {
+    if (auto tensorTy = dyn_cast<TensorType>(type);
+        tensorTy && isa<TestIntegerType>(tensorTy.getElementType()) &&
+        tensorTy.hasRank()) {
+      // Alias tensor<3x!test.int<...>> to !test.tensor_int3<!test.int<...>>
+      ArrayRef<int64_t> shape = tensorTy.getShape();
+      if (shape.size() == 1 && shape[0] == 3)
+        printer << "tensor_int3" << "<" << tensorTy.getElementType() << ">";
+      return success();
+    }
+    return failure();
+  }
+
+  LogicalResult parseDialectAlias(DialectAsmParser &parser,
+                                  Type &type) const override {
+    return AsmParser::KeywordSwitch<LogicalResult>(parser)
+        // Alias !test.tensor_int3<IntType> to tensor<3xIntType>
+        .Case("tensor_int3",
+              [&](llvm::StringRef, llvm::SMLoc) {
+                if (parser.parseLess() || parser.parseType(type) ||
+                    parser.parseGreater())
+                  type = nullptr;
+                if (isa<TestIntegerType>(type) || isa<IntegerType>(type))
+                  type = RankedTensorType::get({3}, type);
+                return success();
+              })
+        .Default([&](StringRef keyword, SMLoc) { return failure(); });
+  }
+
   //===------------------------------------------------------------------===//
   // Resources
   //===------------------------------------------------------------------===//
diff --git a/mlir/test/mlir-cpu-runner/simple.mlir b/mlir/test/mlir-cpu-runner/simple.mlir
index 38d9dcaf553714..dabc3196eaae59 100644
--- a/mlir/test/mlir-cpu-runner/simple.mlir
+++ b/mlir/test/mlir-cpu-runner/simple.mlir
@@ -44,9 +44,9 @@ llvm.func @foo() -> f32 {
   %1 = llvm.mlir.constant(0 : index) : i64
   %2 = llvm.mlir.constant(1.234000e+03 : f32) : f32
   %3 = llvm.getelementptr %0[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  llvm.store %2, %3 : f32, !llvm.ptr
+  ptr.store %2, %3 : f32, !llvm.ptr
   %4 = llvm.getelementptr %0[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
-  %5 = llvm.load %4 : !llvm.ptr -> f32
+  %5 = ptr.load %4 : !llvm.ptr -> f32
   llvm.call @deallocation(%0) : (!llvm.ptr) -> ()
   llvm.return %5 : f32
 }
diff --git a/mlir/test/mlir-cpu-runner/x86-varargs.mlir b/mlir/test/mlir-cpu-runner/x86-varargs.mlir
index de1b723f461e52..89b4a208095460 100644
--- a/mlir/test/mlir-cpu-runner/x86-varargs.mlir
+++ b/mlir/test/mlir-cpu-runner/x86-varargs.mlir
@@ -39,25 +39,25 @@ llvm.func @foo(%arg0: i32, ...) -> i32 {
   %13 = llvm.alloca %12 x !llvm.array<1 x struct<"struct.va_list", (i32, i32, ptr, ptr)>> {alignment = 8 : i64} : (i32) -> !llvm.ptr
   llvm.intr.vastart %13 : !llvm.ptr
   %15 = llvm.getelementptr %13[%11, %10, 0] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<1 x struct<"struct.va_list", (i32, i32, ptr, ptr)>>
-  %16 = llvm.load %15 : !llvm.ptr -> i32
+  %16 = ptr.load %15 : !llvm.ptr -> i32
   %17 = llvm.icmp "ult" %16, %8 : i32
   llvm.cond_br %17, ^bb1, ^bb2
 ^bb1:  // pred: ^bb0
   %18 = llvm.getelementptr %13[%7, %6, 3] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<1 x struct<"struct.va_list", (i32, i32, ptr, ptr)>>
-  %19 = llvm.load %18 : !llvm.ptr -> !llvm.ptr
+  %19 = ptr.load %18 : !llvm.ptr -> !llvm.ptr
   %20 = llvm.zext %16 : i32 to i64
   %21 = llvm.getelementptr %19[%20] : (!llvm.ptr, i64) -> !llvm.ptr, i8
   %22 = llvm.add %16, %4  : i32
-  llvm.store %22, %15 : i32, !llvm.ptr
+  ptr.store %22, %15 : i32, !llvm.ptr
   llvm.br ^bb3(%21 : !llvm.ptr)
 ^bb2:  // pred: ^bb0
   %23 = llvm.getelementptr %13[%3, %2, 2] : (!llvm.ptr, i64, i64) -> !llvm.ptr, !llvm.array<1 x struct<"struct.va_list", (i32, i32, ptr, ptr)>>
-  %24 = llvm.load %23 : !llvm.ptr -> !llvm.ptr
+  %24 = ptr.load %23 : !llvm.ptr -> !llvm.ptr
   %25 = llvm.getelementptr %24[%0] : (!llvm.ptr, i64) -> !llvm.ptr, i8
-  llvm.store %25, %23 : !llvm.ptr, !llvm.ptr
+  ptr.store %25, %23 : !llvm.ptr, !llvm.ptr
   llvm.br ^bb3(%24 : !llvm.ptr)
 ^bb3(%26: !llvm.ptr):  // 2 preds: ^bb1, ^bb2
-  %28 = llvm.load %26 : !llvm.ptr -> i32
+  %28 = ptr.load %26 : !llvm.ptr -> i32
   llvm.intr.vaend %13 : !llvm.ptr
   llvm.return %28 : i32
 }
diff --git a/mlir/unittests/ExecutionEngine/Invoke.cpp b/mlir/unittests/ExecutionEngine/Invoke.cpp
index ff87fc9fad805a..426ead32c51509 100644
--- a/mlir/unittests/ExecutionEngine/Invoke.cpp
+++ b/mlir/unittests/ExecutionEngine/Invoke.cpp
@@ -24,6 +24,7 @@
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
+#include "mlir/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Export.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/raw_ostream.h"
@@ -71,6 +72,7 @@ TEST(MLIRExecutionEngine, SKIP_WITHOUT_JIT(AddInteger)) {
   registerAllDialects(registry);
   registerBuiltinDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   MLIRContext context(registry);
   OwningOpRef<ModuleOp> module =
       parseSourceString<ModuleOp>(moduleStr, &context);
@@ -98,6 +100,7 @@ TEST(MLIRExecutionEngine, SKIP_WITHOUT_JIT(SubtractFloat)) {
   registerAllDialects(registry);
   registerBuiltinDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   MLIRContext context(registry);
   OwningOpRef<ModuleOp> module =
       parseSourceString<ModuleOp>(moduleStr, &context);
@@ -130,6 +133,7 @@ TEST(NativeMemRefJit, SKIP_WITHOUT_JIT(ZeroRankMemref)) {
   registerAllDialects(registry);
   registerBuiltinDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   MLIRContext context(registry);
   auto module = parseSourceString<ModuleOp>(moduleStr, &context);
   ASSERT_TRUE(!!module);
@@ -166,6 +170,7 @@ TEST(NativeMemRefJit, SKIP_WITHOUT_JIT(RankOneMemref)) {
   registerAllDialects(registry);
   registerBuiltinDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   MLIRContext context(registry);
   auto module = parseSourceString<ModuleOp>(moduleStr, &context);
   ASSERT_TRUE(!!module);
@@ -221,6 +226,7 @@ TEST(NativeMemRefJit, SKIP_WITHOUT_JIT(BasicMemref)) {
   registerAllDialects(registry);
   registerBuiltinDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   MLIRContext context(registry);
   OwningOpRef<ModuleOp> module =
       parseSourceString<ModuleOp>(moduleStr, &context);
@@ -271,6 +277,7 @@ TEST(NativeMemRefJit, MAYBE_JITCallback) {
   registerAllDialects(registry);
   registerBuiltinDialectTranslation(registry);
   registerLLVMDialectTranslation(registry);
+  registerPtrDialectTranslation(registry);
   MLIRContext context(registry);
   auto module = parseSourceString<ModuleOp>(moduleStr, &context);
   ASSERT_TRUE(!!module);



More information about the flang-commits mailing list