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