[llvm-branch-commits] [llvm] [IR] Fold `bitcast` pairs through bytes with `ptrtoaddr` (PR #229107)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Oct 5 07:57:52 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-ir
Author: Pedro Lobo (pedroclobo)
<details>
<summary>Changes</summary>
Fold `bitcast` pairs through bytes with `ptrtoaddr`.
Folds:
- A pointer-to-byte `bitcast`, followed by a `bitcast` to an integer becomes `ptrtoaddr`, as both return the address without exposing provenance.
- A byte-to-pointer `bitcast` and `ptrtoaddr` becomes a `bitcast`.
```diff
-%b = bitcast ptr %p to b64
-%x = bitcast b64 %b to i64
+%x = ptrtoaddr ptr %p to i64
-%q = bitcast b64 %b to ptr
-%y = ptrtoaddr ptr %q to i64
+%y = bitcast b64 %b to i64
```
---
Full diff: https://github.com/llvm/llvm-project/pull/229107.diff
4 Files Affected:
- (modified) llvm/lib/IR/Instructions.cpp (+20-4)
- (modified) llvm/test/Transforms/GVN/pr207532.ll (+1-1)
- (modified) llvm/test/Transforms/InstCombine/byte-cast-pairs.ll (+98-12)
- (modified) llvm/test/Transforms/InstSimplify/byte-cast-pairs.ll (+3-3)
``````````diff
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 402540349af0653..dd051d51b4db8d3 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -3143,11 +3143,18 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
// FIXME: this state can be merged with (2), but the following assert
// is useful to check the correcteness of the sequence due to semantic
// change of bitcast.
- // ptrtoint/ptrtoaddr can only fold through a bitcast if the source was
- // already a pointer. A byte-to-pointer bitcast must stay as a separate
- // bitcast.
- if (!SrcTy->isPtrOrPtrVectorTy())
+ // bitcast, ptrtoaddr -> bitcast, if SrcTy is a byte and the address is
+ // the whole pointer
+ // ptrtoint can only fold through a bitcast if the source was already a
+ // pointer, as ptrtoint exposes the provenance.
+ if (!SrcTy->isPtrOrPtrVectorTy()) {
+ // ptrtoaddr yields the address width, so the sizes only match if the
+ // address is the whole pointer.
+ if (secondOp == Instruction::PtrToAddr &&
+ SrcTy->getPrimitiveSizeInBits() == DstTy->getPrimitiveSizeInBits())
+ return Instruction::BitCast;
return 0;
+ }
assert(
SrcTy->isPtrOrPtrVectorTy() &&
MidTy->isPtrOrPtrVectorTy() &&
@@ -3163,6 +3170,8 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
// bitcast, bitcast -> bitcast, if neither SrcTy nor DstTy is a pointer,
// both are pointers in the same addrspace,
// or one is a pointer and the other a byte
+ // bitcast, bitcast -> ptrtoaddr, if a pointer goes through a byte to an
+ // integer of the address width
// A pair of bitcasts through a byte must stay separate otherwise.
if (!SrcTy->isPtrOrPtrVectorTy() && !DstTy->isPtrOrPtrVectorTy())
return Instruction::BitCast;
@@ -3171,6 +3180,13 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
return Instruction::BitCast;
if (SrcTy->isByteOrByteVectorTy() || DstTy->isByteOrByteVectorTy())
return Instruction::BitCast;
+ if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isIntOrIntVectorTy() &&
+ SrcTy->isVectorTy() == DstTy->isVectorTy() && DL) {
+ unsigned AddrSize = DL->getAddressSizeInBits(SrcTy);
+ if (AddrSize == DL->getPointerTypeSizeInBits(SrcTy) &&
+ AddrSize == DstTy->getScalarSizeInBits())
+ return Instruction::PtrToAddr;
+ }
return 0;
case 99:
// Cast combination can't happen (error in input). This is for all cases
diff --git a/llvm/test/Transforms/GVN/pr207532.ll b/llvm/test/Transforms/GVN/pr207532.ll
index f1db0fdff9a2f5f..122a6cf47def6ab 100644
--- a/llvm/test/Transforms/GVN/pr207532.ll
+++ b/llvm/test/Transforms/GVN/pr207532.ll
@@ -9,7 +9,7 @@ define ptr @forward_byte_store_to_ptr_load() {
; CHECK-LABEL: define ptr @forward_byte_store_to_ptr_load() {
; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8
; CHECK-NEXT: store b64 bitcast (ptr @g to b64), ptr [[A]], align 8
-; CHECK-NEXT: ret ptr inttoptr (i64 bitcast (b64 bitcast (ptr @g to b64) to i64) to ptr)
+; CHECK-NEXT: ret ptr inttoptr (i64 ptrtoaddr (ptr @g to i64) to ptr)
;
%a = alloca ptr, align 8
store b64 bitcast (ptr @g to b64), ptr %a, align 8
diff --git a/llvm/test/Transforms/InstCombine/byte-cast-pairs.ll b/llvm/test/Transforms/InstCombine/byte-cast-pairs.ll
index 64b76b927080945..3531b5b822877e7 100644
--- a/llvm/test/Transforms/InstCombine/byte-cast-pairs.ll
+++ b/llvm/test/Transforms/InstCombine/byte-cast-pairs.ll
@@ -1,11 +1,12 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-define i64 @neg_ptr_to_byte_to_int(ptr %p) {
-; CHECK-LABEL: define i64 @neg_ptr_to_byte_to_int(
+target datalayout = "p1:128:128:128:64"
+
+define i64 @ptr_to_byte_to_int(ptr %p) {
+; CHECK-LABEL: define i64 @ptr_to_byte_to_int(
; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT: [[B:%.*]] = bitcast ptr [[P]] to b64
-; CHECK-NEXT: [[X:%.*]] = bitcast b64 [[B]] to i64
+; CHECK-NEXT: [[X:%.*]] = ptrtoaddr ptr [[P]] to i64
; CHECK-NEXT: ret i64 [[X]]
;
%b = bitcast ptr %p to b64
@@ -25,11 +26,10 @@ define ptr @neg_int_to_byte_to_ptr(i64 %i) {
ret ptr %x
}
-define <2 x i64> @neg_ptr_to_byte_to_int_vec(<2 x ptr> %p) {
-; CHECK-LABEL: define <2 x i64> @neg_ptr_to_byte_to_int_vec(
+define <2 x i64> @ptr_to_byte_to_int_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x i64> @ptr_to_byte_to_int_vec(
; CHECK-SAME: <2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT: [[B:%.*]] = bitcast <2 x ptr> [[P]] to <2 x b64>
-; CHECK-NEXT: [[X:%.*]] = bitcast <2 x b64> [[B]] to <2 x i64>
+; CHECK-NEXT: [[X:%.*]] = ptrtoaddr <2 x ptr> [[P]] to <2 x i64>
; CHECK-NEXT: ret <2 x i64> [[X]]
;
%b = bitcast <2 x ptr> %p to <2 x b64>
@@ -37,6 +37,68 @@ define <2 x i64> @neg_ptr_to_byte_to_int_vec(<2 x ptr> %p) {
ret <2 x i64> %x
}
+define i64 @ptr_to_byte_vec_to_int(ptr %p) {
+; CHECK-LABEL: define i64 @ptr_to_byte_vec_to_int(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[X:%.*]] = ptrtoaddr ptr [[P]] to i64
+; CHECK-NEXT: ret i64 [[X]]
+;
+ %b = bitcast ptr %p to <2 x b32>
+ %x = bitcast <2 x b32> %b to i64
+ ret i64 %x
+}
+
+; ptrtoaddr can't cast a scalar pointer to a vector.
+define <1 x i64> @neg_ptr_to_byte_to_int_vec1(ptr %p) {
+; CHECK-LABEL: define <1 x i64> @neg_ptr_to_byte_to_int_vec1(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = bitcast ptr [[P]] to b64
+; CHECK-NEXT: [[X:%.*]] = bitcast b64 [[B]] to <1 x i64>
+; CHECK-NEXT: ret <1 x i64> [[X]]
+;
+ %b = bitcast ptr %p to b64
+ %x = bitcast b64 %b to <1 x i64>
+ ret <1 x i64> %x
+}
+
+define double @neg_ptr_to_byte_to_fp(ptr %p) {
+; CHECK-LABEL: define double @neg_ptr_to_byte_to_fp(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = bitcast ptr [[P]] to b64
+; CHECK-NEXT: [[X:%.*]] = bitcast b64 [[B]] to double
+; CHECK-NEXT: ret double [[X]]
+;
+ %b = bitcast ptr %p to b64
+ %x = bitcast b64 %b to double
+ ret double %x
+}
+
+; Address width (64) != pointer width (128).
+define i128 @neg_ptr_to_byte_to_int_narrow_addr(ptr addrspace(1) %p) {
+; CHECK-LABEL: define i128 @neg_ptr_to_byte_to_int_narrow_addr(
+; CHECK-SAME: ptr addrspace(1) [[P:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = bitcast ptr addrspace(1) [[P]] to b128
+; CHECK-NEXT: [[X:%.*]] = bitcast b128 [[B]] to i128
+; CHECK-NEXT: ret i128 [[X]]
+;
+ %b = bitcast ptr addrspace(1) %p to b128
+ %x = bitcast b128 %b to i128
+ ret i128 %x
+}
+
+; Lane width matches the address width (64), but not the pointer width (128).
+define <2 x i64> @neg_ptr_to_byte_to_int_narrow_addr_vec(ptr addrspace(1) %p) {
+; CHECK-LABEL: define <2 x i64> @neg_ptr_to_byte_to_int_narrow_addr_vec(
+; CHECK-SAME: ptr addrspace(1) [[P:%.*]]) {
+; CHECK-NEXT: [[B:%.*]] = bitcast ptr addrspace(1) [[P]] to b128
+; CHECK-NEXT: [[X:%.*]] = bitcast b128 [[B]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[X]]
+;
+ %b = bitcast ptr addrspace(1) %p to b128
+ %x = bitcast b128 %b to <2 x i64>
+ ret <2 x i64> %x
+}
+
define ptr @neg_ptr_to_byte_to_ptr_addrspace(ptr addrspace(2) %p) {
; CHECK-LABEL: define ptr @neg_ptr_to_byte_to_ptr_addrspace(
; CHECK-SAME: ptr addrspace(2) [[P:%.*]]) {
@@ -61,6 +123,7 @@ define b64 @neg_inttoptr_to_byte(i64 %i) {
ret b64 %x
}
+; ptrtoint exposes the provenance.
define i64 @neg_byte_to_ptrtoint(b64 %b) {
; CHECK-LABEL: define i64 @neg_byte_to_ptrtoint(
; CHECK-SAME: b64 [[B:%.*]]) {
@@ -73,11 +136,10 @@ define i64 @neg_byte_to_ptrtoint(b64 %b) {
ret i64 %x
}
-define i64 @neg_byte_to_ptrtoaddr(b64 %b) {
-; CHECK-LABEL: define i64 @neg_byte_to_ptrtoaddr(
+define i64 @byte_to_ptrtoaddr(b64 %b) {
+; CHECK-LABEL: define i64 @byte_to_ptrtoaddr(
; CHECK-SAME: b64 [[B:%.*]]) {
-; CHECK-NEXT: [[P:%.*]] = bitcast b64 [[B]] to ptr
-; CHECK-NEXT: [[X:%.*]] = ptrtoaddr ptr [[P]] to i64
+; CHECK-NEXT: [[X:%.*]] = bitcast b64 [[B]] to i64
; CHECK-NEXT: ret i64 [[X]]
;
%p = bitcast b64 %b to ptr
@@ -85,6 +147,30 @@ define i64 @neg_byte_to_ptrtoaddr(b64 %b) {
ret i64 %x
}
+define <2 x i64> @byte_to_ptrtoaddr_vec(<2 x b64> %b) {
+; CHECK-LABEL: define <2 x i64> @byte_to_ptrtoaddr_vec(
+; CHECK-SAME: <2 x b64> [[B:%.*]]) {
+; CHECK-NEXT: [[X:%.*]] = bitcast <2 x b64> [[B]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[X]]
+;
+ %p = bitcast <2 x b64> %b to <2 x ptr>
+ %x = ptrtoaddr <2 x ptr> %p to <2 x i64>
+ ret <2 x i64> %x
+}
+
+; Address width (64) != pointer width (128).
+define i64 @neg_byte_to_ptrtoaddr_narrow_addr(b128 %b) {
+; CHECK-LABEL: define i64 @neg_byte_to_ptrtoaddr_narrow_addr(
+; CHECK-SAME: b128 [[B:%.*]]) {
+; CHECK-NEXT: [[P:%.*]] = bitcast b128 [[B]] to ptr addrspace(1)
+; CHECK-NEXT: [[X:%.*]] = ptrtoaddr ptr addrspace(1) [[P]] to i64
+; CHECK-NEXT: ret i64 [[X]]
+;
+ %p = bitcast b128 %b to ptr addrspace(1)
+ %x = ptrtoaddr ptr addrspace(1) %p to i64
+ ret i64 %x
+}
+
define ptr @ptr_to_byte_to_ptr(ptr %p) {
; CHECK-LABEL: define ptr @ptr_to_byte_to_ptr(
; CHECK-SAME: ptr [[P:%.*]]) {
diff --git a/llvm/test/Transforms/InstSimplify/byte-cast-pairs.ll b/llvm/test/Transforms/InstSimplify/byte-cast-pairs.ll
index 578a51297d88ec6..99831384cbe55a8 100644
--- a/llvm/test/Transforms/InstSimplify/byte-cast-pairs.ll
+++ b/llvm/test/Transforms/InstSimplify/byte-cast-pairs.ll
@@ -9,9 +9,9 @@
; CHECK: @g = external global i32
; CHECK: @c = global i64 bitcast (b64 bitcast (ptr @g to b64) to i64)
;.
-define i64 @neg_ptr_to_byte_to_int_const() {
-; CHECK-LABEL: define i64 @neg_ptr_to_byte_to_int_const() {
-; CHECK-NEXT: ret i64 bitcast (b64 bitcast (ptr @g to b64) to i64)
+define i64 @ptr_to_byte_to_int_const() {
+; CHECK-LABEL: define i64 @ptr_to_byte_to_int_const() {
+; CHECK-NEXT: ret i64 ptrtoaddr (ptr @g to i64)
;
%x = bitcast b64 bitcast (ptr @g to b64) to i64
ret i64 %x
``````````
</details>
https://github.com/llvm/llvm-project/pull/229107
More information about the llvm-branch-commits
mailing list