Index: llvm/trunk/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/trunk/include/llvm/IR/InstrTypes.h +++ llvm/trunk/include/llvm/IR/InstrTypes.h @@ -46,6 +46,10 @@ namespace llvm { +namespace Intrinsic { +enum ID : unsigned; +} + //===----------------------------------------------------------------------===// // UnaryInstruction Class //===----------------------------------------------------------------------===// @@ -1040,6 +1044,9 @@ return I->getOpcode() == Instruction::Call || I->getOpcode() == Instruction::Invoke; } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } FunctionType *getFunctionType() const { return FTy; } @@ -1048,6 +1055,47 @@ 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(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(this)->data_operands_end(); + } + iterator_range data_ops() { + return make_range(data_operands_begin(), data_operands_end()); + } + iterator_range 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 @@ /// 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(this)->arg_end(); } /// Iteration adapter for range-for loops. + iterator_range args() { + return make_range(arg_begin(), arg_end()); + } + iterator_range 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 arg_operands() { return make_range(arg_begin(), arg_end()); } iterator_range 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 @@ 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(); } @@ -1113,6 +1182,17 @@ return dyn_cast_or_null(getCalledOperand()); } + /// Helper to get the caller (the parent function). + Function *getCaller(); + const Function *getCaller() const { + return const_cast(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() = V; } /// Sets the function called, including updating the function type. @@ -1304,6 +1384,55 @@ 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 @@ 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 @@ 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 { Index: llvm/trunk/lib/IR/Instructions.cpp =================================================================== --- llvm/trunk/lib/IR/Instructions.cpp +++ llvm/trunk/lib/IR/Instructions.cpp @@ -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 @@ // 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;