[llvm] r350109 - [CallSite removal] Add and flesh out APIs on the new `CallBase` base class that previously were only available on the `CallSite` wrapper.

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 2 11:50:38 PST 2019


Thanks for staging this.  Having the migration period will make this 
much easier to handle downstream.

Philip

On 12/27/18 3:40 PM, Chandler Carruth via llvm-commits wrote:
> Author: chandlerc
> Date: Thu Dec 27 15:40:17 2018
> New Revision: 350109
>
> URL: http://llvm.org/viewvc/llvm-project?rev=350109&view=rev
> Log:
> [CallSite removal] Add and flesh out APIs on the new `CallBase` base class that previously were only available on the `CallSite` wrapper.
>
> Summary:
> This will make migrating code easier and generally seems like a good collection
> of API improvements.
>
> Some of these APIs seem like more consistent / better naming of existing
> ones. I've retained the old names for migration simplicit and am just
> adding the new ones in this commit. I'll try to garbage collect these
> once CallSite is gone.
>
> Subscribers: sanjoy, mcrosier, hiraditya, llvm-commits
>
> Differential Revision: https://reviews.llvm.org/D55638
>
> Modified:
>      llvm/trunk/include/llvm/IR/InstrTypes.h
>      llvm/trunk/lib/IR/Instructions.cpp
>
> Modified: llvm/trunk/include/llvm/IR/InstrTypes.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/InstrTypes.h?rev=350109&r1=350108&r2=350109&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/InstrTypes.h (original)
> +++ llvm/trunk/include/llvm/IR/InstrTypes.h Thu Dec 27 15:40:17 2018
> @@ -46,6 +46,10 @@
>   
>   namespace llvm {
>   
> +namespace Intrinsic {
> +enum ID : unsigned;
> +}
> +
>   //===----------------------------------------------------------------------===//
>   //                          UnaryInstruction Class
>   //===----------------------------------------------------------------------===//
> @@ -1040,6 +1044,9 @@ public:
>       return I->getOpcode() == Instruction::Call ||
>              I->getOpcode() == Instruction::Invoke;
>     }
> +  static bool classof(const Value *V) {
> +    return isa<Instruction>(V) && classof(cast<Instruction>(V));
> +  }
>   
>     FunctionType *getFunctionType() const { return FTy; }
>   
> @@ -1048,6 +1055,47 @@ public:
>       this->FTy = FTy;
>     }
>   
> +  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
> +
> +  /// data_operands_begin/data_operands_end - Return iterators iterating over
> +  /// the call / invoke argument list and bundle operands.  For invokes, this is
> +  /// the set of instruction operands except the invoke target and the two
> +  /// successor blocks; and for calls this is the set of instruction operands
> +  /// except the call target.
> +  User::op_iterator data_operands_begin() { return op_begin(); }
> +  User::const_op_iterator data_operands_begin() const {
> +    return const_cast<CallBase *>(this)->data_operands_begin();
> +  }
> +  User::op_iterator data_operands_end() {
> +    // Walk from the end of the operands over the called operand and any
> +    // subclass operands.
> +    return op_end() - getNumSubclassExtraOperands() - 1;
> +  }
> +  User::const_op_iterator data_operands_end() const {
> +    return const_cast<CallBase *>(this)->data_operands_end();
> +  }
> +  iterator_range<User::op_iterator> data_ops() {
> +    return make_range(data_operands_begin(), data_operands_end());
> +  }
> +  iterator_range<User::const_op_iterator> data_ops() const {
> +    return make_range(data_operands_begin(), data_operands_end());
> +  }
> +  bool data_operands_empty() const {
> +    return data_operands_end() == data_operands_begin();
> +  }
> +  unsigned data_operands_size() const {
> +    return std::distance(data_operands_begin(), data_operands_end());
> +  }
> +
> +  bool isDataOperand(const Use *U) const {
> +    assert(this == U->getUser() &&
> +           "Only valid to query with a use of this instruction!");
> +    return data_operands_begin() <= U && U < data_operands_end();
> +  }
> +  bool isDataOperand(Value::const_user_iterator UI) const {
> +    return isDataOperand(&UI.getUse());
> +  }
> +
>     /// Return the iterator pointing to the beginning of the argument list.
>     User::op_iterator arg_begin() { return op_begin(); }
>     User::const_op_iterator arg_begin() const {
> @@ -1056,25 +1104,33 @@ public:
>   
>     /// Return the iterator pointing to the end of the argument list.
>     User::op_iterator arg_end() {
> -    // Walk from the end of the operands over the called operand, the subclass
> -    // operands, and any operands for bundles to find the end of the argument
> +    // From the end of the data operands, walk backwards past the bundle
>       // operands.
> -    return op_end() - getNumTotalBundleOperands() -
> -           getNumSubclassExtraOperands() - 1;
> +    return data_operands_end() - getNumTotalBundleOperands();
>     }
>     User::const_op_iterator arg_end() const {
>       return const_cast<CallBase *>(this)->arg_end();
>     }
>   
>     /// Iteration adapter for range-for loops.
> +  iterator_range<User::op_iterator> args() {
> +    return make_range(arg_begin(), arg_end());
> +  }
> +  iterator_range<User::const_op_iterator> args() const {
> +    return make_range(arg_begin(), arg_end());
> +  }
> +  bool arg_empty() const { return arg_end() == arg_begin(); }
> +  unsigned arg_size() const { return arg_end() - arg_begin(); }
> +
> +  // Legacy API names that duplicate the above and will be removed once users
> +  // are migrated.
>     iterator_range<User::op_iterator> arg_operands() {
>       return make_range(arg_begin(), arg_end());
>     }
>     iterator_range<User::const_op_iterator> arg_operands() const {
>       return make_range(arg_begin(), arg_end());
>     }
> -
> -  unsigned getNumArgOperands() const { return arg_end() - arg_begin(); }
> +  unsigned getNumArgOperands() const { return arg_size(); }
>   
>     Value *getArgOperand(unsigned i) const {
>       assert(i < getNumArgOperands() && "Out of bounds!");
> @@ -1096,7 +1152,20 @@ public:
>       return User::getOperandUse(i);
>     }
>   
> -  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
> +  bool isArgOperand(const Use *U) const {
> +    assert(this == U->getUser() &&
> +           "Only valid to query with a use of this instruction!");
> +    return arg_begin() <= U && U < arg_end();
> +  }
> +  bool isArgOperand(Value::const_user_iterator UI) const {
> +    return isArgOperand(&UI.getUse());
> +  }
> +
> +  /// Returns true if this CallSite passes the given Value* as an argument to
> +  /// the called function.
> +  bool hasArgument(const Value *V) const {
> +    return llvm::any_of(args(), [V](const Value *Arg) { return Arg == V; });
> +  }
>   
>     Value *getCalledOperand() const { return Op<CalledOperandOpEndIdx>(); }
>   
> @@ -1113,6 +1182,17 @@ public:
>       return dyn_cast_or_null<Function>(getCalledOperand());
>     }
>   
> +  /// Helper to get the caller (the parent function).
> +  Function *getCaller();
> +  const Function *getCaller() const {
> +    return const_cast<CallBase *>(this)->getCaller();
> +  }
> +
> +  /// Returns the intrinsic ID of the intrinsic called or
> +  /// Intrinsic::not_intrinsic if the called function is not an intrinsic, or if
> +  /// this is an indirect call.
> +  Intrinsic::ID getIntrinsicID() const;
> +
>     void setCalledOperand(Value *V) { Op<CalledOperandOpEndIdx>() = V; }
>   
>     /// Sets the function called, including updating the function type.
> @@ -1304,6 +1384,55 @@ public:
>       return bundleOperandHasAttr(i - 1, Kind);
>     }
>   
> +  /// Determine whether this data operand is not captured.
> +  // FIXME: Once this API is no longer duplicated in `CallSite`, rename this to
> +  // better indicate that this may return a conservative answer.
> +  bool doesNotCapture(unsigned OpNo) const {
> +    return dataOperandHasImpliedAttr(OpNo + 1, Attribute::NoCapture);
> +  }
> +
> +  /// Determine whether this argument is passed by value.
> +  bool isByValArgument(unsigned ArgNo) const {
> +    return paramHasAttr(ArgNo, Attribute::ByVal);
> +  }
> +
> +  /// Determine whether this argument is passed in an alloca.
> +  bool isInAllocaArgument(unsigned ArgNo) const {
> +    return paramHasAttr(ArgNo, Attribute::InAlloca);
> +  }
> +
> +  /// Determine whether this argument is passed by value or in an alloca.
> +  bool isByValOrInAllocaArgument(unsigned ArgNo) const {
> +    return paramHasAttr(ArgNo, Attribute::ByVal) ||
> +           paramHasAttr(ArgNo, Attribute::InAlloca);
> +  }
> +
> +  /// Determine if there are is an inalloca argument. Only the last argument can
> +  /// have the inalloca attribute.
> +  bool hasInAllocaArgument() const {
> +    return !arg_empty() && paramHasAttr(arg_size() - 1, Attribute::InAlloca);
> +  }
> +
> +  // FIXME: Once this API is no longer duplicated in `CallSite`, rename this to
> +  // better indicate that this may return a conservative answer.
> +  bool doesNotAccessMemory(unsigned OpNo) const {
> +    return dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone);
> +  }
> +
> +  // FIXME: Once this API is no longer duplicated in `CallSite`, rename this to
> +  // better indicate that this may return a conservative answer.
> +  bool onlyReadsMemory(unsigned OpNo) const {
> +    return dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadOnly) ||
> +           dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone);
> +  }
> +
> +  // FIXME: Once this API is no longer duplicated in `CallSite`, rename this to
> +  // better indicate that this may return a conservative answer.
> +  bool doesNotReadMemory(unsigned OpNo) const {
> +    return dataOperandHasImpliedAttr(OpNo + 1, Attribute::WriteOnly) ||
> +           dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone);
> +  }
> +
>     /// Extract the alignment of the return value.
>     unsigned getRetAlignment() const { return Attrs.getRetAlignment(); }
>   
> @@ -1324,6 +1453,11 @@ public:
>       return Attrs.getDereferenceableOrNullBytes(i);
>     }
>   
> +  /// Return true if the return value is known to be not null.
> +  /// This may be because it has the nonnull attribute, or because at least
> +  /// one byte is dereferenceable and the pointer is in addrspace(0).
> +  bool isReturnNonNull() const;
> +
>     /// Determine if the return value is marked with NoAlias attribute.
>     bool returnDoesNotAlias() const {
>       return Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias);
> @@ -1477,6 +1611,16 @@ public:
>              Idx < getBundleOperandsEndIndex();
>     }
>   
> +  /// Returns true if the use is a bundle operand.
> +  bool isBundleOperand(const Use *U) const {
> +    assert(this == U->getUser() &&
> +           "Only valid to query with a use of this instruction!");
> +    return hasOperandBundles() && isBundleOperand(U - op_begin());
> +  }
> +  bool isBundleOperand(Value::const_user_iterator UI) const {
> +    return isBundleOperand(&UI.getUse());
> +  }
> +
>     /// Return the total number operands (not operand bundles) used by
>     /// every operand bundle in this OperandBundleUser.
>     unsigned getNumTotalBundleOperands() const {
>
> Modified: llvm/trunk/lib/IR/Instructions.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Instructions.cpp?rev=350109&r1=350108&r2=350109&view=diff
> ==============================================================================
> --- llvm/trunk/lib/IR/Instructions.cpp (original)
> +++ llvm/trunk/lib/IR/Instructions.cpp Thu Dec 27 15:40:17 2018
> @@ -27,6 +27,7 @@
>   #include "llvm/IR/Function.h"
>   #include "llvm/IR/InstrTypes.h"
>   #include "llvm/IR/Instruction.h"
> +#include "llvm/IR/Intrinsics.h"
>   #include "llvm/IR/LLVMContext.h"
>   #include "llvm/IR/Metadata.h"
>   #include "llvm/IR/Module.h"
> @@ -254,6 +255,26 @@ void LandingPadInst::addClause(Constant
>   //                        CallBase Implementation
>   //===----------------------------------------------------------------------===//
>   
> +Function *CallBase::getCaller() { return getParent()->getParent(); }
> +
> +Intrinsic::ID CallBase::getIntrinsicID() const {
> +  if (auto *F = getCalledFunction())
> +    return F->getIntrinsicID();
> +  return Intrinsic::not_intrinsic;
> +}
> +
> +bool CallBase::isReturnNonNull() const {
> +  if (hasRetAttr(Attribute::NonNull))
> +    return true;
> +
> +  if (getDereferenceableBytes(AttributeList::ReturnIndex) > 0 &&
> +           !NullPointerIsDefined(getCaller(),
> +                                 getType()->getPointerAddressSpace()))
> +    return true;
> +
> +  return false;
> +}
> +
>   Value *CallBase::getReturnedArgOperand() const {
>     unsigned Index;
>   
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list