Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'development' into out-of-tree
Browse files Browse the repository at this point in the history
fabianbs96 authored Dec 13, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 3b6b319 + 61b3a30 commit 263b016
Showing 15 changed files with 3,775 additions and 128 deletions.
2 changes: 1 addition & 1 deletion Config.cmake.in
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ foreach(component ${phasar_FIND_COMPONENTS})
list(APPEND PHASAR_NEEDED_LIBS phasar::${component})
endforeach()

if (phasar_FOUND)
if (NOT DEFINED phasar_FOUND OR phasar_FOUND EQUAL TRUE)
foreach(component ${phasar_FIND_COMPONENTS})
# For backwards compatibility -- will be removed with next release
add_library(phasar::phasar_${component} ALIAS phasar::${component})
97 changes: 73 additions & 24 deletions include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h
Original file line number Diff line number Diff line change
@@ -33,107 +33,156 @@ class Module;

namespace psr {

class GeneralStatistics {
private:
friend class GeneralStatisticsAnalysis;
struct GeneralStatistics {

size_t Functions = 0;
size_t ExternalFunctions = 0;
size_t FunctionDefinitions = 0;
size_t AddressTakenFunctions = 0;
size_t Globals = 0;
size_t GlobalConsts = 0;
size_t ExternalGlobals = 0;
size_t GlobalsDefinitions = 0;
size_t BasicBlocks = 0;
size_t AllocationSites = 0;
size_t CallSites = 0;
size_t DebugIntrinsics = 0;
size_t Instructions = 0;
size_t StoreInstructions = 0;
size_t LoadInstructions = 0;
size_t MemIntrinsics = 0;
size_t GlobalPointers = 0;
size_t Branches = 0;
size_t Switches = 0;
size_t GetElementPtrs = 0;
size_t LandingPads = 0;
size_t PhiNodes = 0;
size_t GlobalConsts = 0;
size_t NumInlineAsm = 0;
size_t IndCalls = 0;
size_t TotalNumOperands = 0;
size_t TotalNumUses = 0;
size_t TotalNumPredecessorBBs = 0;
size_t TotalNumSuccessorBBs = 0;
size_t MaxNumOperands = 0;
size_t MaxNumUses = 0;
size_t MaxNumPredecessorBBs = 0;
size_t MaxNumSuccessorBBs = 0;
size_t NumInstWithMultipleUses = 0;
size_t NumInstsUsedOutsideBB = 0;
size_t NonVoidInsts = 0;
std::set<const llvm::Type *> AllocatedTypes;
std::set<const llvm::Instruction *> AllocaInstructions;
std::set<const llvm::Instruction *> RetResInstructions;
std::string ModuleName = "";
std::string ModuleName{};

public:
/**
* @brief Returns the number of Allocation sites.
*/
[[nodiscard]] size_t getAllocationsites() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use AllocationSites instead")]] size_t
getAllocationsites() const;

/**
* @brief Returns the number of Function calls.
*/
[[nodiscard]] size_t getFunctioncalls() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use CallSites instead")]] size_t
getFunctioncalls() const;

/**
* @brief Returns the number of Instructions.
*/
[[nodiscard]] size_t getInstructions() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use Instructions instead")]] size_t
getInstructions() const;

/**
* @brief Returns the number of global pointers.
*/
[[nodiscard]] size_t getGlobalPointers() const;
[[nodiscard]] [[deprecated(
"All globals are pointers. Use Globals instead")]] size_t
getGlobalPointers() const;

/**
* @brief Returns the number of basic blocks.
*/
[[nodiscard]] size_t getBasicBlocks() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use BasicBlocks instead")]] size_t
getBasicBlocks() const;

/**
* @brief Returns the number of functions.
*/
[[nodiscard]] size_t getFunctions() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use Functions instead")]] size_t
getFunctions() const;

/**
* @brief Returns the number of globals.
*/
[[nodiscard]] size_t getGlobals() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use Globals instead")]] size_t
getGlobals() const;

/**
* @brief Returns the number of constant globals.
*/
[[nodiscard]] size_t getGlobalConsts() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use GlobalConsts instead")]] size_t
getGlobalConsts() const;

/**
* @brief Returns the number of memory intrinsics.
*/
[[nodiscard]] size_t getMemoryIntrinsics() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use MemIntrinsics instead")]] size_t
getMemoryIntrinsics() const;

/**
* @brief Returns the number of store instructions.
*/
[[nodiscard]] size_t getStoreInstructions() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use StoreInstructions instead")]] size_t
getStoreInstructions() const;

/**
* @brief Returns the number of load instructions.
*/
[[nodiscard]] size_t getLoadInstructions();
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use LoadInstructions instead; this "
"function seems to be broken anyway")]] size_t
getLoadInstructions();

/**
* @brief Returns all possible Types.
*/
[[nodiscard]] const std::set<const llvm::Type *> &getAllocatedTypes() const;
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use AllocatedTypes instead")]] const std::
set<const llvm::Type *> &
getAllocatedTypes() const;

/**
* @brief Returns all stack and heap allocating instructions.
*/
[[nodiscard]] const std::set<const llvm::Instruction *> &
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use AllocaInstructions "
"instead")]] const std::set<const llvm::Instruction *> &
getAllocaInstructions() const;

/**
* @brief Returns all Return and Resume Instructions.
*/
[[nodiscard]] const std::set<const llvm::Instruction *> &
[[nodiscard]] [[deprecated(
"Getters are no longer needed. Use RetResInstructions "
"instead")]] const std::set<const llvm::Instruction *> &
getRetResInstructions() const;

[[nodiscard]] nlohmann::json getAsJson() const;
void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const;

friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const GeneralStatistics &Statistics);
};

llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const GeneralStatistics &Statistics);

/**
* This class uses the Module Pass Mechanism of LLVM to compute
* some statistics about a Module. This includes the number of
343 changes: 242 additions & 101 deletions lib/PhasarLLVM/Passes/GeneralStatisticsAnalysis.cpp

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -18,8 +18,6 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/CFLAndersAliasAnalysis.h"
#include "llvm/Analysis/CFLSteensAliasAnalysis.h"
#include "llvm/Analysis/ScopedNoAliasAA.h"
#include "llvm/Analysis/TypeBasedAliasAnalysis.h"
#include "llvm/IR/Argument.h"
@@ -32,6 +30,9 @@
#include "llvm/IR/Verifier.h"
#include "llvm/Passes/PassBuilder.h"

#include "external/llvm/CFLAndersAliasAnalysis.h"
#include "external/llvm/CFLSteensAliasAnalysis.h"

using namespace psr;

namespace psr {
278 changes: 278 additions & 0 deletions lib/PhasarLLVM/Pointer/external/LLVM-LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


---- LLVM Exceptions to the Apache 2.0 License ----

As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.

In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.

==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.

==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
University of Illinois/NCSA
Open Source License

Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
All rights reserved.

Developed by:

LLVM Team

University of Illinois at Urbana-Champaign

http://llvm.org

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.

* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
10 changes: 10 additions & 0 deletions lib/PhasarLLVM/Pointer/external/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# External LLVM

All files in the `llvm` subfolder are 1:1 copied from LLVM 14.0.6 and are subject to the LLVM license.
You can find a copy of the LLVM license [here](./LLVM-LICENSE.txt).

Note that we needed to copy these files, as LLVM removed them in the transition from version 14 to 15.
To avoid LLVM from blocking PhASAR releases, we provide these files ourselves as a *temporary solution*.

We, as the PhASAR development core team, do not aim for maintaining the here provided LLVM code and will not add any modifications to it (bugfixes, enhancements, etc.).
Rather, we will add a custom replacement eventually.
269 changes: 269 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/AliasAnalysisSummary.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
//=====- 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 <bitset>

namespace llvm {

class CallBase;
class Value;

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);
} // namespace cflaa

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;
}
};
} // namespace llvm

#endif
57 changes: 57 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/CFLAliasAnalysisUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//=- CFLAliasAnalysisUtils.h - Utilities for CFL Alias Analysis ----*- 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
//
//===----------------------------------------------------------------------===//
// \file
// These are the utilities/helpers used by the CFL Alias Analyses available in
// tree, i.e. Steensgaard's and Andersens'.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H
#define LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H

#include "llvm/IR/Function.h"
#include "llvm/IR/ValueHandle.h"

namespace llvm {
namespace cflaa {

template <typename AAResult> struct FunctionHandle final : public CallbackVH {
FunctionHandle(Function *Fn, AAResult *Result)
: CallbackVH(Fn), Result(Result) {
assert(Fn != nullptr);
assert(Result != nullptr);
}

void deleted() override { removeSelfFromCache(); }
void allUsesReplacedWith(Value *) override { removeSelfFromCache(); }

private:
AAResult *Result;

void removeSelfFromCache() {
assert(Result != nullptr);
auto *Val = getValPtr();
Result->evict(cast<Function>(Val));
setValPtr(nullptr);
}
};

static inline const Function *parentFunctionOfValue(const Value *Val) {
if (auto *Inst = dyn_cast<Instruction>(Val)) {
auto *Bb = Inst->getParent();
return Bb->getParent();
}

if (auto *Arg = dyn_cast<Argument>(Val))
return Arg->getParent();
return nullptr;
}
} // namespace cflaa
} // namespace llvm

#endif // LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H
934 changes: 934 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.cpp

Large diffs are not rendered by default.

128 changes: 128 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/CFLAndersAliasAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//==- CFLAndersAliasAnalysis.h - Unification-based Alias Analysis -*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This is the interface for LLVM's inclusion-based alias analysis
/// implemented with CFL graph reachability.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H
#define LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CFLAliasAnalysisUtils.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"

#include <forward_list>
#include <memory>

namespace llvm {

class Function;
class MemoryLocation;
class TargetLibraryInfo;

namespace cflaa {

struct AliasSummary;

} // end namespace cflaa

class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
friend AAResultBase<CFLAndersAAResult>;

class FunctionInfo;

public:
explicit CFLAndersAAResult(
std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
CFLAndersAAResult(CFLAndersAAResult &&RHS);
~CFLAndersAAResult();

/// Handle invalidation events from the new pass manager.
/// By definition, this result is stateless and so remains valid.
bool invalidate(Function &, const PreservedAnalyses &,
FunctionAnalysisManager::Invalidator &) {
return false;
}

/// Evict the given function from cache
void evict(const Function *Fn);

/// Get the alias summary for the given function
/// Return nullptr if the summary is not found or not available
const cflaa::AliasSummary *getAliasSummary(const Function &);

AliasResult query(const MemoryLocation &, const MemoryLocation &);
AliasResult alias(const MemoryLocation &, const MemoryLocation &,
AAQueryInfo &);

private:
/// Ensures that the given function is available in the cache.
/// Returns the appropriate entry from the cache.
const Optional<FunctionInfo> &ensureCached(const Function &);

/// Inserts the given Function into the cache.
void scan(const Function &);

/// Build summary for a given function
FunctionInfo buildInfoFrom(const Function &);

std::function<const TargetLibraryInfo &(Function &F)> GetTLI;

/// Cached mapping of Functions to their StratifiedSets.
/// If a function's sets are currently being built, it is marked
/// in the cache as an Optional without a value. This way, if we
/// have any kind of recursion, it is discernable from a function
/// that simply has empty sets.
DenseMap<const Function *, Optional<FunctionInfo>> Cache;

std::forward_list<cflaa::FunctionHandle<CFLAndersAAResult>> Handles;
};

/// Analysis pass providing a never-invalidated alias analysis result.
///
/// FIXME: We really should refactor CFL to use the analysis more heavily, and
/// in particular to leverage invalidation to trigger re-computation.
class CFLAndersAA : public AnalysisInfoMixin<CFLAndersAA> {
friend AnalysisInfoMixin<CFLAndersAA>;

static AnalysisKey Key;

public:
using Result = CFLAndersAAResult;

CFLAndersAAResult run(Function &F, FunctionAnalysisManager &AM);
};

/// Legacy wrapper pass to provide the CFLAndersAAResult object.
class CFLAndersAAWrapperPass : public ImmutablePass {
std::unique_ptr<CFLAndersAAResult> Result;

public:
static char ID;

CFLAndersAAWrapperPass();

CFLAndersAAResult &getResult() { return *Result; }
const CFLAndersAAResult &getResult() const { return *Result; }

void initializePass() override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
};

// createCFLAndersAAWrapperPass - This pass implements a set-based approach to
// alias analysis.
ImmutablePass *createCFLAndersAAWrapperPass();

} // end namespace llvm

#endif // LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H
669 changes: 669 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/CFLGraph.h

Large diffs are not rendered by default.

367 changes: 367 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,367 @@
//===- CFLSteensAliasAnalysis.cpp - Unification-based Alias Analysis ------===//
//
// 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 implements a CFL-base, summary-based alias analysis algorithm. It
// does not depend on types. The algorithm is a mixture of the one described in
// "Demand-driven alias analysis for C" by Xin Zheng and Radu Rugina, and "Fast
// algorithms for Dyck-CFL-reachability with applications to Alias Analysis" by
// Zhang Q, Lyu M R, Yuan H, and Su Z. -- to summarize the papers, we build a
// graph of the uses of a variable, where each node is a memory location, and
// each edge is an action that happened on that memory location. The "actions"
// can be one of Dereference, Reference, or Assign. The precision of this
// analysis is roughly the same as that of an one level context-sensitive
// Steensgaard's algorithm.
//
// Two variables are considered as aliasing iff you can reach one value's node
// from the other value's node and the language formed by concatenating all of
// the edge labels (actions) conforms to a context-free grammar.
//
// Because this algorithm requires a graph search on each query, we execute the
// algorithm outlined in "Fast algorithms..." (mentioned above)
// in order to transform the graph into sets of variables that may alias in
// ~nlogn time (n = number of variables), which makes queries take constant
// time.
//===----------------------------------------------------------------------===//

// N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and
// CFLSteensAA is interprocedural. This is *technically* A Bad Thing, because
// FunctionPasses are only allowed to inspect the Function that they're being
// run on. Realistically, this likely isn't a problem until we allow
// FunctionPasses to run concurrently.

#include "llvm/Analysis/CFLSteensAliasAnalysis.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

#include "AliasAnalysisSummary.h"
#include "CFLGraph.h"
#include "StratifiedSets.h"

#include <algorithm>
#include <cassert>
#include <limits>
#include <memory>
#include <utility>

using namespace llvm;
using namespace llvm::cflaa;

#define DEBUG_TYPE "cfl-steens-aa"

CFLSteensAAResult::CFLSteensAAResult(
std::function<const TargetLibraryInfo &(Function &F)> GetTLI)
: GetTLI(std::move(GetTLI)) {}
CFLSteensAAResult::CFLSteensAAResult(CFLSteensAAResult &&Arg)
: AAResultBase(std::move(Arg)), GetTLI(std::move(Arg.GetTLI)) {}
CFLSteensAAResult::~CFLSteensAAResult() = default;

/// Information we have about a function and would like to keep around.
class CFLSteensAAResult::FunctionInfo {
StratifiedSets<InstantiatedValue> Sets;
AliasSummary Summary;

public:
FunctionInfo(Function &Fn, const SmallVectorImpl<Value *> &RetVals,
StratifiedSets<InstantiatedValue> S);

const StratifiedSets<InstantiatedValue> &getStratifiedSets() const {
return Sets;
}

const AliasSummary &getAliasSummary() const { return Summary; }
};

const StratifiedIndex StratifiedLink::SetSentinel =
std::numeric_limits<StratifiedIndex>::max();

//===----------------------------------------------------------------------===//
// Function declarations that require types defined in the namespace above
//===----------------------------------------------------------------------===//

/// Determines whether it would be pointless to add the given Value to our sets.
static bool canSkipAddingToSets(Value *Val) {
// Constants can share instances, which may falsely unify multiple
// sets, e.g. in
// store i32* null, i32** %ptr1
// store i32* null, i32** %ptr2
// clearly ptr1 and ptr2 should not be unified into the same set, so
// we should filter out the (potentially shared) instance to
// i32* null.
if (isa<Constant>(Val)) {
// TODO: Because all of these things are constant, we can determine whether
// the data is *actually* mutable at graph building time. This will probably
// come for free/cheap with offset awareness.
bool CanStoreMutableData = isa<GlobalValue>(Val) ||
isa<ConstantExpr>(Val) ||
isa<ConstantAggregate>(Val);
return !CanStoreMutableData;
}

return false;
}

CFLSteensAAResult::FunctionInfo::FunctionInfo(
Function &Fn, const SmallVectorImpl<Value *> &RetVals,
StratifiedSets<InstantiatedValue> S)
: Sets(std::move(S)) {
// Historically, an arbitrary upper-bound of 50 args was selected. We may want
// to remove this if it doesn't really matter in practice.
if (Fn.arg_size() > MaxSupportedArgsInSummary)
return;

DenseMap<StratifiedIndex, InterfaceValue> InterfaceMap;

// Our intention here is to record all InterfaceValues that share the same
// StratifiedIndex in RetParamRelations. For each valid InterfaceValue, we
// have its StratifiedIndex scanned here and check if the index is presented
// in InterfaceMap: if it is not, we add the correspondence to the map;
// otherwise, an aliasing relation is found and we add it to
// RetParamRelations.

auto AddToRetParamRelations = [&](unsigned InterfaceIndex,
StratifiedIndex SetIndex) {
unsigned Level = 0;
while (true) {
InterfaceValue CurrValue{InterfaceIndex, Level};

auto Itr = InterfaceMap.find(SetIndex);
if (Itr != InterfaceMap.end()) {
if (CurrValue != Itr->second)
Summary.RetParamRelations.push_back(
ExternalRelation{CurrValue, Itr->second, UnknownOffset});
break;
}

auto &Link = Sets.getLink(SetIndex);
InterfaceMap.insert(std::make_pair(SetIndex, CurrValue));
auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs);
if (ExternalAttrs.any())
Summary.RetParamAttributes.push_back(
ExternalAttribute{CurrValue, ExternalAttrs});

if (!Link.hasBelow())
break;

++Level;
SetIndex = Link.Below;
}
};

// Populate RetParamRelations for return values
for (auto *RetVal : RetVals) {
assert(RetVal != nullptr);
assert(RetVal->getType()->isPointerTy());
auto RetInfo = Sets.find(InstantiatedValue{RetVal, 0});
if (RetInfo.hasValue())
AddToRetParamRelations(0, RetInfo->Index);
}

// Populate RetParamRelations for parameters
unsigned I = 0;
for (auto &Param : Fn.args()) {
if (Param.getType()->isPointerTy()) {
auto ParamInfo = Sets.find(InstantiatedValue{&Param, 0});
if (ParamInfo.hasValue())
AddToRetParamRelations(I + 1, ParamInfo->Index);
}
++I;
}
}

// Builds the graph + StratifiedSets for a function.
CFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) {
CFLGraphBuilder<CFLSteensAAResult> GraphBuilder(*this, GetTLI(*Fn), *Fn);
StratifiedSetsBuilder<InstantiatedValue> SetBuilder;

// Add all CFLGraph nodes and all Dereference edges to StratifiedSets
auto &Graph = GraphBuilder.getCFLGraph();
for (const auto &Mapping : Graph.value_mappings()) {
auto Val = Mapping.first;
if (canSkipAddingToSets(Val))
continue;
auto &ValueInfo = Mapping.second;

assert(ValueInfo.getNumLevels() > 0);
SetBuilder.add(InstantiatedValue{Val, 0});
SetBuilder.noteAttributes(InstantiatedValue{Val, 0},
ValueInfo.getNodeInfoAtLevel(0).Attr);
for (unsigned I = 0, E = ValueInfo.getNumLevels() - 1; I < E; ++I) {
SetBuilder.add(InstantiatedValue{Val, I + 1});
SetBuilder.noteAttributes(InstantiatedValue{Val, I + 1},
ValueInfo.getNodeInfoAtLevel(I + 1).Attr);
SetBuilder.addBelow(InstantiatedValue{Val, I},
InstantiatedValue{Val, I + 1});
}
}

// Add all assign edges to StratifiedSets
for (const auto &Mapping : Graph.value_mappings()) {
auto Val = Mapping.first;
if (canSkipAddingToSets(Val))
continue;
auto &ValueInfo = Mapping.second;

for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
auto Src = InstantiatedValue{Val, I};
for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges)
SetBuilder.addWith(Src, Edge.Other);
}
}

return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build());
}

void CFLSteensAAResult::scan(Function *Fn) {
auto InsertPair = Cache.insert(std::make_pair(Fn, Optional<FunctionInfo>()));
(void)InsertPair;
assert(InsertPair.second &&
"Trying to scan a function that has already been cached");

// Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call
// may get evaluated after operator[], potentially triggering a DenseMap
// resize and invalidating the reference returned by operator[]
auto FunInfo = buildSetsFrom(Fn);
Cache[Fn] = std::move(FunInfo);

Handles.emplace_front(Fn, this);
}

void CFLSteensAAResult::evict(Function *Fn) { Cache.erase(Fn); }

/// Ensures that the given function is available in the cache, and returns the
/// entry.
const Optional<CFLSteensAAResult::FunctionInfo> &
CFLSteensAAResult::ensureCached(Function *Fn) {
auto Iter = Cache.find(Fn);
if (Iter == Cache.end()) {
scan(Fn);
Iter = Cache.find(Fn);
assert(Iter != Cache.end());
assert(Iter->second.hasValue());
}
return Iter->second;
}

const AliasSummary *CFLSteensAAResult::getAliasSummary(Function &Fn) {
auto &FunInfo = ensureCached(&Fn);
if (FunInfo.hasValue())
return &FunInfo->getAliasSummary();
else
return nullptr;
}

AliasResult CFLSteensAAResult::query(const MemoryLocation &LocA,
const MemoryLocation &LocB) {
auto *ValA = const_cast<Value *>(LocA.Ptr);
auto *ValB = const_cast<Value *>(LocB.Ptr);

if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
return AliasResult::NoAlias;

Function *Fn = nullptr;
Function *MaybeFnA = const_cast<Function *>(parentFunctionOfValue(ValA));
Function *MaybeFnB = const_cast<Function *>(parentFunctionOfValue(ValB));
if (!MaybeFnA && !MaybeFnB) {
// The only times this is known to happen are when globals + InlineAsm are
// involved
LLVM_DEBUG(
dbgs()
<< "CFLSteensAA: could not extract parent function information.\n");
return AliasResult::MayAlias;
}

if (MaybeFnA) {
Fn = MaybeFnA;
assert((!MaybeFnB || MaybeFnB == MaybeFnA) &&
"Interprocedural queries not supported");
} else {
Fn = MaybeFnB;
}

assert(Fn != nullptr);
auto &MaybeInfo = ensureCached(Fn);
assert(MaybeInfo.hasValue());

auto &Sets = MaybeInfo->getStratifiedSets();
auto MaybeA = Sets.find(InstantiatedValue{ValA, 0});
if (!MaybeA.hasValue())
return AliasResult::MayAlias;

auto MaybeB = Sets.find(InstantiatedValue{ValB, 0});
if (!MaybeB.hasValue())
return AliasResult::MayAlias;

auto SetA = *MaybeA;
auto SetB = *MaybeB;
auto AttrsA = Sets.getLink(SetA.Index).Attrs;
auto AttrsB = Sets.getLink(SetB.Index).Attrs;

// If both values are local (meaning the corresponding set has attribute
// AttrNone or AttrEscaped), then we know that CFLSteensAA fully models them:
// they may-alias each other if and only if they are in the same set.
// If at least one value is non-local (meaning it either is global/argument or
// it comes from unknown sources like integer cast), the situation becomes a
// bit more interesting. We follow three general rules described below:
// - Non-local values may alias each other
// - AttrNone values do not alias any non-local values
// - AttrEscaped do not alias globals/arguments, but they may alias
// AttrUnknown values
if (SetA.Index == SetB.Index)
return AliasResult::MayAlias;
if (AttrsA.none() || AttrsB.none())
return AliasResult::NoAlias;
if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
return AliasResult::MayAlias;
if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
return AliasResult::MayAlias;
return AliasResult::NoAlias;
}

AnalysisKey CFLSteensAA::Key;

CFLSteensAAResult CFLSteensAA::run(Function &F, FunctionAnalysisManager &AM) {
auto GetTLI = [&AM](Function &F) -> const TargetLibraryInfo & {
return AM.getResult<TargetLibraryAnalysis>(F);
};
return CFLSteensAAResult(GetTLI);
}

char CFLSteensAAWrapperPass::ID = 0;
INITIALIZE_PASS(CFLSteensAAWrapperPass, "cfl-steens-aa",
"Unification-Based CFL Alias Analysis", false, true)

ImmutablePass *llvm::createCFLSteensAAWrapperPass() {
return new CFLSteensAAWrapperPass();
}

CFLSteensAAWrapperPass::CFLSteensAAWrapperPass() : ImmutablePass(ID) {
initializeCFLSteensAAWrapperPassPass(*PassRegistry::getPassRegistry());
}

void CFLSteensAAWrapperPass::initializePass() {
auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & {
return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
};
Result.reset(new CFLSteensAAResult(GetTLI));
}

void CFLSteensAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<TargetLibraryInfoWrapperPass>();
}
145 changes: 145 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/CFLSteensAliasAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//==- CFLSteensAliasAnalysis.h - Unification-based Alias Analysis -*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This is the interface for LLVM's unification-based alias analysis
/// implemented with CFL graph reachability.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H
#define LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CFLAliasAnalysisUtils.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"

#include <forward_list>
#include <memory>

namespace llvm {

class Function;
class TargetLibraryInfo;

namespace cflaa {

struct AliasSummary;

} // end namespace cflaa

class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
friend AAResultBase<CFLSteensAAResult>;

class FunctionInfo;

public:
explicit CFLSteensAAResult(
std::function<const TargetLibraryInfo &(Function &)> GetTLI);
CFLSteensAAResult(CFLSteensAAResult &&Arg);
~CFLSteensAAResult();

/// Handle invalidation events from the new pass manager.
///
/// By definition, this result is stateless and so remains valid.
bool invalidate(Function &, const PreservedAnalyses &,
FunctionAnalysisManager::Invalidator &) {
return false;
}

/// Inserts the given Function into the cache.
void scan(Function *Fn);

void evict(Function *Fn);

/// Ensures that the given function is available in the cache.
/// Returns the appropriate entry from the cache.
const Optional<FunctionInfo> &ensureCached(Function *Fn);

/// Get the alias summary for the given function
/// Return nullptr if the summary is not found or not available
const cflaa::AliasSummary *getAliasSummary(Function &Fn);

AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB);

AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB,
AAQueryInfo &AAQI) {
if (LocA.Ptr == LocB.Ptr)
return AliasResult::MustAlias;

// Comparisons between global variables and other constants should be
// handled by BasicAA.
// CFLSteensAA may report NoAlias when comparing a GlobalValue and
// ConstantExpr, but every query needs to have at least one Value tied to a
// Function, and neither GlobalValues nor ConstantExprs are.
if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr))
return AAResultBase::alias(LocA, LocB, AAQI);

AliasResult QueryResult = query(LocA, LocB);
if (QueryResult == AliasResult::MayAlias)
return AAResultBase::alias(LocA, LocB, AAQI);

return QueryResult;
}

private:
std::function<const TargetLibraryInfo &(Function &)> GetTLI;

/// Cached mapping of Functions to their StratifiedSets.
/// If a function's sets are currently being built, it is marked
/// in the cache as an Optional without a value. This way, if we
/// have any kind of recursion, it is discernable from a function
/// that simply has empty sets.
DenseMap<Function *, Optional<FunctionInfo>> Cache;
std::forward_list<cflaa::FunctionHandle<CFLSteensAAResult>> Handles;

FunctionInfo buildSetsFrom(Function *F);
};

/// Analysis pass providing a never-invalidated alias analysis result.
///
/// FIXME: We really should refactor CFL to use the analysis more heavily, and
/// in particular to leverage invalidation to trigger re-computation of sets.
class CFLSteensAA : public AnalysisInfoMixin<CFLSteensAA> {
friend AnalysisInfoMixin<CFLSteensAA>;

static AnalysisKey Key;

public:
using Result = CFLSteensAAResult;

CFLSteensAAResult run(Function &F, FunctionAnalysisManager &AM);
};

/// Legacy wrapper pass to provide the CFLSteensAAResult object.
class CFLSteensAAWrapperPass : public ImmutablePass {
std::unique_ptr<CFLSteensAAResult> Result;

public:
static char ID;

CFLSteensAAWrapperPass();

CFLSteensAAResult &getResult() { return *Result; }
const CFLSteensAAResult &getResult() const { return *Result; }

void initializePass() override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
};

// createCFLSteensAAWrapperPass - This pass implements a set-based approach to
// alias analysis.
ImmutablePass *createCFLSteensAAWrapperPass();

} // end namespace llvm

#endif // LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H
598 changes: 598 additions & 0 deletions lib/PhasarLLVM/Pointer/external/llvm/StratifiedSets.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions unittests/PhasarLLVM/ControlFlow/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ set(ControlFlowSources
LLVMBasedICFGSerializationTest.cpp
)

set(LLVM_LINK_COMPONENTS Linker) # The CtorDtorTest needs the linker
foreach(TEST_SRC ${ControlFlowSources})
add_phasar_unittest(${TEST_SRC})
endforeach(TEST_SRC)

0 comments on commit 263b016

Please sign in to comment.