[llvm] f16f139 - Basis of dropping uses in llvm.assume.

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 13 13:58:30 PDT 2020


On 03/13, Philip Reames wrote:
> Well, the key bit is it's being considered.  That was the main thing I
> wanted to make sure of with my original email;

It is (now) for sure. Thanks again for pointing it out!


> Philip
> 
> On 3/13/20 1:13 PM, Johannes Doerfert wrote:
> > On 03/13, Philip Reames wrote:
> > > Up front, have to admit I skimmed everything past the first section since it
> > > seemed to go a bit off topic.
> > I don't think it is that simple, thus all of the other sections ;)
> > 
> > The key sentence:
> > > > However, as I see it, there is actually little we can do about it "just now".
> > I believe you can implement the collectEphemeralValues interface via
> > droppable uses but it will actually reduce the efficiency or be more
> > complex than what we have right now. We first need the described
> > infrastructure and then we replace the collectEphemeralValues
> > implementation with the lazy caching implementation I described.
> > 
> > > On 3/13/20 10:24 AM, Johannes Doerfert wrote:
> > > > Hi Philip,
> > > > 
> > > > thank you for pointing this out.
> > > > 
> > > > On 03/12, Philip Reames via llvm-commits wrote:
> > > > > I'm a bit confused, how does this droppable notion correspond to the
> > > > > ephemeral values notion we already have?  On the surface, this looks like
> > > > > duplication.
> > > > It does in a way yes. There are differences though and I think we are
> > > > moving in the right direction. Let me elaborate on both and describe how
> > > > I see the future of both.
> > > > 
> > > > First, modulo implementation artifacts (see Site Note 2), an ephemeral
> > > > value will have only droppable uses and vice versa.
> > > I think this is the key statement for my question on the patch. If we can
> > > simple define an ephemeral value as one which only has dropable transitive
> > > uses and is speculateable, I think a lot of things fall out.  In particular,
> > > we unify old and new code paths.
> > > 
> > > We could tweak the comments on CodeMetrics::collectEphemeralValues to make
> > > this obvious, or even assert that all of the operands are droppable uses.
> > > 
> > > > That said, I think ephemeral values, which seem to be mostly used as
> > > > ephemeral instructions, are an artifact of the instruction-based
> > > > `llvm.assume` encoding. As we move away from that, via explicit operand
> > > > bundle uses, it seems we should adapt the ephemeral machinery as well.
> > > > 
> > > > --- Site Note 1 -- Explicit use case for the droppable use interface.
> > > > 
> > > > Before I elaborate on the above, I want to mention that the droppable*
> > > > use interface can be used in places ephemeral values were not used
> > > > before, see https://reviews.llvm.org/D73832#C1850473NL395 for example.
> > > > 
> > > > * Name can be changed, e.g., to ephemeralUses as suggested by Roman now.
> > > I like this suggestion.  "emphemeral uses" and "emphemeral values" seems to
> > > be nice duality.
> > > > ---
> > > > 
> > > > I agree with you as that we should not duplicate functionality. However,
> > > > as I see it, there is actually little we can do about it "just now". The
> > > > `CodeMetrics::collectEphemeralValues` interface collects all ephemeral
> > > > values in a scope by searching outward from assumes; droppable uses is a
> > > > local property of an instruction. The way to reconcile the two is to
> > > > encode uses of values directly in the operand bundles. As we haven't
> > > > switched over to operand bundle assume uses for the assumptions we
> > > > generate automatically, e.g., `alignment`, it is hard to tell what
> > > > instructions will be left in the encoding.
> > > > Let's assume we will see a pattern like: `%i = op %a, %b; assume(%i);`.
> > > > I would like us to express this (directly or via rewriting) as
> > > > `assume(true) ["op"(%a,%b)]` instead. (Multi-instruction encodings can
> > > > be outlined as described in my llvm.assume RFC or encoded as special
> > > > tags if they are frequent enough.) Once we do this, ephemeral value
> > > > collection will become less useful to the point that we can replace it
> > > > by
> > > >    `bool isDroppable(I) { return isAssume(I) || hasOnlyDroppableUses(I);}`
> > > > potentially behind a lazy caching interface.
> > > > 
> > > > The direct encoding in operand bundles has other benefits as well. Even
> > > > if `%i` in the above example is not ephemeral, removing it's "ephemeral
> > > > uses" is arguably a normalization that clears the way for better cost
> > > > heuristics, e.g. the use-sensitive transformations in instcombine.
> > > > 
> > > > At the end of the day we should not need to analyze a lot of IR to
> > > > determine if something is *only* used by `llvm.assume` (and similar,
> > > > e.g. `llvm.lifetime`). I want us not to be cause it should make heavy
> > > > use of `llvm.assume` cheaper (see https://reviews.llvm.org/D75825).
> > > > 
> > > > 
> > > > --- Site Note 2 -- Implementation artifact of collectEphemeralValues.
> > > > 
> > > > FWIW, after looking at it it seems to be non-optimal as for example like
> > > > ```
> > > >     %c = add %a, %b
> > > >     call @llvm.assume(%c)
> > > >     call @llvm.assume(%a)
> > > > ```
> > > > the order of the assumes is important. If we move `%c` into an operand
> > > > bundle this should go away naturally:
> > > > ```
> > > >     call @llvm.assume(true) ["add"(%a, %b)]
> > > >     call @llvm.assume(%a)
> > > > ```
> > > > ---
> > > > 
> > > > I hope this makes sense. Please let me know if you have comments or
> > > > concerns with this plan :)
> > > It didn't.  But I believe it's also solidly out of scope for my actual
> > > question so that's okay.  :)
> > > > Thanks again for mentioning this, it is not more central on my radar!
> > > > 
> > > > Cheers,
> > > >     Johannes
> > > > 
> > > > 
> > > > > Philip
> > > > > 
> > > > > On 3/12/20 2:47 AM, via llvm-commits wrote:
> > > > > > Author: Tyker
> > > > > > Date: 2020-03-12T10:10:22+01:00
> > > > > > New Revision: f16f139db40e6bf6462ca831eb1ec423c50aeef2
> > > > > > 
> > > > > > URL: https://github.com/llvm/llvm-project/commit/f16f139db40e6bf6462ca831eb1ec423c50aeef2
> > > > > > DIFF: https://github.com/llvm/llvm-project/commit/f16f139db40e6bf6462ca831eb1ec423c50aeef2.diff
> > > > > > 
> > > > > > LOG: Basis of dropping uses in llvm.assume.
> > > > > > 
> > > > > > Summary: This patch adds the basic utilities to deal with dropable uses. dropable uses are uses that we rather drop than prevent transformations, for now they are limited to uses in llvm.assume.
> > > > > > 
> > > > > > Reviewers: jdoerfert, sstefan1
> > > > > > 
> > > > > > Reviewed By: jdoerfert
> > > > > > 
> > > > > > Subscribers: uenoku, lebedev.ri, mgorny, hiraditya, dexonsmith, llvm-commits
> > > > > > 
> > > > > > Tags: #llvm
> > > > > > 
> > > > > > Differential Revision: https://reviews.llvm.org/D73404
> > > > > > 
> > > > > > Added:
> > > > > > 
> > > > > > Modified:
> > > > > >        llvm/docs/LangRef.rst
> > > > > >        llvm/include/llvm/IR/User.h
> > > > > >        llvm/include/llvm/IR/Value.h
> > > > > >        llvm/lib/IR/KnowledgeRetention.cpp
> > > > > >        llvm/lib/IR/User.cpp
> > > > > >        llvm/lib/IR/Value.cpp
> > > > > >        llvm/lib/IR/Verifier.cpp
> > > > > >        llvm/unittests/IR/KnowledgeRetentionTest.cpp
> > > > > > 
> > > > > > Removed:
> > > > > > 
> > > > > > 
> > > > > > ################################################################################
> > > > > > diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
> > > > > > index 480a0fc4c07a..4db8aa1bc939 100644
> > > > > > --- a/llvm/docs/LangRef.rst
> > > > > > +++ b/llvm/docs/LangRef.rst
> > > > > > @@ -2119,8 +2119,9 @@ An assume operand bundle has the form:
> > > > > >           "<tag>"([ <holds for value> [, <attribute argument>] ])
> > > > > > -* The tag of the operand bundle is the name of attribute that can be assumed
> > > > > > -  to hold.
> > > > > > +* The tag of the operand bundle is usually the name of attribute that can be
> > > > > > +  assumed to hold. It can also be `ignore`, this tag doesn't contain any
> > > > > > +  information and should be ignored.
> > > > > >     * The first argument if present is the value for which the attribute hold.
> > > > > >     * The second argument if present is an argument of the attribute.
> > > > > > 
> > > > > > diff  --git a/llvm/include/llvm/IR/User.h b/llvm/include/llvm/IR/User.h
> > > > > > index 850ee72a0387..ebfae1db2980 100644
> > > > > > --- a/llvm/include/llvm/IR/User.h
> > > > > > +++ b/llvm/include/llvm/IR/User.h
> > > > > > @@ -218,6 +218,11 @@ class User : public Value {
> > > > > >         NumUserOperands = NumOps;
> > > > > >       }
> > > > > > +  /// A droppable user is a user for which uses can be dropped without affecting
> > > > > > +  /// correctness and should be dropped rather than preventing a transformation
> > > > > > +  /// from happening.
> > > > > > +  bool isDroppable() const;
> > > > > > +
> > > > > >       // ---------------------------------------------------------------------------
> > > > > >       // Operand Iterator interface...
> > > > > >       //
> > > > > > 
> > > > > > diff  --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h
> > > > > > index f2c4b3b3f203..0f9c335b5ba8 100644
> > > > > > --- a/llvm/include/llvm/IR/Value.h
> > > > > > +++ b/llvm/include/llvm/IR/Value.h
> > > > > > @@ -444,6 +444,34 @@ class Value {
> > > > > >       /// This is logically equivalent to getNumUses() >= N.
> > > > > >       bool hasNUsesOrMore(unsigned N) const;
> > > > > > +  /// Return true if there is exactly one user of this value that cannot be
> > > > > > +  /// dropped.
> > > > > > +  ///
> > > > > > +  /// This is specialized because it is a common request and does not require
> > > > > > +  /// traversing the whole use list.
> > > > > > +  Use *getSingleUndroppableUse();
> > > > > > +
> > > > > > +  /// Return true if there this value.
> > > > > > +  ///
> > > > > > +  /// This is specialized because it is a common request and does not require
> > > > > > +  /// traversing the whole use list.
> > > > > > +  bool hasNUndroppableUses(unsigned N) const;
> > > > > > +
> > > > > > +  /// Return true if this value has N users or more.
> > > > > > +  ///
> > > > > > +  /// This is logically equivalent to getNumUses() >= N.
> > > > > > +  bool hasNUndroppableUsesOrMore(unsigned N) const;
> > > > > > +
> > > > > > +  /// Remove every uses that can safely be removed.
> > > > > > +  ///
> > > > > > +  /// This will remove for example uses in llvm.assume.
> > > > > > +  /// This should be used when performing want to perform a tranformation but
> > > > > > +  /// some Droppable uses pervent it.
> > > > > > +  /// This function optionally takes a filter to only remove some droppable
> > > > > > +  /// uses.
> > > > > > +  void dropDroppableUses(llvm::function_ref<bool(const Use *)> ShouldDrop =
> > > > > > +                             [](const Use *) { return true; });
> > > > > > +
> > > > > >       /// Check if this value is used in the specified basic block.
> > > > > >       bool isUsedInBasicBlock(const BasicBlock *BB) const;
> > > > > > 
> > > > > > diff  --git a/llvm/lib/IR/KnowledgeRetention.cpp b/llvm/lib/IR/KnowledgeRetention.cpp
> > > > > > index fa2145012910..e87791137f4a 100644
> > > > > > --- a/llvm/lib/IR/KnowledgeRetention.cpp
> > > > > > +++ b/llvm/lib/IR/KnowledgeRetention.cpp
> > > > > > @@ -197,51 +197,27 @@ bool llvm::hasAttributeInAssume(CallInst &AssumeCI, Value *IsOn,
> > > > > >       if (Assume.bundle_op_infos().empty())
> > > > > >         return false;
> > > > > > -  CallInst::bundle_op_iterator Lookup;
> > > > > > -
> > > > > > -  /// The right attribute can be found by binary search. After this finding the
> > > > > > -  /// right WasOn needs to be done via linear search.
> > > > > > -  /// Element have been ordered by argument value so the first we find is the
> > > > > > -  /// one we need.
> > > > > > -  if (AQR == AssumeQuery::Lowest)
> > > > > > -    Lookup =
> > > > > > -        llvm::lower_bound(Assume.bundle_op_infos(), AttrName,
> > > > > > -                          [](const CallBase::BundleOpInfo &BOI, StringRef RHS) {
> > > > > > -                            return BOI.Tag->getKey() < RHS;
> > > > > > -                          });
> > > > > > -  else
> > > > > > -    Lookup = std::prev(
> > > > > > -        llvm::upper_bound(Assume.bundle_op_infos(), AttrName,
> > > > > > -                          [](StringRef LHS, const CallBase::BundleOpInfo &BOI) {
> > > > > > -                            return LHS < BOI.Tag->getKey();
> > > > > > -                          }));
> > > > > > -
> > > > > > -  if (Lookup == Assume.bundle_op_info_end() ||
> > > > > > -      Lookup->Tag->getKey() != AttrName)
> > > > > > -    return false;
> > > > > > -  if (IsOn) {
> > > > > > -    assert((Lookup->End - Lookup->Begin > BOIE_WasOn) &&
> > > > > > -           "missing argument of attribute");
> > > > > > -    while (true) {
> > > > > > -      if (Lookup == Assume.bundle_op_info_end() ||
> > > > > > -          Lookup->Tag->getKey() != AttrName)
> > > > > > -        return false;
> > > > > > -      if (getValueFromBundleOpInfo(Assume, *Lookup, BOIE_WasOn) == IsOn)
> > > > > > -        break;
> > > > > > -      if (AQR == AssumeQuery::Highest &&
> > > > > > -          Lookup == Assume.bundle_op_info_begin())
> > > > > > -        return false;
> > > > > > -      Lookup = Lookup + (AQR == AssumeQuery::Lowest ? 1 : -1);
> > > > > > +  auto Loop = [&](auto &&Range) {
> > > > > > +    for (auto &BOI : Range) {
> > > > > > +      if (BOI.Tag->getKey() != AttrName)
> > > > > > +        continue;
> > > > > > +      if (IsOn && (BOI.End - BOI.Begin <= BOIE_WasOn ||
> > > > > > +                   IsOn != getValueFromBundleOpInfo(Assume, BOI, BOIE_WasOn)))
> > > > > > +        continue;
> > > > > > +      if (ArgVal) {
> > > > > > +        assert(BOI.End - BOI.Begin > BOIE_Argument);
> > > > > > +        *ArgVal = cast<ConstantInt>(
> > > > > > +                      getValueFromBundleOpInfo(Assume, BOI, BOIE_Argument))
> > > > > > +                      ->getZExtValue();
> > > > > > +      }
> > > > > > +      return true;
> > > > > >         }
> > > > > > -  }
> > > > > > +    return false;
> > > > > > +  };
> > > > > > -  if (Lookup->End - Lookup->Begin < BOIE_Argument)
> > > > > > -    return true;
> > > > > > -  if (ArgVal)
> > > > > > -    *ArgVal = cast<ConstantInt>(
> > > > > > -                  getValueFromBundleOpInfo(Assume, *Lookup, BOIE_Argument))
> > > > > > -                  ->getZExtValue();
> > > > > > -  return true;
> > > > > > +  if (AQR == AssumeQuery::Lowest)
> > > > > > +    return Loop(Assume.bundle_op_infos());
> > > > > > +  return Loop(reverse(Assume.bundle_op_infos()));
> > > > > >     }
> > > > > >     void llvm::fillMapFromAssume(CallInst &AssumeCI, RetainedKnowledgeMap &Result) {
> > > > > > 
> > > > > > diff  --git a/llvm/lib/IR/User.cpp b/llvm/lib/IR/User.cpp
> > > > > > index 4a3eba9e8cf7..3097916c5152 100644
> > > > > > --- a/llvm/lib/IR/User.cpp
> > > > > > +++ b/llvm/lib/IR/User.cpp
> > > > > > @@ -9,6 +9,7 @@
> > > > > >     #include "llvm/IR/User.h"
> > > > > >     #include "llvm/IR/Constant.h"
> > > > > >     #include "llvm/IR/GlobalValue.h"
> > > > > > +#include "llvm/IR/IntrinsicInst.h"
> > > > > >     namespace llvm {
> > > > > >     class BasicBlock;
> > > > > > @@ -105,6 +106,12 @@ MutableArrayRef<uint8_t> User::getDescriptor() {
> > > > > >           reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
> > > > > >     }
> > > > > > +bool User::isDroppable() const {
> > > > > > +  if (const auto *Intr = dyn_cast<IntrinsicInst>(this))
> > > > > > +    return Intr->getIntrinsicID() == Intrinsic::assume;
> > > > > > +  return false;
> > > > > > +}
> > > > > > +
> > > > > >     //===----------------------------------------------------------------------===//
> > > > > >     //                         User operator new Implementations
> > > > > >     //===----------------------------------------------------------------------===//
> > > > > > 
> > > > > > diff  --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
> > > > > > index beb3989ebb56..8cd589759eab 100644
> > > > > > --- a/llvm/lib/IR/Value.cpp
> > > > > > +++ b/llvm/lib/IR/Value.cpp
> > > > > > @@ -141,6 +141,51 @@ bool Value::hasNUsesOrMore(unsigned N) const {
> > > > > >       return hasNItemsOrMore(use_begin(), use_end(), N);
> > > > > >     }
> > > > > > +static bool isUnDroppableUser(const User *U) { return !U->isDroppable(); }
> > > > > > +
> > > > > > +Use *Value::getSingleUndroppableUse() {
> > > > > > +  Use *Result = nullptr;
> > > > > > +  for (Use &U : uses()) {
> > > > > > +    if (!U.getUser()->isDroppable()) {
> > > > > > +      if (Result)
> > > > > > +        return nullptr;
> > > > > > +      Result = &U;
> > > > > > +    }
> > > > > > +  }
> > > > > > +  return Result;
> > > > > > +}
> > > > > > +
> > > > > > +bool Value::hasNUndroppableUses(unsigned int N) const {
> > > > > > +  return hasNItems(user_begin(), user_end(), N, isUnDroppableUser);
> > > > > > +}
> > > > > > +
> > > > > > +bool Value::hasNUndroppableUsesOrMore(unsigned int N) const {
> > > > > > +  return hasNItemsOrMore(user_begin(), user_end(), N, isUnDroppableUser);
> > > > > > +}
> > > > > > +
> > > > > > +void Value::dropDroppableUses(
> > > > > > +    llvm::function_ref<bool(const Use *)> ShouldDrop) {
> > > > > > +  SmallVector<Use *, 8> ToBeEdited;
> > > > > > +  for (Use &U : uses())
> > > > > > +    if (U.getUser()->isDroppable() && ShouldDrop(&U))
> > > > > > +      ToBeEdited.push_back(&U);
> > > > > > +  for (Use *U : ToBeEdited) {
> > > > > > +    U->removeFromList();
> > > > > > +    if (auto *Assume = dyn_cast<IntrinsicInst>(U->getUser())) {
> > > > > > +      assert(Assume->getIntrinsicID() == Intrinsic::assume);
> > > > > > +      unsigned OpNo = U->getOperandNo();
> > > > > > +      if (OpNo == 0)
> > > > > > +        Assume->setOperand(0, ConstantInt::getTrue(Assume->getContext()));
> > > > > > +      else {
> > > > > > +        Assume->setOperand(OpNo, UndefValue::get(U->get()->getType()));
> > > > > > +        CallInst::BundleOpInfo &BOI = Assume->getBundleOpInfoForOperand(OpNo);
> > > > > > +        BOI.Tag = getContext().pImpl->getOrInsertBundleTag("ignore");
> > > > > > +      }
> > > > > > +    } else
> > > > > > +      llvm_unreachable("unkown droppable use");
> > > > > > +  }
> > > > > > +}
> > > > > > +
> > > > > >     bool Value::isUsedInBasicBlock(const BasicBlock *BB) const {
> > > > > >       // This can be computed either by scanning the instructions in BB, or by
> > > > > >       // scanning the use list of this Value. Both lists can be very long, but
> > > > > > 
> > > > > > diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
> > > > > > index abd7a00193a8..676f98dae0bb 100644
> > > > > > --- a/llvm/lib/IR/Verifier.cpp
> > > > > > +++ b/llvm/lib/IR/Verifier.cpp
> > > > > > @@ -4322,7 +4322,8 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
> > > > > >         break;
> > > > > >       case Intrinsic::assume: {
> > > > > >         for (auto &Elem : Call.bundle_op_infos()) {
> > > > > > -      Assert(Attribute::isExistingAttribute(Elem.Tag->getKey()),
> > > > > > +      Assert(Elem.Tag->getKey() == "ignore" ||
> > > > > > +                 Attribute::isExistingAttribute(Elem.Tag->getKey()),
> > > > > >                  "tags must be valid attribute names");
> > > > > >           Assert(Elem.End - Elem.Begin <= 2, "to many arguments");
> > > > > >           Attribute::AttrKind Kind =
> > > > > > 
> > > > > > diff  --git a/llvm/unittests/IR/KnowledgeRetentionTest.cpp b/llvm/unittests/IR/KnowledgeRetentionTest.cpp
> > > > > > index 46f8c9346d6b..36c5e0341a15 100644
> > > > > > --- a/llvm/unittests/IR/KnowledgeRetentionTest.cpp
> > > > > > +++ b/llvm/unittests/IR/KnowledgeRetentionTest.cpp
> > > > > > @@ -25,21 +25,17 @@ static void RunTest(
> > > > > >         StringRef Head, StringRef Tail,
> > > > > >         std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
> > > > > >             &Tests) {
> > > > > > -  std::string IR;
> > > > > > -  IR.append(Head.begin(), Head.end());
> > > > > > -  for (auto &Elem : Tests)
> > > > > > +  for (auto &Elem : Tests) {
> > > > > > +    std::string IR;
> > > > > > +    IR.append(Head.begin(), Head.end());
> > > > > >         IR.append(Elem.first.begin(), Elem.first.end());
> > > > > > -  IR.append(Tail.begin(), Tail.end());
> > > > > > -  LLVMContext C;
> > > > > > -  SMDiagnostic Err;
> > > > > > -  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
> > > > > > -  if (!Mod)
> > > > > > -    Err.print("AssumeQueryAPI", errs());
> > > > > > -  unsigned Idx = 0;
> > > > > > -  for (Instruction &I : (*Mod->getFunction("test")->begin())) {
> > > > > > -    if (Idx < Tests.size())
> > > > > > -      Tests[Idx].second(&I);
> > > > > > -    Idx++;
> > > > > > +    IR.append(Tail.begin(), Tail.end());
> > > > > > +    LLVMContext C;
> > > > > > +    SMDiagnostic Err;
> > > > > > +    std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
> > > > > > +    if (!Mod)
> > > > > > +      Err.print("AssumeQueryAPI", errs());
> > > > > > +    Elem.second(&*(Mod->getFunction("test")->begin()->begin()));
> > > > > >       }
> > > > > >     }
> > > > > > @@ -199,7 +195,29 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
> > > > > >                                    Attribute::AttrKind::Dereferenceable, 12, true);
> > > > > >           }));
> > > > > > -  /// Keep this test last as it modifies the function.
> > > > > > +  Tests.push_back(std::make_pair(
> > > > > > +      "call void @func1(i32* readnone align 32 "
> > > > > > +      "dereferenceable(48) noalias %P, i32* "
> > > > > > +      "align 8 dereferenceable(28) %P1, i32* align 64 "
> > > > > > +      "dereferenceable(4) "
> > > > > > +      "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
> > > > > > +      [](Instruction *I) {
> > > > > > +        CallInst *Assume = BuildAssumeFromInst(I);
> > > > > > +        Assume->insertBefore(I);
> > > > > > +        I->getOperand(1)->dropDroppableUses();
> > > > > > +        I->getOperand(2)->dropDroppableUses();
> > > > > > +        I->getOperand(3)->dropDroppableUses();
> > > > > > +        AssertMatchesExactlyAttributes(
> > > > > > +            Assume, I->getOperand(0),
> > > > > > +            "(readnone|align|dereferenceable|noalias)");
> > > > > > +        AssertMatchesExactlyAttributes(Assume, I->getOperand(1), "");
> > > > > > +        AssertMatchesExactlyAttributes(Assume, I->getOperand(2), "");
> > > > > > +        AssertMatchesExactlyAttributes(Assume, I->getOperand(3), "");
> > > > > > +        AssertHasTheRightValue(Assume, I->getOperand(0),
> > > > > > +                               Attribute::AttrKind::Alignment, 32, true);
> > > > > > +        AssertHasTheRightValue(Assume, I->getOperand(0),
> > > > > > +                               Attribute::AttrKind::Dereferenceable, 48, true);
> > > > > > +      }));
> > > > > >       Tests.push_back(std::make_pair(
> > > > > >           "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
> > > > > >           "8 noalias %P1)\n",
> > > > > > 
> > > > > > 
> > > > > > _______________________________________________
> > > > > > llvm-commits mailing list
> > > > > > llvm-commits at lists.llvm.org
> > > > > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> > > > > _______________________________________________
> > > > > llvm-commits mailing list
> > > > > llvm-commits at lists.llvm.org
> > > > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits

-- 

Johannes Doerfert
Researcher

Argonne National Laboratory
Lemont, IL 60439, USA

jdoerfert at anl.gov
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200313/ff69f8a3/attachment.sig>


More information about the llvm-commits mailing list