[Mlir-commits] [mlir] [mlir][LLVM] Add support for `ptrtoaddr` (PR #185104)
Markus Böck
llvmlistbot at llvm.org
Sat Mar 7 04:47:42 PST 2026
https://github.com/zero9178 updated https://github.com/llvm/llvm-project/pull/185104
>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 1/5] [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
>From 07788ac712f452d5f20ae320cfdbc3b8874003ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Markus=20B=C3=B6ck?= <markus.boeck02 at gmail.com>
Date: Sat, 7 Mar 2026 13:21:23 +0100
Subject: [PATCH 2/5] address review comments
---
mlir/test/Dialect/LLVMIR/roundtrip.mlir | 2 ++
mlir/test/Target/LLVMIR/Import/instructions.ll | 5 ++++-
mlir/test/Target/LLVMIR/llvmir.mlir | 13 +++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 1b3e0750a9aab..dc9c80b70790b 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -247,6 +247,8 @@ func.func @ops(%arg0: i32, %arg1: f32,
%25 = llvm.inttoptr %arg0 : i32 to !llvm.ptr
%26 = llvm.ptrtoint %25 : !llvm.ptr to i32
%a26 = llvm.ptrtoaddr %25 : !llvm.ptr to i64
+ %vp = llvm.mlir.poison : vector<3 x !llvm.ptr>
+ %va26 = llvm.ptrtoaddr %vp : vector<3 x !llvm.ptr> to vector<3 x 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 a67ab1c9e9c56..6cd8cf9d02c8c 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -181,15 +181,18 @@ define void @integer_extension_and_truncation(i32 %arg1) {
; CHECK-LABEL: @pointer_casts
; CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]
; CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]
-define ptr @pointer_casts(ptr %arg1, i64 %arg2) {
+; CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]
+define ptr @pointer_casts(ptr %arg1, i64 %arg2, <3 x ptr> %arg3) {
; 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.ptrtoaddr %[[ARG3]] : vector<3x!llvm.ptr> to vector<3xi64>
; 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
+ %vp = ptrtoaddr <3 x ptr> %arg3 to <3 x 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 a0d32e270caaa..f1e9e7bff8bce 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -1283,15 +1283,24 @@ llvm.func @intpointerconversion(%arg0 : i32) -> i32 {
llvm.return %2 : i32
}
-// CHECK-LABEL: @addrpointerconversion
+// CHECK-LABEL: @addrpointerconversion_scalar
// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]
-llvm.func @addrpointerconversion(%arg0 : !llvm.ptr) -> i64 {
+llvm.func @addrpointerconversion_scalar(%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
}
+// CHECK-LABEL: @addrpointerconversion_vector
+// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]
+llvm.func @addrpointerconversion_vector(%arg0 : vector<3x!llvm.ptr>) -> vector<3x i64> {
+ // CHECK: %[[PTR:.*]] = ptrtoaddr <3 x ptr> %[[ARG0]] to <3 x i64>
+ // CHECK-NEXT: ret <3 x i64> %[[PTR]]
+ %1 = llvm.ptrtoaddr %arg0 : vector<3x!llvm.ptr> to vector<3x i64>
+ llvm.return %1 : vector<3x i64>
+}
+
llvm.func @fpconversion(%arg0 : i32) -> i32 {
// CHECK: %2 = sitofp i32 %0 to float
// CHECK-NEXT: %3 = fptosi float %2 to i32
>From 3572b3500a0aa0dd84f9ce3d39fa7c67049567ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Markus=20B=C3=B6ck?= <markus.boeck02 at gmail.com>
Date: Sat, 7 Mar 2026 13:21:43 +0100
Subject: [PATCH 3/5] add description
---
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 29 +++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 1a4e79899c923..50ebb0845d196 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -635,6 +635,35 @@ def LLVM_PtrToAddrOp : LLVM_CastOp<"ptrtoaddr", "PtrToAddr",
LLVM_ScalarOrVectorOf<AnySignlessInteger>> {
let llvmBuilder = "$res = builder.CreatePtrToAddr($arg);";
let hasVerifier = 1;
+
+ let description = [{
+ Operation mirroring LLVM's `ptrtoaddr` operation.
+
+ This operation casts a pointer (or a vector of pointers) to an integer
+ (or a vector of integers).
+ The integer type used as the result type is required to be equal in width
+ to the pointer type as specified in the data layout.
+
+ Use the `llvm-target-to-data-layout` pass to derive an MLIR datalayout from
+ an LLVM datalayout.
+
+ Examples:
+ ```
+ llvm.func @default_64_bit_ptrtoaddr(%arg0 : !llvm.ptr) -> i64 {
+ %0 = llvm.ptrtoaddr %arg0 : !llvm.ptr to i64
+ llvm.return i64
+ }
+
+ module attributes { dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<!llvm.ptr, dense<[/*size=*/32, 32, 64]> : vector<3xi64>>
+ >} {
+ llvm.func @datalayout_32_bit(%arg0 : !llvm.ptr) -> i32 {
+ %0 = llvm.ptrtoaddr %arg0 : !llvm.ptr to i32
+ llvm.return %0 : i32
+ }
+ }
+ ```
+ }];
}
def LLVM_SExtOp : LLVM_CastOp<"sext", "SExt",
>From 17eafe6b1e0d50091c091b486412164792c70542 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Markus=20B=C3=B6ck?= <markus.boeck02 at gmail.com>
Date: Sat, 7 Mar 2026 13:30:37 +0100
Subject: [PATCH 4/5] add description
---
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 50ebb0845d196..490852d4e4dfd 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -640,10 +640,15 @@ def LLVM_PtrToAddrOp : LLVM_CastOp<"ptrtoaddr", "PtrToAddr",
Operation mirroring LLVM's `ptrtoaddr` operation.
This operation casts a pointer (or a vector of pointers) to an integer
- (or a vector of integers).
+ (or a vector of integers) without capturing the provenance of the pointer.
+ Therefore, an integer returned or derived from `llvm.ptrtoaddr` does not
+ create a legal-to-access pointer when used in `llvm.inttoptr`.
+ Code that only care about the address value of a pointer
+ (e.g. pointer subtraction) should prefer `llvm.ptrtoaddr` over
+ `llvm.ptrtoint`.
+
The integer type used as the result type is required to be equal in width
to the pointer type as specified in the data layout.
-
Use the `llvm-target-to-data-layout` pass to derive an MLIR datalayout from
an LLVM datalayout.
>From f2055e3127960981fbd967ce2b3c46edbc56b7b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Markus=20B=C3=B6ck?= <markus.boeck02 at gmail.com>
Date: Sat, 7 Mar 2026 13:30:58 +0100
Subject: [PATCH 5/5] use type index bitwidth
---
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 38ad55db916ef..e6e9736ef5dfd 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3860,10 +3860,11 @@ LogicalResult LLVM::PtrToAddrOp::verify() {
auto integerType = cast<IntegerType>(extractVectorElementType(getType()));
auto dataLayout = DataLayout::closest(*this);
- unsigned width = dataLayout.getTypeSizeInBits(pointerType);
+ std::optional<unsigned> width = dataLayout.getTypeIndexBitwidth(pointerType);
+ assert(width && "pointers always return an index bitwidth");
if (width != integerType.getWidth())
return emitOpError("bit-width of integer result type ")
- << integerType << " must match the pointer bitwidth (" << width
+ << integerType << " must match the pointer bitwidth (" << *width
<< ") specified in the datalayout";
return success();
More information about the Mlir-commits
mailing list