[Mlir-commits] [mlir] [mlir][SPIRV] Lower ptr dialect to PBA addresses (PR #206159)

Eddy Shieh llvmlistbot at llvm.org
Sun Jun 28 15:56:44 PDT 2026


https://github.com/edmundshieh updated https://github.com/llvm/llvm-project/pull/206159

>From 802af4c1b884b5a16e137c6d91f7e5823fb41e29 Mon Sep 17 00:00:00 2001
From: eshieh <eshieh at nvidia.com>
Date: Fri, 26 Jun 2026 14:25:17 -0400
Subject: [PATCH] [SPIRV] Lower ptr dialect to PBA addresses

Add a Ptr-to-SPIR-V conversion that represents ptr values as 64-bit
PhysicalStorageBuffer addresses. The conversion materializes typed
SPIR-V pointers at memory access sites so the ptr dialect can remain
pointee-type agnostic until loads and stores.

This covers the standalone conversion path. Vulkan runner ABI
integration is left for a follow-up because it depends on separate
runtime support for raw physical storage buffer arguments.

Tests:
- ninja -C build-pba mlir-opt
- llvm-lit -v mlir/test/Conversion/PtrToSPIRV/ptr-to-spirv.mlir

Assisted-by: OpenAI Codex
---
 mlir/include/mlir/Conversion/Passes.h         |   1 +
 mlir/include/mlir/Conversion/Passes.td        |  23 ++
 .../mlir/Conversion/PtrToSPIRV/PtrToSPIRV.h   |  37 +++
 mlir/lib/Conversion/CMakeLists.txt            |   1 +
 mlir/lib/Conversion/PtrToSPIRV/CMakeLists.txt |  17 +
 mlir/lib/Conversion/PtrToSPIRV/PtrToSPIRV.cpp | 297 ++++++++++++++++++
 .../Conversion/PtrToSPIRV/ptr-to-spirv.mlir   |  43 +++
 7 files changed, 419 insertions(+)
 create mode 100644 mlir/include/mlir/Conversion/PtrToSPIRV/PtrToSPIRV.h
 create mode 100644 mlir/lib/Conversion/PtrToSPIRV/CMakeLists.txt
 create mode 100644 mlir/lib/Conversion/PtrToSPIRV/PtrToSPIRV.cpp
 create mode 100644 mlir/test/Conversion/PtrToSPIRV/ptr-to-spirv.mlir

diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h
index 0ea248df3fee4..1394e03bc4f45 100644
--- a/mlir/include/mlir/Conversion/Passes.h
+++ b/mlir/include/mlir/Conversion/Passes.h
@@ -61,6 +61,7 @@
 #include "mlir/Conversion/OpenACCToSCF/ConvertOpenACCToSCF.h"
 #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
 #include "mlir/Conversion/PDLToPDLInterp/PDLToPDLInterp.h"
+#include "mlir/Conversion/PtrToSPIRV/PtrToSPIRV.h"
 #include "mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h"
 #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
 #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 340ff8fdf2a8a..9cc8765dce934 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -1134,6 +1134,29 @@ def ConvertPDLToPDLInterpPass : Pass<"convert-pdl-to-pdl-interp", "ModuleOp"> {
   let dependentDialects = ["pdl_interp::PDLInterpDialect"];
 }
 
+//===----------------------------------------------------------------------===//
+// PtrToSPIRV
+//===----------------------------------------------------------------------===//
+
+def ConvertPtrToSPIRVPass : Pass<"convert-ptr-to-spirv"> {
+  let summary = "Convert Ptr dialect operations to SPIR-V dialect operations";
+  let description = [{
+    This pass lowers supported Ptr dialect operations to SPIR-V operations.
+    Ptr dialect pointer types are converted to address integer types. Memory
+    operations materialize SPIR-V pointer types in the selected storage class.
+    The default storage class is PhysicalStorageBuffer, which enables physical
+    buffer address style pointer arithmetic.
+  }];
+
+  let dependentDialects = ["ptr::PtrDialect", "spirv::SPIRVDialect"];
+
+  let options = [
+    Option<"storageClass", "storage-class", "std::string",
+           /*default=*/"\"PhysicalStorageBuffer\"",
+           "SPIR-V storage class to use for materialized pointer accesses">
+  ];
+}
+
 //===----------------------------------------------------------------------===//
 // ReconcileUnrealizedCasts
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Conversion/PtrToSPIRV/PtrToSPIRV.h b/mlir/include/mlir/Conversion/PtrToSPIRV/PtrToSPIRV.h
new file mode 100644
index 0000000000000..2e7463b6061d5
--- /dev/null
+++ b/mlir/include/mlir/Conversion/PtrToSPIRV/PtrToSPIRV.h
@@ -0,0 +1,37 @@
+//===- PtrToSPIRV.h - Convert Ptr to SPIR-V 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CONVERSION_PTRTOSPIRV_PTRTOSPIRV_H
+#define MLIR_CONVERSION_PTRTOSPIRV_PTRTOSPIRV_H
+
+#include "mlir/Dialect/SPIRV/IR/SPIRVEnums.h"
+#include "mlir/Pass/Pass.h"
+#include <memory>
+
+namespace mlir {
+class RewritePatternSet;
+class SPIRVTypeConverter;
+
+#define GEN_PASS_DECL_CONVERTPTRTOSPIRVPASS
+#include "mlir/Conversion/Passes.h.inc"
+
+namespace ptr {
+/// Populates the type converter with conversions for ptr dialect types.
+void populatePtrToSPIRVTypeConversions(SPIRVTypeConverter &typeConverter);
+
+/// Appends patterns for lowering ptr dialect operations to SPIR-V operations.
+void populatePtrToSPIRVPatterns(const SPIRVTypeConverter &typeConverter,
+                                RewritePatternSet &patterns,
+                                spirv::StorageClass storageClass =
+                                    spirv::StorageClass::PhysicalStorageBuffer);
+
+std::unique_ptr<OperationPass<>> createConvertPtrToSPIRVPass();
+} // namespace ptr
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_PTRTOSPIRV_PTRTOSPIRV_H
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index 4fa5b9d582a4e..30cef4eabd086 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -55,6 +55,7 @@ add_subdirectory(OpenACCToSCF)
 add_subdirectory(OpenMPToLLVM)
 add_subdirectory(PDLToPDLInterp)
 add_subdirectory(PtrToLLVM)
+add_subdirectory(PtrToSPIRV)
 add_subdirectory(RaiseWasm)
 add_subdirectory(ReconcileUnrealizedCasts)
 add_subdirectory(SCFToControlFlow)
diff --git a/mlir/lib/Conversion/PtrToSPIRV/CMakeLists.txt b/mlir/lib/Conversion/PtrToSPIRV/CMakeLists.txt
new file mode 100644
index 0000000000000..29c6045401d4b
--- /dev/null
+++ b/mlir/lib/Conversion/PtrToSPIRV/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_mlir_conversion_library(MLIRPtrToSPIRV
+  PtrToSPIRV.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/PtrToSPIRV
+
+  DEPENDS
+  MLIRConversionPassIncGen
+
+  LINK_COMPONENTS
+  Core
+
+  LINK_LIBS PUBLIC
+  MLIRPtrDialect
+  MLIRSPIRVConversion
+  MLIRSPIRVDialect
+  )
diff --git a/mlir/lib/Conversion/PtrToSPIRV/PtrToSPIRV.cpp b/mlir/lib/Conversion/PtrToSPIRV/PtrToSPIRV.cpp
new file mode 100644
index 0000000000000..813bc6fb1a13e
--- /dev/null
+++ b/mlir/lib/Conversion/PtrToSPIRV/PtrToSPIRV.cpp
@@ -0,0 +1,297 @@
+//===- PtrToSPIRV.cpp - Ptr to SPIR-V dialect conversion -----------------===//
+//
+// 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/Conversion/PtrToSPIRV/PtrToSPIRV.h"
+
+#include "mlir/Dialect/Ptr/IR/PtrOps.h"
+#include "mlir/Dialect/Ptr/IR/PtrTypes.h"
+#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
+#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
+#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
+#include "mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h"
+#include "mlir/Transforms/DialectConversion.h"
+#include "llvm/ADT/StringRef.h"
+#include <limits>
+
+namespace mlir {
+#define GEN_PASS_DEF_CONVERTPTRTOSPIRVPASS
+#include "mlir/Conversion/Passes.h.inc"
+} // namespace mlir
+
+using namespace mlir;
+
+namespace {
+
+static FailureOr<Type> getAddressType(spirv::TargetEnvAttr targetAttr,
+                                      MLIRContext *context) {
+  spirv::AddressingModel addressingModel =
+      spirv::getAddressingModel(targetAttr, /*use64bitAddress=*/true);
+  if (addressingModel == spirv::AddressingModel::PhysicalStorageBuffer64)
+    return IntegerType::get(context, 64);
+
+  return failure();
+}
+
+static LogicalResult getMemoryAccessAttrs(std::optional<int64_t> alignment,
+                                          Builder &builder,
+                                          spirv::MemoryAccessAttr &accessAttr,
+                                          IntegerAttr &alignmentAttr) {
+  if (!alignment)
+    return success();
+  if (*alignment > std::numeric_limits<uint32_t>::max())
+    return failure();
+
+  accessAttr = spirv::MemoryAccessAttr::get(builder.getContext(),
+                                            spirv::MemoryAccess::Aligned);
+  alignmentAttr = builder.getI32IntegerAttr(*alignment);
+  return success();
+}
+
+static LogicalResult checkSupportedPtrLoad(ptr::LoadOp op,
+                                           PatternRewriter &rewriter) {
+  if (op.getVolatile_() || op.getNontemporal() || op.getInvariant() ||
+      op.getInvariantGroup())
+    return rewriter.notifyMatchFailure(
+        op, "unsupported ptr.load memory operand for SPIR-V lowering");
+  if (op.getOrdering() != ptr::AtomicOrdering::not_atomic)
+    return rewriter.notifyMatchFailure(
+        op, "unsupported atomic ptr.load for SPIR-V lowering");
+  return success();
+}
+
+static LogicalResult checkSupportedPtrStore(ptr::StoreOp op,
+                                            PatternRewriter &rewriter) {
+  if (op.getVolatile_() || op.getNontemporal() || op.getInvariantGroup())
+    return rewriter.notifyMatchFailure(
+        op, "unsupported ptr.store memory operand for SPIR-V lowering");
+  if (op.getOrdering() != ptr::AtomicOrdering::not_atomic)
+    return rewriter.notifyMatchFailure(
+        op, "unsupported atomic ptr.store for SPIR-V lowering");
+  return success();
+}
+
+static FailureOr<Value>
+castAddressToPointeeType(Operation *op, Value address, Type pointeeType,
+                         spirv::StorageClass storageClass, Location loc,
+                         PatternRewriter &rewriter) {
+  if (!isa<IntegerType>(address.getType())) {
+    (void)rewriter.notifyMatchFailure(op, "expected integer address operand");
+    return failure();
+  }
+  if (storageClass != spirv::StorageClass::PhysicalStorageBuffer) {
+    (void)rewriter.notifyMatchFailure(
+        op, "only PhysicalStorageBuffer pointer materialization is supported");
+    return failure();
+  }
+
+  auto typedPtrType = spirv::PointerType::get(pointeeType, storageClass);
+  return spirv::ConvertUToPtrOp::create(rewriter, loc, typedPtrType, address)
+      .getResult();
+}
+
+struct PtrTypeOffsetOpConverter final
+    : public OpConversionPattern<ptr::TypeOffsetOp> {
+  using Base::Base;
+
+  LogicalResult
+  matchAndRewrite(ptr::TypeOffsetOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    Type convertedType = getTypeConverter()->convertType(op.getType());
+    if (!convertedType)
+      return rewriter.notifyMatchFailure(op, "result type is not convertible");
+
+    llvm::TypeSize typeSize = op.getTypeSize();
+    if (typeSize.isScalable())
+      return rewriter.notifyMatchFailure(op, "scalable type size");
+
+    auto intType = dyn_cast<IntegerType>(convertedType);
+    if (!intType)
+      return rewriter.notifyMatchFailure(
+          op, "converted result type is not an integer");
+
+    auto attr = rewriter.getIntegerAttr(intType, typeSize.getFixedValue());
+    rewriter.replaceOpWithNewOp<spirv::ConstantOp>(op, intType, attr);
+    return success();
+  }
+};
+
+struct PtrAddOpConverter final : public OpConversionPattern<ptr::PtrAddOp> {
+  using Base::Base;
+
+  LogicalResult
+  matchAndRewrite(ptr::PtrAddOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    Type convertedType = getTypeConverter()->convertType(op.getType());
+    if (!convertedType)
+      return rewriter.notifyMatchFailure(op, "result type is not convertible");
+
+    auto addressType = dyn_cast<IntegerType>(convertedType);
+    if (!addressType)
+      return rewriter.notifyMatchFailure(
+          op, "converted result type is not an integer address");
+    if (adaptor.getBase().getType() != addressType)
+      return rewriter.notifyMatchFailure(
+          op, "converted base pointer type does not match result type");
+
+    Location loc = op.getLoc();
+    Value offset = adaptor.getOffset();
+    if (!isa<IntegerType>(offset.getType()))
+      return rewriter.notifyMatchFailure(op, "offset is not an integer");
+    if (offset.getType() != addressType)
+      offset = spirv::UConvertOp::create(rewriter, loc, addressType, offset);
+
+    rewriter.replaceOpWithNewOp<spirv::IAddOp>(op, addressType,
+                                               adaptor.getBase(), offset);
+    return success();
+  }
+};
+
+struct PtrLoadOpConverter final : public OpConversionPattern<ptr::LoadOp> {
+  PtrLoadOpConverter(const SPIRVTypeConverter &typeConverter,
+                     MLIRContext *context, spirv::StorageClass storageClass)
+      : OpConversionPattern<ptr::LoadOp>(typeConverter, context),
+        storageClass(storageClass) {}
+
+  LogicalResult
+  matchAndRewrite(ptr::LoadOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    if (failed(checkSupportedPtrLoad(op, rewriter)))
+      return failure();
+
+    Type convertedType = getTypeConverter()->convertType(op.getType());
+    if (!convertedType)
+      return rewriter.notifyMatchFailure(op, "result type is not convertible");
+
+    FailureOr<Value> ptr =
+        castAddressToPointeeType(op, adaptor.getPtr(), convertedType,
+                                 storageClass, op.getLoc(), rewriter);
+    if (failed(ptr))
+      return failure();
+
+    spirv::MemoryAccessAttr accessAttr;
+    IntegerAttr alignmentAttr;
+    if (failed(getMemoryAccessAttrs(op.getAlignment(), rewriter, accessAttr,
+                                    alignmentAttr)))
+      return rewriter.notifyMatchFailure(op, "invalid alignment requirement");
+
+    rewriter.replaceOpWithNewOp<spirv::LoadOp>(op, convertedType, *ptr,
+                                               accessAttr, alignmentAttr);
+    return success();
+  }
+
+private:
+  spirv::StorageClass storageClass;
+};
+
+struct PtrStoreOpConverter final : public OpConversionPattern<ptr::StoreOp> {
+  PtrStoreOpConverter(const SPIRVTypeConverter &typeConverter,
+                      MLIRContext *context, spirv::StorageClass storageClass)
+      : OpConversionPattern<ptr::StoreOp>(typeConverter, context),
+        storageClass(storageClass) {}
+
+  LogicalResult
+  matchAndRewrite(ptr::StoreOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    if (failed(checkSupportedPtrStore(op, rewriter)))
+      return failure();
+
+    Type valueType = adaptor.getValue().getType();
+    FailureOr<Value> ptr = castAddressToPointeeType(
+        op, adaptor.getPtr(), valueType, storageClass, op.getLoc(), rewriter);
+    if (failed(ptr))
+      return failure();
+
+    spirv::MemoryAccessAttr accessAttr;
+    IntegerAttr alignmentAttr;
+    if (failed(getMemoryAccessAttrs(op.getAlignment(), rewriter, accessAttr,
+                                    alignmentAttr)))
+      return rewriter.notifyMatchFailure(op, "invalid alignment requirement");
+
+    rewriter.replaceOpWithNewOp<spirv::StoreOp>(op, *ptr, adaptor.getValue(),
+                                                accessAttr, alignmentAttr);
+    return success();
+  }
+
+private:
+  spirv::StorageClass storageClass;
+};
+
+static FailureOr<spirv::StorageClass> parseStorageClass(StringRef storageClass,
+                                                        Operation *op) {
+  std::optional<spirv::StorageClass> parsed =
+      spirv::symbolizeStorageClass(storageClass);
+  if (!parsed)
+    return op->emitError() << "invalid SPIR-V storage class: " << storageClass;
+  return *parsed;
+}
+
+struct ConvertPtrToSPIRVPass final
+    : public impl::ConvertPtrToSPIRVPassBase<ConvertPtrToSPIRVPass> {
+  using Base::Base;
+
+  void runOnOperation() override {
+    Operation *op = getOperation();
+    spirv::TargetEnvAttr targetAttr = spirv::lookupTargetEnvOrDefault(op);
+    std::unique_ptr<SPIRVConversionTarget> target =
+        SPIRVConversionTarget::get(targetAttr);
+    SPIRVTypeConverter typeConverter(targetAttr);
+
+    FailureOr<spirv::StorageClass> storageClass =
+        parseStorageClass(this->storageClass, op);
+    if (failed(storageClass))
+      return signalPassFailure();
+    if (*storageClass != spirv::StorageClass::PhysicalStorageBuffer) {
+      op->emitError()
+          << "ptr-to-SPIR-V currently only supports PhysicalStorageBuffer";
+      return signalPassFailure();
+    }
+    if (failed(getAddressType(targetAttr, op->getContext()))) {
+      op->emitError()
+          << "ptr-to-SPIR-V requires PhysicalStorageBuffer64 addressing";
+      return signalPassFailure();
+    }
+
+    ptr::populatePtrToSPIRVTypeConversions(typeConverter);
+
+    target->addLegalOp<UnrealizedConversionCastOp>();
+    target->addIllegalDialect<ptr::PtrDialect>();
+
+    RewritePatternSet patterns(&getContext());
+    ptr::populatePtrToSPIRVPatterns(typeConverter, patterns, *storageClass);
+
+    if (failed(applyPartialConversion(op, *target, std::move(patterns))))
+      signalPassFailure();
+  }
+};
+
+} // namespace
+
+void mlir::ptr::populatePtrToSPIRVTypeConversions(
+    SPIRVTypeConverter &typeConverter) {
+  spirv::TargetEnvAttr targetAttr = typeConverter.getTargetEnv().getAttr();
+  typeConverter.addConversion([targetAttr](
+                                  ptr::PtrType type) -> std::optional<Type> {
+    FailureOr<Type> addressType = getAddressType(targetAttr, type.getContext());
+    if (failed(addressType))
+      return std::nullopt;
+    return *addressType;
+  });
+}
+
+void mlir::ptr::populatePtrToSPIRVPatterns(
+    const SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns,
+    spirv::StorageClass storageClass) {
+  patterns.add<PtrAddOpConverter, PtrTypeOffsetOpConverter>(
+      typeConverter, patterns.getContext());
+  patterns.add<PtrLoadOpConverter, PtrStoreOpConverter>(
+      typeConverter, patterns.getContext(), storageClass);
+}
+
+std::unique_ptr<OperationPass<>> mlir::ptr::createConvertPtrToSPIRVPass() {
+  return std::make_unique<ConvertPtrToSPIRVPass>();
+}
diff --git a/mlir/test/Conversion/PtrToSPIRV/ptr-to-spirv.mlir b/mlir/test/Conversion/PtrToSPIRV/ptr-to-spirv.mlir
new file mode 100644
index 0000000000000..6863577ce7264
--- /dev/null
+++ b/mlir/test/Conversion/PtrToSPIRV/ptr-to-spirv.mlir
@@ -0,0 +1,43 @@
+// RUN: mlir-opt %s -split-input-file -convert-ptr-to-spirv | FileCheck %s
+
+!ptr = !ptr.ptr<#ptr.generic_space>
+
+module attributes {
+  spirv.target_env = #spirv.target_env<
+    #spirv.vce<v1.5, [Shader, Int64, PhysicalStorageBufferAddresses],
+               [SPV_KHR_physical_storage_buffer]>,
+    #spirv.resource_limits<>>
+} {
+
+// CHECK-LABEL: func.func @ptr_add_load_store
+// CHECK-SAME:    %[[PTR:.*]]: !ptr.ptr<#ptr.generic_space>
+// CHECK-SAME:    %[[OFFSET:.*]]: index
+// CHECK-SAME:    %[[VALUE:.*]]: f32
+func.func @ptr_add_load_store(%ptr: !ptr, %offset: index, %value: f32) -> f32 {
+  // CHECK-DAG: %[[ADDR:.*]] = builtin.unrealized_conversion_cast %[[PTR]] : !ptr.ptr<#ptr.generic_space> to i64
+  // CHECK-DAG: %[[SPIRV_OFFSET:.*]] = builtin.unrealized_conversion_cast %[[OFFSET]] : index to i32
+  // CHECK: %[[OFFSET64:.*]] = spirv.UConvert %[[SPIRV_OFFSET]] : i32 to i64
+  // CHECK: %[[ELEM_ADDR:.*]] = spirv.IAdd %[[ADDR]], %[[OFFSET64]] : i64
+  %elem = ptr.ptr_add %ptr, %offset : !ptr, index
+
+  // CHECK: %[[LOAD_PTR:.*]] = spirv.ConvertUToPtr %[[ELEM_ADDR]] : i64 to !spirv.ptr<f32, PhysicalStorageBuffer>
+  // CHECK: %[[LOADED:.*]] = spirv.Load "PhysicalStorageBuffer" %[[LOAD_PTR]] ["Aligned", 4] : f32
+  %loaded = ptr.load %elem alignment = 4 : !ptr -> f32
+
+  // CHECK: %[[STORE_PTR:.*]] = spirv.ConvertUToPtr %[[ELEM_ADDR]] : i64 to !spirv.ptr<f32, PhysicalStorageBuffer>
+  // CHECK: spirv.Store "PhysicalStorageBuffer" %[[STORE_PTR]], %[[VALUE]] ["Aligned", 4] : f32
+  ptr.store %value, %elem alignment = 4 : f32, !ptr
+
+  // CHECK: return %[[LOADED]] : f32
+  return %loaded : f32
+}
+
+// CHECK-LABEL: func.func @type_offset
+func.func @type_offset() -> index {
+  // CHECK: %[[SIZE:.*]] = spirv.Constant 4 : i32
+  %size = ptr.type_offset f32 : index
+  // CHECK: builtin.unrealized_conversion_cast %[[SIZE]] : i32 to index
+  return %size : index
+}
+
+} // module



More information about the Mlir-commits mailing list