Index: include/llvm/IR/CallSite.h =================================================================== --- include/llvm/IR/CallSite.h +++ include/llvm/IR/CallSite.h @@ -163,6 +163,22 @@ bool arg_empty() const { return arg_end() == arg_begin(); } unsigned arg_size() const { return unsigned(arg_end() - arg_begin()); } + /// param_begin/param_end - Return iterators iterating over the actual + /// argument list and bundle operands (i.e. every operand to the instruction + /// other than the callee and the two successor blocks for invokes). + + IterTy param_begin() const { + assert(getInstruction() && "Not a call or invoke instruction!"); + // Skip non-arguments + return (*this)->op_begin(); + } + IterTy param_end() const { return (*this)->op_end() - (isCall() ? 1 : 3); } + iterator_range params() const { + return iterator_range(param_begin(), param_end()); + } + bool param_empty() const { return param_end() == param_begin(); } + unsigned param_size() const { return unsigned(param_end() - param_begin()); } + /// getType - Return the type of the instruction that generated this call site /// Type *getType() const { return (*this)->getType(); } Index: include/llvm/IR/InstrTypes.h =================================================================== --- include/llvm/IR/InstrTypes.h +++ include/llvm/IR/InstrTypes.h @@ -1120,6 +1120,16 @@ OperandBundleUse() {} explicit OperandBundleUse(StringRef Tag, ArrayRef Inputs) : Tag(Tag), Inputs(Inputs) {} + + /// \brief Return true if all the operands in this operand bundle have the + /// attribute A. + /// + /// Currently there is no way to have attributes on operand bundles differ on + /// a per operand granularity. + bool operandsHaveAttr(Attribute::AttrKind A) const { + // Conservative answer: no operands have any attributes. + return false; + }; }; /// \brief A container for an operand bundle being viewed as a set of values @@ -1196,27 +1206,35 @@ /// \brief Return true if this User has any operand bundles. bool hasOperandBundles() const { return getNumOperandBundles() != 0; } + /// \brief Return the index of the first bundle operand in the Use array. + unsigned getBundleOperandsStartIndex() const { + assert(hasOperandBundles() && "Don't call otherwise!"); + return bundle_op_info_begin()->Begin; + } + + /// \brief Return the index of the last bundle operand in the Use array. + unsigned getBundleOperandsEndIndex() const { + assert(hasOperandBundles() && "Don't call otherwise!"); + return bundle_op_info_end()[-1].End; + } + /// \brief Return the total number operands (not operand bundles) used by /// every operand bundle in this OperandBundleUser. unsigned getNumTotalBundleOperands() const { if (!hasOperandBundles()) return 0; - auto *Begin = bundle_op_info_begin(); - auto *Back = bundle_op_info_end() - 1; - - assert(Begin <= Back && "hasOperandBundles() returned true!"); + unsigned Begin = getBundleOperandsStartIndex(); + unsigned End = getBundleOperandsEndIndex(); - return Back->End - Begin->Begin; + assert(Begin <= End && "Should be!"); + return End - Begin; } /// \brief Return the operand bundle at a specific index. OperandBundleUse getOperandBundle(unsigned Index) const { assert(Index < getNumOperandBundles() && "Index out of bounds!"); - auto *BOI = bundle_op_info_begin() + Index; - auto op_begin = static_cast(this)->op_begin(); - ArrayRef Inputs(op_begin + BOI->Begin, op_begin + BOI->End); - return OperandBundleUse(BOI->Tag->getKey(), Inputs); + return operandBundleFromBundleOpInfo(bundle_op_info_begin()[Index]); } /// \brief Return the number of operand bundles with the tag Name attached to @@ -1246,6 +1264,18 @@ return None; } + /// \brief Return the operand bundle for the operand at index OpIdx. + /// + /// It is an error to call this with an OpIdx that does not correspond to an + /// bundle operand. + OperandBundleUse getOperandBundleForOperand(unsigned OpIdx) const { + for (auto &BOI : bundle_op_infos()) + if (BOI.Begin <= OpIdx && OpIdx < BOI.End) + return operandBundleFromBundleOpInfo(BOI); + + llvm_unreachable("Did not find operand bundle for operand!"); + } + /// \brief Return true if this operand bundle user has operand bundles that /// may read from the heap. bool hasReadingOperandBundles() const { @@ -1309,6 +1339,15 @@ uint32_t End; }; + /// \brief Simple helper function to map a BundleOpInfo to an + /// OperandBundleUse. + OperandBundleUse + operandBundleFromBundleOpInfo(const BundleOpInfo &BOI) const { + auto op_begin = static_cast(this)->op_begin(); + ArrayRef Inputs(op_begin + BOI.Begin, op_begin + BOI.End); + return OperandBundleUse(BOI.Tag->getKey(), Inputs); + } + typedef BundleOpInfo *bundle_op_iterator; typedef const BundleOpInfo *const_bundle_op_iterator; Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -333,6 +333,9 @@ bool CallInst::paramHasAttr(unsigned i, Attribute::AttrKind A) const { assert(i != AttributeSet::FunctionIndex && "Use hasFnAttr instead!"); + if (hasOperandBundles() && i >= (getBundleOperandsStartIndex() + 1)) + return getOperandBundleForOperand(i - 1).operandsHaveAttr(A); + if (AttributeList.hasAttribute(i, A)) return true; if (const Function *F = getCalledFunction()) @@ -579,6 +582,9 @@ bool InvokeInst::paramHasAttr(unsigned i, Attribute::AttrKind A) const { assert(i != AttributeSet::FunctionIndex && "Use hasFnAttr instead!"); + if (hasOperandBundles() && i >= (getBundleOperandsStartIndex() + 1)) + return getOperandBundleForOperand(i - 1).operandsHaveAttr(A); + if (AttributeList.hasAttribute(i, A)) return true; if (const Function *F = getCalledFunction())