|  | //=====- CFLSummary.h - Abstract stratified sets implementation. --------=====// | 
|  | // | 
|  | // 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// \file | 
|  | /// This file defines various utility types and functions useful to | 
|  | /// summary-based alias analysis. | 
|  | /// | 
|  | /// Summary-based analysis, also known as bottom-up analysis, is a style of | 
|  | /// interprocedrual static analysis that tries to analyze the callees before the | 
|  | /// callers get analyzed. The key idea of summary-based analysis is to first | 
|  | /// process each function independently, outline its behavior in a condensed | 
|  | /// summary, and then instantiate the summary at the callsite when the said | 
|  | /// function is called elsewhere. This is often in contrast to another style | 
|  | /// called top-down analysis, in which callers are always analyzed first before | 
|  | /// the callees. | 
|  | /// | 
|  | /// In a summary-based analysis, functions must be examined independently and | 
|  | /// out-of-context. We have no information on the state of the memory, the | 
|  | /// arguments, the global values, and anything else external to the function. To | 
|  | /// carry out the analysis conservative assumptions have to be made about those | 
|  | /// external states. In exchange for the potential loss of precision, the | 
|  | /// summary we obtain this way is highly reusable, which makes the analysis | 
|  | /// easier to scale to large programs even if carried out context-sensitively. | 
|  | /// | 
|  | /// Currently, all CFL-based alias analyses adopt the summary-based approach | 
|  | /// and therefore heavily rely on this header. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H | 
|  | #define LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H | 
|  |  | 
|  | #include "llvm/ADT/DenseMapInfo.h" | 
|  | #include "llvm/ADT/Optional.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/IR/InstrTypes.h" | 
|  | #include <bitset> | 
|  |  | 
|  | namespace llvm { | 
|  | namespace cflaa { | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // AliasAttr related stuffs | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// The number of attributes that AliasAttr should contain. Attributes are | 
|  | /// described below, and 32 was an arbitrary choice because it fits nicely in 32 | 
|  | /// bits (because we use a bitset for AliasAttr). | 
|  | static const unsigned NumAliasAttrs = 32; | 
|  |  | 
|  | /// These are attributes that an alias analysis can use to mark certain special | 
|  | /// properties of a given pointer. Refer to the related functions below to see | 
|  | /// what kinds of attributes are currently defined. | 
|  | typedef std::bitset<NumAliasAttrs> AliasAttrs; | 
|  |  | 
|  | /// Attr represent whether the said pointer comes from an unknown source | 
|  | /// (such as opaque memory or an integer cast). | 
|  | AliasAttrs getAttrNone(); | 
|  |  | 
|  | /// AttrUnknown represent whether the said pointer comes from a source not known | 
|  | /// to alias analyses (such as opaque memory or an integer cast). | 
|  | AliasAttrs getAttrUnknown(); | 
|  | bool hasUnknownAttr(AliasAttrs); | 
|  |  | 
|  | /// AttrCaller represent whether the said pointer comes from a source not known | 
|  | /// to the current function but known to the caller. Values pointed to by the | 
|  | /// arguments of the current function have this attribute set | 
|  | AliasAttrs getAttrCaller(); | 
|  | bool hasCallerAttr(AliasAttrs); | 
|  | bool hasUnknownOrCallerAttr(AliasAttrs); | 
|  |  | 
|  | /// AttrEscaped represent whether the said pointer comes from a known source but | 
|  | /// escapes to the unknown world (e.g. casted to an integer, or passed as an | 
|  | /// argument to opaque function). Unlike non-escaped pointers, escaped ones may | 
|  | /// alias pointers coming from unknown sources. | 
|  | AliasAttrs getAttrEscaped(); | 
|  | bool hasEscapedAttr(AliasAttrs); | 
|  |  | 
|  | /// AttrGlobal represent whether the said pointer is a global value. | 
|  | /// AttrArg represent whether the said pointer is an argument, and if so, what | 
|  | /// index the argument has. | 
|  | AliasAttrs getGlobalOrArgAttrFromValue(const Value &); | 
|  | bool isGlobalOrArgAttr(AliasAttrs); | 
|  |  | 
|  | /// Given an AliasAttrs, return a new AliasAttrs that only contains attributes | 
|  | /// meaningful to the caller. This function is primarily used for | 
|  | /// interprocedural analysis | 
|  | /// Currently, externally visible AliasAttrs include AttrUnknown, AttrGlobal, | 
|  | /// and AttrEscaped | 
|  | AliasAttrs getExternallyVisibleAttrs(AliasAttrs); | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // Function summary related stuffs | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// The maximum number of arguments we can put into a summary. | 
|  | static const unsigned MaxSupportedArgsInSummary = 50; | 
|  |  | 
|  | /// We use InterfaceValue to describe parameters/return value, as well as | 
|  | /// potential memory locations that are pointed to by parameters/return value, | 
|  | /// of a function. | 
|  | /// Index is an integer which represents a single parameter or a return value. | 
|  | /// When the index is 0, it refers to the return value. Non-zero index i refers | 
|  | /// to the i-th parameter. | 
|  | /// DerefLevel indicates the number of dereferences one must perform on the | 
|  | /// parameter/return value to get this InterfaceValue. | 
|  | struct InterfaceValue { | 
|  | unsigned Index; | 
|  | unsigned DerefLevel; | 
|  | }; | 
|  |  | 
|  | inline bool operator==(InterfaceValue LHS, InterfaceValue RHS) { | 
|  | return LHS.Index == RHS.Index && LHS.DerefLevel == RHS.DerefLevel; | 
|  | } | 
|  | inline bool operator!=(InterfaceValue LHS, InterfaceValue RHS) { | 
|  | return !(LHS == RHS); | 
|  | } | 
|  | inline bool operator<(InterfaceValue LHS, InterfaceValue RHS) { | 
|  | return LHS.Index < RHS.Index || | 
|  | (LHS.Index == RHS.Index && LHS.DerefLevel < RHS.DerefLevel); | 
|  | } | 
|  | inline bool operator>(InterfaceValue LHS, InterfaceValue RHS) { | 
|  | return RHS < LHS; | 
|  | } | 
|  | inline bool operator<=(InterfaceValue LHS, InterfaceValue RHS) { | 
|  | return !(RHS < LHS); | 
|  | } | 
|  | inline bool operator>=(InterfaceValue LHS, InterfaceValue RHS) { | 
|  | return !(LHS < RHS); | 
|  | } | 
|  |  | 
|  | // We use UnknownOffset to represent pointer offsets that cannot be determined | 
|  | // at compile time. Note that MemoryLocation::UnknownSize cannot be used here | 
|  | // because we require a signed value. | 
|  | static const int64_t UnknownOffset = INT64_MAX; | 
|  |  | 
|  | inline int64_t addOffset(int64_t LHS, int64_t RHS) { | 
|  | if (LHS == UnknownOffset || RHS == UnknownOffset) | 
|  | return UnknownOffset; | 
|  | // FIXME: Do we need to guard against integer overflow here? | 
|  | return LHS + RHS; | 
|  | } | 
|  |  | 
|  | /// We use ExternalRelation to describe an externally visible aliasing relations | 
|  | /// between parameters/return value of a function. | 
|  | struct ExternalRelation { | 
|  | InterfaceValue From, To; | 
|  | int64_t Offset; | 
|  | }; | 
|  |  | 
|  | inline bool operator==(ExternalRelation LHS, ExternalRelation RHS) { | 
|  | return LHS.From == RHS.From && LHS.To == RHS.To && LHS.Offset == RHS.Offset; | 
|  | } | 
|  | inline bool operator!=(ExternalRelation LHS, ExternalRelation RHS) { | 
|  | return !(LHS == RHS); | 
|  | } | 
|  | inline bool operator<(ExternalRelation LHS, ExternalRelation RHS) { | 
|  | if (LHS.From < RHS.From) | 
|  | return true; | 
|  | if (LHS.From > RHS.From) | 
|  | return false; | 
|  | if (LHS.To < RHS.To) | 
|  | return true; | 
|  | if (LHS.To > RHS.To) | 
|  | return false; | 
|  | return LHS.Offset < RHS.Offset; | 
|  | } | 
|  | inline bool operator>(ExternalRelation LHS, ExternalRelation RHS) { | 
|  | return RHS < LHS; | 
|  | } | 
|  | inline bool operator<=(ExternalRelation LHS, ExternalRelation RHS) { | 
|  | return !(RHS < LHS); | 
|  | } | 
|  | inline bool operator>=(ExternalRelation LHS, ExternalRelation RHS) { | 
|  | return !(LHS < RHS); | 
|  | } | 
|  |  | 
|  | /// We use ExternalAttribute to describe an externally visible AliasAttrs | 
|  | /// for parameters/return value. | 
|  | struct ExternalAttribute { | 
|  | InterfaceValue IValue; | 
|  | AliasAttrs Attr; | 
|  | }; | 
|  |  | 
|  | /// AliasSummary is just a collection of ExternalRelation and ExternalAttribute | 
|  | struct AliasSummary { | 
|  | // RetParamRelations is a collection of ExternalRelations. | 
|  | SmallVector<ExternalRelation, 8> RetParamRelations; | 
|  |  | 
|  | // RetParamAttributes is a collection of ExternalAttributes. | 
|  | SmallVector<ExternalAttribute, 8> RetParamAttributes; | 
|  | }; | 
|  |  | 
|  | /// This is the result of instantiating InterfaceValue at a particular call | 
|  | struct InstantiatedValue { | 
|  | Value *Val; | 
|  | unsigned DerefLevel; | 
|  | }; | 
|  | Optional<InstantiatedValue> instantiateInterfaceValue(InterfaceValue IValue, | 
|  | CallBase &Call); | 
|  |  | 
|  | inline bool operator==(InstantiatedValue LHS, InstantiatedValue RHS) { | 
|  | return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel; | 
|  | } | 
|  | inline bool operator!=(InstantiatedValue LHS, InstantiatedValue RHS) { | 
|  | return !(LHS == RHS); | 
|  | } | 
|  | inline bool operator<(InstantiatedValue LHS, InstantiatedValue RHS) { | 
|  | return std::less<Value *>()(LHS.Val, RHS.Val) || | 
|  | (LHS.Val == RHS.Val && LHS.DerefLevel < RHS.DerefLevel); | 
|  | } | 
|  | inline bool operator>(InstantiatedValue LHS, InstantiatedValue RHS) { | 
|  | return RHS < LHS; | 
|  | } | 
|  | inline bool operator<=(InstantiatedValue LHS, InstantiatedValue RHS) { | 
|  | return !(RHS < LHS); | 
|  | } | 
|  | inline bool operator>=(InstantiatedValue LHS, InstantiatedValue RHS) { | 
|  | return !(LHS < RHS); | 
|  | } | 
|  |  | 
|  | /// This is the result of instantiating ExternalRelation at a particular | 
|  | /// callsite | 
|  | struct InstantiatedRelation { | 
|  | InstantiatedValue From, To; | 
|  | int64_t Offset; | 
|  | }; | 
|  | Optional<InstantiatedRelation> | 
|  | instantiateExternalRelation(ExternalRelation ERelation, CallBase &Call); | 
|  |  | 
|  | /// This is the result of instantiating ExternalAttribute at a particular | 
|  | /// callsite | 
|  | struct InstantiatedAttr { | 
|  | InstantiatedValue IValue; | 
|  | AliasAttrs Attr; | 
|  | }; | 
|  | Optional<InstantiatedAttr> instantiateExternalAttribute(ExternalAttribute EAttr, | 
|  | CallBase &Call); | 
|  | } | 
|  |  | 
|  | template <> struct DenseMapInfo<cflaa::InstantiatedValue> { | 
|  | static inline cflaa::InstantiatedValue getEmptyKey() { | 
|  | return cflaa::InstantiatedValue{DenseMapInfo<Value *>::getEmptyKey(), | 
|  | DenseMapInfo<unsigned>::getEmptyKey()}; | 
|  | } | 
|  | static inline cflaa::InstantiatedValue getTombstoneKey() { | 
|  | return cflaa::InstantiatedValue{DenseMapInfo<Value *>::getTombstoneKey(), | 
|  | DenseMapInfo<unsigned>::getTombstoneKey()}; | 
|  | } | 
|  | static unsigned getHashValue(const cflaa::InstantiatedValue &IV) { | 
|  | return DenseMapInfo<std::pair<Value *, unsigned>>::getHashValue( | 
|  | std::make_pair(IV.Val, IV.DerefLevel)); | 
|  | } | 
|  | static bool isEqual(const cflaa::InstantiatedValue &LHS, | 
|  | const cflaa::InstantiatedValue &RHS) { | 
|  | return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel; | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | #endif |