forked from OSchip/llvm-project
[IR] Add a `data_operand` abstraction
Summary: Data operands of a call or invoke consist of the call arguments, and the bundle operands associated with the `call` (or `invoke`) instruction. The motivation for this change is that we'd like to be able to query "argument attributes" like `readonly` and `nocapture` for bundle operands naturally. This change also provides a conservative "implementation" for these attributes for any bundle operand, and an extension point for future work. Reviewers: chandlerc, majnemer, reames Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D14305 llvm-svn: 252077
This commit is contained in:
parent
d7dcffaea4
commit
a4bae3bb21
|
@ -163,6 +163,34 @@ public:
|
|||
bool arg_empty() const { return arg_end() == arg_begin(); }
|
||||
unsigned arg_size() const { return unsigned(arg_end() - arg_begin()); }
|
||||
|
||||
/// Type of iterator to use when looping over data operands at this call site
|
||||
/// (see below).
|
||||
typedef IterTy data_operand_iterator;
|
||||
|
||||
/// 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.
|
||||
|
||||
IterTy data_operands_begin() const {
|
||||
assert(getInstruction() && "Not a call or invoke instruction!");
|
||||
return (*this)->op_begin();
|
||||
}
|
||||
IterTy data_operands_end() const {
|
||||
assert(getInstruction() && "Not a call or invoke instruction!");
|
||||
return (*this)->op_end() - (isCall() ? 1 : 3);
|
||||
}
|
||||
iterator_range<IterTy> data_ops() const {
|
||||
return iterator_range<IterTy>(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());
|
||||
}
|
||||
|
||||
/// getType - Return the type of the instruction that generated this call site
|
||||
///
|
||||
Type *getType() const { return (*this)->getType(); }
|
||||
|
@ -245,6 +273,17 @@ public:
|
|||
CALLSITE_DELEGATE_GETTER(paramHasAttr(i, A));
|
||||
}
|
||||
|
||||
/// \brief Return true if the data operand at index \p i directly or
|
||||
/// indirectly has the attribute \p A.
|
||||
///
|
||||
/// Normal call or invoke arguments have per operand attributes, as specified
|
||||
/// in the attribute set attached to this instruction, while operand bundle
|
||||
/// operands may have some attributes implied by the type of its containing
|
||||
/// operand bundle.
|
||||
bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const {
|
||||
CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, A));
|
||||
}
|
||||
|
||||
/// @brief Extract the alignment for a call or parameter (0=unknown).
|
||||
uint16_t getParamAlignment(uint16_t i) const {
|
||||
CALLSITE_DELEGATE_GETTER(getParamAlignment(i));
|
||||
|
@ -347,9 +386,9 @@ public:
|
|||
#undef CALLSITE_DELEGATE_GETTER
|
||||
#undef CALLSITE_DELEGATE_SETTER
|
||||
|
||||
/// @brief Determine whether this argument is not captured.
|
||||
bool doesNotCapture(unsigned ArgNo) const {
|
||||
return paramHasAttr(ArgNo + 1, Attribute::NoCapture);
|
||||
/// @brief Determine whether this data operand is not captured.
|
||||
bool doesNotCapture(unsigned OpNo) const {
|
||||
return dataOperandHasImpliedAttr(OpNo + 1, Attribute::NoCapture);
|
||||
}
|
||||
|
||||
/// @brief Determine whether this argument is passed by value.
|
||||
|
@ -374,13 +413,13 @@ public:
|
|||
return paramHasAttr(arg_size(), Attribute::InAlloca);
|
||||
}
|
||||
|
||||
bool doesNotAccessMemory(unsigned ArgNo) const {
|
||||
return paramHasAttr(ArgNo + 1, Attribute::ReadNone);
|
||||
bool doesNotAccessMemory(unsigned OpNo) const {
|
||||
return dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone);
|
||||
}
|
||||
|
||||
bool onlyReadsMemory(unsigned ArgNo) const {
|
||||
return paramHasAttr(ArgNo + 1, Attribute::ReadOnly) ||
|
||||
paramHasAttr(ArgNo + 1, Attribute::ReadNone);
|
||||
bool onlyReadsMemory(unsigned OpNo) const {
|
||||
return dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadOnly) ||
|
||||
dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone);
|
||||
}
|
||||
|
||||
/// @brief Return true if the return value is known to be not null.
|
||||
|
|
|
@ -1120,6 +1120,16 @@ struct OperandBundleUse {
|
|||
OperandBundleUse() {}
|
||||
explicit OperandBundleUse(StringRef Tag, ArrayRef<Use> 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
|
||||
|
@ -1254,6 +1264,18 @@ public:
|
|||
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 {
|
||||
|
|
|
@ -1603,6 +1603,21 @@ public:
|
|||
/// \brief Determine whether the call or the callee has the given attributes.
|
||||
bool paramHasAttr(unsigned i, Attribute::AttrKind A) const;
|
||||
|
||||
/// \brief Return true if the data operand at index \p i has the attribute \p
|
||||
/// A.
|
||||
///
|
||||
/// Data operands include call arguments and values used in operand bundles,
|
||||
/// but does not include the callee operand. This routine dispatches to the
|
||||
/// underlying AttributeList or the OperandBundleUser as appropriate.
|
||||
///
|
||||
/// The index \p i is interpreted as
|
||||
///
|
||||
/// \p i == Attribute::ReturnIndex -> the return value
|
||||
/// \p i in [1, arg_size + 1) -> argument number (\p i - 1)
|
||||
/// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index
|
||||
/// (\p i - 1) in the operand list.
|
||||
bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const;
|
||||
|
||||
/// \brief Extract the alignment for a call or parameter (0=unknown).
|
||||
unsigned getParamAlignment(unsigned i) const {
|
||||
return AttributeList.getParamAlignment(i);
|
||||
|
@ -3474,6 +3489,22 @@ public:
|
|||
/// \brief Determine whether the call or the callee has the given attributes.
|
||||
bool paramHasAttr(unsigned i, Attribute::AttrKind A) const;
|
||||
|
||||
/// \brief Return true if the data operand at index \p i has the attribute \p
|
||||
/// A.
|
||||
///
|
||||
/// Data operands include invoke arguments and values used in operand bundles,
|
||||
/// but does not include the invokee operand, or the two successor blocks.
|
||||
/// This routine dispatches to the underlying AttributeList or the
|
||||
/// OperandBundleUser as appropriate.
|
||||
///
|
||||
/// The index \p i is interpreted as
|
||||
///
|
||||
/// \p i == Attribute::ReturnIndex -> the return value
|
||||
/// \p i in [1, arg_size + 1) -> argument number (\p i - 1)
|
||||
/// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index
|
||||
/// (\p i - 1) in the operand list.
|
||||
bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const;
|
||||
|
||||
/// \brief Extract the alignment for a call or parameter (0=unknown).
|
||||
unsigned getParamAlignment(unsigned i) const {
|
||||
return AttributeList.getParamAlignment(i);
|
||||
|
|
|
@ -340,6 +340,21 @@ bool CallInst::paramHasAttr(unsigned i, Attribute::AttrKind A) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CallInst::dataOperandHasImpliedAttr(unsigned i,
|
||||
Attribute::AttrKind A) const {
|
||||
|
||||
// The attribute A can either be directly specified, if the operand in
|
||||
// question is a call argument; or be indirectly implied by the kind of its
|
||||
// containing operand bundle, if the operand is a bundle operand.
|
||||
|
||||
if (i < (getNumArgOperands() + 1))
|
||||
return paramHasAttr(i, A);
|
||||
|
||||
assert(hasOperandBundles() && i >= (getBundleOperandsStartIndex() + 1) &&
|
||||
"Must be either a call argument or an operand bundle!");
|
||||
return getOperandBundleForOperand(i - 1).operandsHaveAttr(A);
|
||||
}
|
||||
|
||||
/// IsConstantOne - Return true only if val is constant int 1
|
||||
static bool IsConstantOne(Value *val) {
|
||||
assert(val && "IsConstantOne does not work with nullptr val");
|
||||
|
@ -586,6 +601,20 @@ bool InvokeInst::paramHasAttr(unsigned i, Attribute::AttrKind A) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool InvokeInst::dataOperandHasImpliedAttr(unsigned i,
|
||||
Attribute::AttrKind A) const {
|
||||
// The attribute A can either be directly specified, if the operand in
|
||||
// question is an invoke argument; or be indirectly implied by the kind of its
|
||||
// containing operand bundle, if the operand is a bundle operand.
|
||||
|
||||
if (i < (getNumArgOperands() + 1))
|
||||
return paramHasAttr(i, A);
|
||||
|
||||
assert(hasOperandBundles() && i >= (getBundleOperandsStartIndex() + 1) &&
|
||||
"Must be either an invoke argument or an operand bundle!");
|
||||
return getOperandBundleForOperand(i - 1).operandsHaveAttr(A);
|
||||
}
|
||||
|
||||
void InvokeInst::addAttribute(unsigned i, Attribute::AttrKind attr) {
|
||||
AttributeSet PAL = getAttributes();
|
||||
PAL = PAL.addAttribute(getContext(), i, attr);
|
||||
|
|
Loading…
Reference in New Issue