//===- AssumeBundleQueries.h - utilities to query assume bundles *- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contain tools to query into assume bundles. assume bundles can be // built using utilities from Transform/Utils/AssumeBundleBuilder.h // //===----------------------------------------------------------------------===// #ifndef LLVM_TRANSFORMS_UTILS_ASSUMEBUNDLEQUERIES_H #define LLVM_TRANSFORMS_UTILS_ASSUMEBUNDLEQUERIES_H #include "llvm/IR/Attributes.h" #include "llvm/IR/Instructions.h" #include "llvm/ADT/DenseMap.h" namespace llvm { class IntrinsicInst; /// Index of elements in the operand bundle. /// If the element exist it is guaranteed to be what is specified in this enum /// but it may not exist. enum AssumeBundleArg { ABA_WasOn = 0, ABA_Argument = 1, }; /// It is possible to have multiple Value for the argument of an attribute in /// the same llvm.assume on the same llvm::Value. This is rare but need to be /// dealt with. enum class AssumeQuery { Highest, ///< Take the highest value available. Lowest, ///< Take the lowest value available. }; /// Query the operand bundle of an llvm.assume to find a single attribute of /// the specified kind applied on a specified Value. /// /// This has a non-constant complexity. It should only be used when a single /// attribute is going to be queried. /// /// Return true iff the queried attribute was found. /// If ArgVal is set. the argument will be stored to ArgVal. bool hasAttributeInAssume(CallInst &AssumeCI, Value *IsOn, StringRef AttrName, uint64_t *ArgVal = nullptr, AssumeQuery AQR = AssumeQuery::Highest); inline bool hasAttributeInAssume(CallInst &AssumeCI, Value *IsOn, Attribute::AttrKind Kind, uint64_t *ArgVal = nullptr, AssumeQuery AQR = AssumeQuery::Highest) { return hasAttributeInAssume( AssumeCI, IsOn, Attribute::getNameFromAttrKind(Kind), ArgVal, AQR); } template<> struct DenseMapInfo { static Attribute::AttrKind getEmptyKey() { return Attribute::EmptyKey; } static Attribute::AttrKind getTombstoneKey() { return Attribute::TombstoneKey; } static unsigned getHashValue(Attribute::AttrKind AK) { return hash_combine(AK); } static bool isEqual(Attribute::AttrKind LHS, Attribute::AttrKind RHS) { return LHS == RHS; } }; /// The map Key contains the Value on for which the attribute is valid and /// the Attribute that is valid for that value. /// If the Attribute is not on any value, the Value is nullptr. using RetainedKnowledgeKey = std::pair; struct MinMax { unsigned Min; unsigned Max; }; /// A mapping from intrinsics (=`llvm.assume` calls) to a value range /// (=knowledge) that is encoded in them. How the value range is interpreted /// depends on the RetainedKnowledgeKey that was used to get this out of the /// RetainedKnowledgeMap. using Assume2KnowledgeMap = DenseMap; using RetainedKnowledgeMap = DenseMap; /// Insert into the map all the informations contained in the operand bundles of /// the llvm.assume. This should be used instead of hasAttributeInAssume when /// many queries are going to be made on the same llvm.assume. /// String attributes are not inserted in the map. /// If the IR changes the map will be outdated. void fillMapFromAssume(CallInst &AssumeCI, RetainedKnowledgeMap &Result); /// Represent one information held inside an operand bundle of an llvm.assume. /// AttrKind is the property that hold. /// WasOn if not null is that Value for which AttrKind holds. /// ArgValue is optionally an argument. struct RetainedKnowledge { Attribute::AttrKind AttrKind = Attribute::None; Value *WasOn = nullptr; unsigned ArgValue = 0; }; /// Retreive the information help by Assume on the operand at index Idx. /// Assume should be an llvm.assume and Idx should be in the operand bundle. RetainedKnowledge getKnowledgeFromOperandInAssume(CallInst &Assume, unsigned Idx); /// Retreive the information help by the Use U of an llvm.assume. the use should /// be in the operand bundle. inline RetainedKnowledge getKnowledgeFromUseInAssume(const Use *U) { return getKnowledgeFromOperandInAssume(*cast(U->getUser()), U->getOperandNo()); } /// Return true iff the operand bundles of the provided llvm.assume doesn't /// contain any valuable information. This is true when: /// - The operand bundle is empty /// - The operand bundle only contains information about dropped values or /// constant folded values. /// /// the argument to the call of llvm.assume may still be useful even if the /// function returned true. bool isAssumeWithEmptyBundle(CallInst &Assume); } // namespace llvm #endif