[llvm] 4d7ba1f - [IR] Preserve pointer-byte bitcasts around addrspacecast (#202454)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 07:15:59 PDT 2026


Author: Drew Kersnar
Date: 2026-06-09T09:15:54-05:00
New Revision: 4d7ba1f5ef6402183372e2ea6358c53a9c182868

URL: https://github.com/llvm/llvm-project/commit/4d7ba1f5ef6402183372e2ea6358c53a9c182868
DIFF: https://github.com/llvm/llvm-project/commit/4d7ba1f5ef6402183372e2ea6358c53a9c182868.diff

LOG: [IR] Preserve pointer-byte bitcasts around addrspacecast (#202454)

This fixes cast-pair elimination for addrspacecast combined with
pointer/byte bitcast.

The LLVM LangRef defines [bN byte
types](https://llvm.org/docs/LangRef.html#byte-type) as raw memory data
in SSA registers, where each bit may be an integer bit, part of a
pointer value, or poison.

The LangRef permits pointer-to-byte bitcast: the [bitcast .. to
instruction](https://llvm.org/docs/LangRef.html#bitcast-to-instruction)
says that if the source type is a pointer, the destination type must be
a pointer or a byte/vector-of-bytes type of the same size.

The same [bitcast .. to
section](https://llvm.org/docs/LangRef.html#bitcast-to-instruction) also
defines byte-to-pointer behavior: when the destination type is a pointer
type, a byte value whose bits all come from the same correctly ordered
pointer produces that pointer; otherwise it produces a pointer with the
address encoded by the input and no provenance.

By contrast, [addrspacecast ..
to](https://llvm.org/docs/LangRef.html#addrspacecast-to-instruction) is
only valid from a pointer or vector-of-pointers value to a pointer type
in a different address space.

So these two-step sequences are valid:

```
%p = addrspacecast ptr addrspace(1) %x to ptr
%b = bitcast ptr %p to b64
```
```
%p = bitcast b64 %x to ptr
%q = addrspacecast ptr %p to ptr addrspace(1)
```
But they cannot be folded into a single addrspacecast, because that
would require addrspacecast to cast directly to or from bN, which the
LangRef does not allow.

This patch prevents cast-pair elimination from performing those invalid
folds and adds InstCombine regression coverage for both directions. Both
tests crashed before this patch. This patch was created with the
assistance of AI, based on a real case I found while working on
https://github.com/llvm/llvm-project/pull/177908. I'm pretty sure I'm
reading the langref correctly, but please let me know if I am mistaken.

Added: 
    

Modified: 
    llvm/lib/IR/Instructions.cpp
    llvm/test/Transforms/InstCombine/addrspacecast.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index a22683916b9cc..496a3ffa5d965 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -3033,6 +3033,10 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
       // FIXME: this state can be merged with (1), but the following assert
       // is useful to check the correcteness of the sequence due to semantic
       // change of bitcast.
+      // addrspacecast can only fold through a bitcast if the result remains a
+      // pointer. A pointer-to-byte bitcast must stay as a separate bitcast.
+      if (!DstTy->isPtrOrPtrVectorTy())
+        return 0;
       assert(
         SrcTy->isPtrOrPtrVectorTy() &&
         MidTy->isPtrOrPtrVectorTy() &&
@@ -3044,6 +3048,10 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
       return firstOp;
     case 14:
       // bitcast, addrspacecast -> addrspacecast
+      // addrspacecast 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())
+        return 0;
       return Instruction::AddrSpaceCast;
     case 15:
       // FIXME: this state can be merged with (1), but the following assert

diff  --git a/llvm/test/Transforms/InstCombine/addrspacecast.ll b/llvm/test/Transforms/InstCombine/addrspacecast.ll
index 8f3270cd60609..ff37149bdab7b 100644
--- a/llvm/test/Transforms/InstCombine/addrspacecast.ll
+++ b/llvm/test/Transforms/InstCombine/addrspacecast.ll
@@ -67,6 +67,29 @@ define ptr addrspace(2) @combine_addrspacecast_bitcast_2(ptr addrspace(1) %x) no
   ret ptr addrspace(2) %y
 }
 
+define b64 @do_not_combine_addrspacecast_bitcast_to_byte(ptr addrspace(1) %x) nounwind {
+; CHECK-LABEL: @do_not_combine_addrspacecast_bitcast_to_byte(
+; CHECK-NEXT:    [[Y:%.*]] = addrspacecast ptr addrspace(1) [[X:%.*]] to ptr
+; CHECK-NEXT:    [[Z:%.*]] = bitcast ptr [[Y]] to b64
+; CHECK-NEXT:    ret b64 [[Z]]
+;
+  %y = addrspacecast ptr addrspace(1) %x to ptr
+  %z = bitcast ptr %y to b64
+  ret b64 %z
+}
+
+define ptr addrspace(1) @do_not_combine_bitcast_from_byte_addrspacecast(b64 %x) nounwind {
+; CHECK-LABEL: @do_not_combine_bitcast_from_byte_addrspacecast(
+; CHECK-NEXT:    [[Y:%.*]] = bitcast b64 [[X:%.*]] to ptr
+; CHECK-NEXT:    [[Z:%.*]] = addrspacecast ptr [[Y]] to ptr addrspace(1)
+; CHECK-NEXT:    ret ptr addrspace(1) [[Z]]
+;
+  %y = bitcast b64 %x to ptr
+  %z = addrspacecast ptr %y to ptr addrspace(1)
+  ret ptr addrspace(1) %z
+}
+
+
 define ptr addrspace(2) @combine_bitcast_addrspacecast_1(ptr addrspace(1) %x) nounwind {
 ; CHECK-LABEL: @combine_bitcast_addrspacecast_1(
 ; CHECK-NEXT:    [[Z:%.*]] = addrspacecast ptr addrspace(1) [[X:%.*]] to ptr addrspace(2)


        


More information about the llvm-commits mailing list