2020-04-02 13:41:24 +02:00
|
|
|
//===- AssumeBundleQueries.h - utilities to query assume bundles *- C++ -*-===//
|
2020-02-02 14:46:59 +01:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2020-04-02 13:41:24 +02:00
|
|
|
// This file contain tools to query into assume bundles. assume bundles can be
|
|
|
|
// built using utilities from Transform/Utils/AssumeBundleBuilder.h
|
2020-02-02 14:46:59 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-02 13:41:24 +02:00
|
|
|
#ifndef LLVM_TRANSFORMS_UTILS_ASSUMEBUNDLEQUERIES_H
|
|
|
|
#define LLVM_TRANSFORMS_UTILS_ASSUMEBUNDLEQUERIES_H
|
2020-02-02 14:46:59 +01:00
|
|
|
|
2020-02-18 19:06:30 +01:00
|
|
|
#include "llvm/IR/Attributes.h"
|
2020-04-02 13:41:24 +02:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2020-03-03 13:24:16 +01:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2020-02-02 14:46:59 +01:00
|
|
|
|
|
|
|
namespace llvm {
|
2020-02-20 09:06:48 +01:00
|
|
|
class IntrinsicInst;
|
2020-02-02 14:46:59 +01:00
|
|
|
|
2020-04-02 13:41:24 +02:00
|
|
|
/// 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,
|
|
|
|
};
|
|
|
|
|
2020-02-18 19:06:30 +01:00
|
|
|
/// 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);
|
|
|
|
}
|
|
|
|
|
2020-03-03 13:24:16 +01:00
|
|
|
template<> struct DenseMapInfo<Attribute::AttrKind> {
|
|
|
|
static Attribute::AttrKind getEmptyKey() {
|
2020-03-03 17:42:57 +01:00
|
|
|
return Attribute::EmptyKey;
|
2020-03-03 13:24:16 +01:00
|
|
|
}
|
|
|
|
static Attribute::AttrKind getTombstoneKey() {
|
2020-03-03 17:42:57 +01:00
|
|
|
return Attribute::TombstoneKey;
|
2020-03-03 13:24:16 +01:00
|
|
|
}
|
|
|
|
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<Value *, Attribute::AttrKind>;
|
|
|
|
|
|
|
|
struct MinMax {
|
|
|
|
unsigned Min;
|
|
|
|
unsigned Max;
|
|
|
|
};
|
|
|
|
|
2020-02-20 09:06:48 +01:00
|
|
|
/// 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<IntrinsicInst *, MinMax>;
|
|
|
|
|
|
|
|
using RetainedKnowledgeMap =
|
|
|
|
DenseMap<RetainedKnowledgeKey, Assume2KnowledgeMap>;
|
2020-03-03 13:24:16 +01:00
|
|
|
|
|
|
|
/// 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);
|
2020-02-18 19:06:30 +01:00
|
|
|
|
2020-03-07 18:00:05 +01:00
|
|
|
/// 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<CallInst>(U->getUser()),
|
|
|
|
U->getOperandNo());
|
|
|
|
}
|
|
|
|
|
2020-03-17 11:28:10 +01:00
|
|
|
/// 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);
|
|
|
|
|
2020-02-02 14:46:59 +01:00
|
|
|
} // namespace llvm
|
|
|
|
|
|
|
|
#endif
|