[llvm] [InferAS] Infer the address space of inttoptr (PR #173244)

Luo Yuanke via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 10 05:04:56 PST 2026


================
@@ -369,15 +384,56 @@ getPointerOperands(const Value &V, const DataLayout &DL,
     return {II.getArgOperand(0)};
   }
   case Instruction::IntToPtr: {
-    assert(isNoopPtrIntCastPair(&Op, DL, TTI));
-    auto *P2I = cast<Operator>(Op.getOperand(0));
-    return {P2I->getOperand(0)};
+    if (isNoopPtrIntCastPair(&Op, DL, TTI)) {
+      auto *P2I = cast<Operator>(Op.getOperand(0));
+      return {P2I->getOperand(0)};
+    }
+    assert(isSafeToCastPtrIntPair(&Op, DL));
+    return {PtrIntCastPairs[&Op]};
   }
   default:
     llvm_unreachable("Unexpected instruction type.");
   }
 }
 
+bool InferAddressSpacesImpl::isSafeToCastPtrIntPair(
+    const Operator *I2P, const DataLayout &DL) const {
+  assert(I2P->getOpcode() == Instruction::IntToPtr);
+  if (PtrIntCastPairs.count(I2P))
+    return true;
+
+  if (I2P->getType()->isVectorTy())
+    return false;
+
+  auto *Xor = dyn_cast<Operator>(I2P->getOperand(0));
+  if (!Xor || Xor->getOpcode() != Instruction::Xor)
+    return false;
----------------
LuoYuanke wrote:

I try to create a temporary instruction `bitdiff = xor(initial_ptrvalue, ptrvalue)`, but ValueTracking is not that powerful to deduce the known bit of bitdiff.

The idea to create a helper intrinsic looks good to me. How about name intrinsic as `void @llvm.ptr.bit.diff(ptr InitialPtr, ptr DerivedPtr, iAny BitDiff)` which provide some information of the bitdiff? It is similar to `void @llvm.assume(i1)` which can not be eliminated by any optimization.
In InstCombine pass we can visit `IntToPtr` and insert intrinsic `void @llvm.ptrdiff(ptr InitialPtr, ptr IntToPtr, i64 BitDiff)` after it. Then in InferAddressSpaces, we visit ptrdiff intrinsic and infer the address space. We may also eliminate the intrinsic and the related dead code in CodeGenPrepare().

Another way maybe transform the address to %baseAddr + %offset. The %baseAddr is the common bit for initial_ptrvalue and ptrvalue. We can transform the %baseAddr to `%baseAddr = call ptr @llvm.ptrmask.p0.iAny(ptr %ptrValue, iAny %mask)`, so that InferAddressSpaces can infer the address space. For example,

```
define void @test_xor_smem(ptr addrspace(3) %sp) {
  %gp = addrspacecast ptr addrspace(3) %sp to ptr
  %a = ptrtoint ptr %gp to i64
  %b = xor i64 4095, %a
  %gp2 = inttoptr i64 %b to ptr
  store i64 0, ptr %gp2, align 8
  ret void
}
```
can be transformed to 
```
define void @test_xor_smem(ptr addrspace(3) %sp) {
  %gp = addrspacecast ptr addrspace(3) %sp to ptr
  %a = ptrtoint ptr %gp to i64
  %b = xor i64 4095, %a
  %gp2 = inttoptr i64 %b to ptr
  %xor = xor i64 %a, %b
  %lz = call i64 @llvm.ctlz.i64(i64 %xor)
  %lmask = lshr i64 -1, %lz
  %offset = and i64 %b, %lmask
  %base = sub i64 %b, %offset
  %hmask = xor i64 -1, %lmask
  %bptr = call ptr @llvm.ptrmask.p0.i64(ptr %gp, i64 %hmask)
  %dstptr = getelementptr i8, ptr %bptr, i64 %offset
  store i64 0, ptr %dstptr, align 8
  ret void
}
```
And then being transformed by InstCombine as below.
```
define void @test_xor_smem(ptr addrspace(3) %sp) {
  %gp = addrspacecast ptr addrspace(3) %sp to ptr
  %a = ptrtoint ptr %gp to i64
  %b = and i64 %a, 4095
  %offset = xor i64 %b, 4095
  %bptr = call align 4096 ptr @llvm.ptrmask.p0.i64(ptr %gp, i64 -4096)
  %dstptr = getelementptr i8, ptr %bptr, i64 %offset
  store i64 0, ptr %dstptr, align 8
  ret void
}
```
The cons is this introduce many instructions to calculate the %basePtr and %offset. If InstCombine failed to reduce the instructions, the overhead seems unacceptable.


https://github.com/llvm/llvm-project/pull/173244


More information about the llvm-commits mailing list