Repository: llvm/llvm-project
File: llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp (C++)

Code before:
    return DoIt(0, Remangled);
  }

  // We can also hoist through binary operators if the other operand is uniform.
  if (isa<BinaryOperator>(OpInst)) {
    // FIXME: If we had access to UniformityInfo here we could just check
    // if the operand is uniform.
    if (isTriviallyUniform(OpInst->getOperandUse(0)))
      return DoIt(1, II.getCalledFunction());
    if (isTriviallyUniform(OpInst->getOperandUse(1)))
      return DoIt(0, II.getCalledFunction());
  }

  return nullptr;
}

std::optional<Instruction *>
GCNTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
  Intrinsic::ID IID = II.getIntrinsicID();
  switch (IID) {
  case Intrinsic::amdgcn_implicitarg_ptr: {
    bool Modified = false;
    // Not checking calling function's "amdgpu-no-implicitarg-ptr" attribute
    // under the assumption that a call to this intrinsic is not present with
    // that attribute.
    if (!II.hasRetAttr(Attribute::Dereferenceable)) {
      // Add dereferenceable and alignment attributes to the result.
      uint64_t Bytes = ST->getImplicitArgNumBytes(*II.getFunction());
      II.addRetAttr(
          Attribute::getWithDereferenceableBytes(II.getContext(), Bytes));
      Modified = true;
    }

    if (!II.hasRetAttr(Attribute::Alignment)) {
      Align Align = ST->getAlignmentForImplicitArgPtr();
      II.addRetAttr(Attribute::getWithAlignment(II.getContext(), Align));
      Modified = true;
    }

    if (Modified)
      return &II;

    return std::nullopt;
  } break;
  case Intrinsic::amdgcn_rcp: {
    Value *Src = II.getArgOperand(0);
    if (isa<PoisonValue>(Src))
      return IC.replaceInstUsesWith(II, Src);

    // TODO: Move to ConstantFolding/InstSimplify?
    if (isa<UndefValue>(Src)) {

Review comment (suggestion):
Instead of treating this as binary, it should read the value and set the value if the maximum is different 

Code after:
    return DoIt(0, Remangled);
  }

  // We can also hoist through binary operators if the other operand is uniform.
  if (isa<BinaryOperator>(OpInst)) {
    // FIXME: If we had access to UniformityInfo here we could just check
    // if the operand is uniform.
    if (isTriviallyUniform(OpInst->getOperandUse(0)))
      return DoIt(1, II.getCalledFunction());
    if (isTriviallyUniform(OpInst->getOperandUse(1)))
      return DoIt(0, II.getCalledFunction());
  }

  return nullptr;
}

std::optional<Instruction *>
GCNTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
  Intrinsic::ID IID = II.getIntrinsicID();
  switch (IID) {
  case Intrinsic::amdgcn_implicitarg_ptr: {
    uint64_t ImplicitArgBytes = ST->getImplicitArgNumBytes(*II.getFunction());

    uint64_t CurrentOrNullBytes =
        II.getAttributes().getRetDereferenceableOrNullBytes();
    if (CurrentOrNullBytes != 0) {
      // Refine "dereferenceable (A) meets dereferenceable_or_null(B)"
      // into dereferenceable(max(A, B))
      uint64_t NewBytes = std::max(CurrentOrNullBytes, ImplicitArgBytes);
      II.addRetAttr(
          Attribute::getWithDereferenceableBytes(II.getContext(), NewBytes));
      II.removeRetAttr(Attribute::DereferenceableOrNull);
      return &II;
    }

    uint64_t CurrentBytes = II.getAttributes().getRetDereferenceableBytes();
    uint64_t NewBytes = std::max(CurrentBytes, ImplicitArgBytes);
    if (NewBytes != CurrentBytes) {
      II.addRetAttr(
          Attribute::getWithDereferenceableBytes(II.getContext(), NewBytes));
      return &II;
    }

    return std::nullopt;
  }
  case Intrinsic::amdgcn_rcp: {
    Value *Src = II.getArgOperand(0);
    if (isa<PoisonValue>(Src))
      return IC.replaceInstUsesWith(II, Src);

    // TODO: Move to ConstantFolding/InstSimplify?