[Mlir-commits] [mlir] [mlir][LLVM] Add support for `ptrtoaddr` (PR #185104)
Markus Böck
llvmlistbot at llvm.org
Fri Mar 6 12:47:36 PST 2026
https://github.com/zero9178 created https://github.com/llvm/llvm-project/pull/185104
The `ptrtoaddr` op is akin to `ptrtoint` with some important differences:
* It does not capture the provenance of the pointer, meaning a pointer does not escape and subsequent `inttoptr` don't make a legal pointer. LLVM can then assume the pointer never escaped, which helps alias analysis.
* It does not support arbitrary integer types, but only exactly the integer type that is equal in width to the pointer type as specified by the data layout.
This PR adds the op the MLIR dialect and adds the corresponding verification for the datalayout property.
>From 0b6cd1a2a718c6514b938cdb3bad11141e321cad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Markus=20B=C3=B6ck?= <markus.boeck02 at gmail.com>
Date: Fri, 6 Mar 2026 21:45:37 +0100
Subject: [PATCH] [mlir][LLVM] Add support for `ptrtoaddr`
The `ptrtoaddr` op is akin to `ptrtoint` with some important differences:
* It does not capture the provenance of the pointer, meaning a pointer does not escape and subsequent `inttoptr` don't make a legal pointer. LLVM can then assume the pointer never escaped, which helps alias analysis.
* It does not support arbitrary integer types, but only exactly the integer type that is equal in width to the pointer type as specified by the data layout.
This PR adds the op the MLIR dialect and adds the corresponding verification for the datalayout property.
---
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 8 ++++++++
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 15 +++++++++++++++
mlir/test/Dialect/LLVMIR/invalid.mlir | 18 ++++++++++++++++++
mlir/test/Dialect/LLVMIR/roundtrip.mlir | 2 ++
mlir/test/Target/LLVMIR/Import/instructions.ll | 2 ++
mlir/test/Target/LLVMIR/llvmir.mlir | 9 +++++++++
6 files changed, 54 insertions(+)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 0957f751bf44b..1a4e79899c923 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -629,6 +629,14 @@ def LLVM_IntToPtrOp : LLVM_DereferenceableCastOp<"inttoptr", "IntToPtr",
def LLVM_PtrToIntOp : LLVM_CastOp<"ptrtoint", "PtrToInt",
LLVM_ScalarOrVectorOf<LLVM_AnyPointer>,
LLVM_ScalarOrVectorOf<AnySignlessInteger>>;
+
+def LLVM_PtrToAddrOp : LLVM_CastOp<"ptrtoaddr", "PtrToAddr",
+ LLVM_ScalarOrVectorOf<LLVM_AnyPointer>,
+ LLVM_ScalarOrVectorOf<AnySignlessInteger>> {
+ let llvmBuilder = "$res = builder.CreatePtrToAddr($arg);";
+ let hasVerifier = 1;
+}
+
def LLVM_SExtOp : LLVM_CastOp<"sext", "SExt",
LLVM_ScalarOrVectorOf<AnySignlessInteger>,
LLVM_ScalarOrVectorOf<AnySignlessInteger>> {
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index d960201e2b3d0..38ad55db916ef 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3854,6 +3854,21 @@ LogicalResult LLVM::BitcastOp::verify() {
return success();
}
+LogicalResult LLVM::PtrToAddrOp::verify() {
+ auto pointerType =
+ cast<LLVM::LLVMPointerType>(extractVectorElementType(getArg().getType()));
+ auto integerType = cast<IntegerType>(extractVectorElementType(getType()));
+
+ auto dataLayout = DataLayout::closest(*this);
+ unsigned width = dataLayout.getTypeSizeInBits(pointerType);
+ if (width != integerType.getWidth())
+ return emitOpError("bit-width of integer result type ")
+ << integerType << " must match the pointer bitwidth (" << width
+ << ") specified in the datalayout";
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// Folder for LLVM::AddrSpaceCastOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 5068ddc42e1e5..7f3eb20ce00fa 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -2072,3 +2072,21 @@ module {
// expected-error at +1 {{'llvm.blockaddress' op expects an existing block label target in the referenced function}}
%0 = llvm.blockaddress <function = @missing_func, tag = <id = 1>> : !llvm.ptr
}
+
+// -----
+
+llvm.func @too_narrow_ptr_to_addr(%arg0 : !llvm.ptr) -> () {
+ // expected-error at +1 {{'llvm.ptrtoaddr' op bit-width of integer result type 'i32' must match the pointer bitwidth (64) specified in the datalayout}}
+ %0 = llvm.ptrtoaddr %arg0 : !llvm.ptr to i32
+}
+
+// -----
+
+module attributes { dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<!llvm.ptr, dense<[32, 32, 64]> : vector<3xi64>>
+>} {
+ llvm.func @too_narrow_ptr_to_addr(%arg0 : !llvm.ptr) -> () {
+ // expected-error at +1 {{'llvm.ptrtoaddr' op bit-width of integer result type 'i64' must match the pointer bitwidth (32) specified in the datalayout}}
+ %0 = llvm.ptrtoaddr %arg0 : !llvm.ptr to i64
+ }
+}
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index c680d0d98ac5f..1b3e0750a9aab 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -243,8 +243,10 @@ func.func @ops(%arg0: i32, %arg1: f32,
//
// CHECK: %[[PTR:.*]] = llvm.inttoptr %[[I32]] : i32 to !llvm.ptr
// CHECK: %{{.*}} = llvm.ptrtoint %[[PTR]] : !llvm.ptr to i32
+// CHECK: %{{.*}} = llvm.ptrtoaddr %[[PTR]] : !llvm.ptr to i64
%25 = llvm.inttoptr %arg0 : i32 to !llvm.ptr
%26 = llvm.ptrtoint %25 : !llvm.ptr to i32
+ %a26 = llvm.ptrtoaddr %25 : !llvm.ptr to i64
// Extended and Quad floating point
//
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 22a274049ecf4..a67ab1c9e9c56 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -184,10 +184,12 @@ define void @integer_extension_and_truncation(i32 %arg1) {
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.ptrtoaddr %[[ARG1]] : !llvm.ptr to i64
; CHECK: llvm.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
+ %p = ptrtoaddr ptr %arg1 to i64
%2 = inttoptr i64 %arg2 to ptr
%3 = bitcast ptr %arg1 to ptr
ret ptr null
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 4fb5285584a89..a0d32e270caaa 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -1283,6 +1283,15 @@ llvm.func @intpointerconversion(%arg0 : i32) -> i32 {
llvm.return %2 : i32
}
+// CHECK-LABEL: @addrpointerconversion
+// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]
+llvm.func @addrpointerconversion(%arg0 : !llvm.ptr) -> i64 {
+ // CHECK: %[[PTR:.*]] = ptrtoaddr ptr %[[ARG0]] to i64
+ // CHECK-NEXT: ret i64 %[[PTR]]
+ %1 = llvm.ptrtoaddr %arg0 : !llvm.ptr to i64
+ llvm.return %1 : i64
+}
+
llvm.func @fpconversion(%arg0 : i32) -> i32 {
// CHECK: %2 = sitofp i32 %0 to float
// CHECK-NEXT: %3 = fptosi float %2 to i32
More information about the Mlir-commits
mailing list