Repository: llvm/llvm-project
File: llvm/lib/Analysis/Loads.cpp (C++)

Code before:
    if (isa<ICmpInst, PtrToAddrInst>(User))
      continue;
    // FIXME: The PtrToIntInst case here is not strictly correct, as it
    // changes which provenance is exposed.
    if (!HasNonAddressBits && isa<PtrToIntInst>(User))
      continue;
    if (isa<PHINode, SelectInst>(User))
      Worklist.append(User->user_begin(), User->user_end());
    else
      return false;
  }

  return Limit != 0;
}

// Returns true if `From` is a null pointer, `To` is a null pointer, or `To` is
// a constant dereferenceable pointer, or both pointers have the same underlying
// objects.
static bool isPointerAlwaysReplaceable(const Value *From, const Value *To,
                                       const DataLayout &DL) {
  // This is not strictly correct, but we do it for now to retain important
  // optimizations.
  if (isa<ConstantPointerNull>(To))
    return true;
  // Conversely, replacing null with destination pointer is always valid.
  if (isa<ConstantPointerNull>(From))
    return true;
  if (isa<Constant>(To) && To->getType()->isPointerTy() &&
      isDereferenceablePointer(To, Type::getInt8Ty(To->getContext()), DL))
    return true;
  return getUnderlyingObjectAggressive(From) ==
         getUnderlyingObjectAggressive(To);
}

bool llvm::canReplacePointersInUseIfEqual(const Use &U, const Value *To,
                                          const DataLayout &DL) {
  Type *Ty = To->getType();
  assert(U->getType() == Ty && "values must have matching types");
  // Not a pointer, just return true.
  if (!Ty->isPtrOrPtrVectorTy())
    return true;

  // Do not perform replacements in lifetime intrinsic arguments.
  if (isa<LifetimeIntrinsic>(U.getUser()))
    return false;

  if (isPointerAlwaysReplaceable(&*U, To, DL))
    return true;

  bool HasNonAddressBits =
      DL.getAddressSizeInBits(Ty) != DL.getPointerTypeSizeInBits(Ty);

Review comment (bug):
I guess it is incorrect when null is defined in a non-zero address space. A null constant is interpreted as `inttoptr 0 to ptr`, which may recover provenance.

Code after:
    if (isa<ICmpInst, PtrToAddrInst>(User))
      continue;
    // FIXME: The PtrToIntInst case here is not strictly correct, as it
    // changes which provenance is exposed.
    if (!HasNonAddressBits && isa<PtrToIntInst>(User))
      continue;
    if (isa<PHINode, SelectInst>(User))
      Worklist.append(User->user_begin(), User->user_end());
    else
      return false;
  }

  return Limit != 0;
}

static bool isPointerAlwaysReplaceable(const Value *From, const Value *To,
                                       const DataLayout &DL) {
  // This is not strictly correct, but we do it for now to retain important
  // optimizations.
  if (isa<ConstantPointerNull>(To))
    return true;
  // Conversely, replacing null in the default address space with destination
  // pointer is always valid.
  if (isa<ConstantPointerNull>(From) &&
      From->getType()->getPointerAddressSpace() == 0)
    return true;
  if (isa<Constant>(To) && To->getType()->isPointerTy() &&
      isDereferenceablePointer(To, Type::getInt8Ty(To->getContext()), DL))
    return true;
  return getUnderlyingObjectAggressive(From) ==
         getUnderlyingObjectAggressive(To);
}

bool llvm::canReplacePointersInUseIfEqual(const Use &U, const Value *To,
                                          const DataLayout &DL) {
  Type *Ty = To->getType();
  assert(U->getType() == Ty && "values must have matching types");
  // Not a pointer, just return true.
  if (!Ty->isPtrOrPtrVectorTy())
    return true;

  // Do not perform replacements in lifetime intrinsic arguments.
  if (isa<LifetimeIntrinsic>(U.getUser()))
    return false;

  if (isPointerAlwaysReplaceable(&*U, To, DL))
    return true;

  bool HasNonAddressBits =
      DL.getAddressSizeInBits(Ty) != DL.getPointerTypeSizeInBits(Ty);
  return isPointerUseReplacable(U, HasNonAddressBits);