LLVM 20.0.0git
|
This file implements the new LLVM's Global Value Numbering pass. More...
#include "llvm/Transforms/Scalar/NewGVN.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CFGPrinter.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/ArrayRecycler.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar/GVNExpression.h"
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/PredicateInfo.h"
#include "llvm/Transforms/Utils/VNCoercion.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iterator>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
Go to the source code of this file.
Classes | |
struct | llvm::ExactEqualsExpression |
struct | llvm::DenseMapInfo< const Expression * > |
struct | NewGVN::ValueDFS |
Namespaces | |
namespace | llvm |
This is an optimization pass for GlobalISel generic memory operations. | |
namespace | llvm::GVNExpression |
Macros | |
#define | DEBUG_TYPE "newgvn" |
Functions | |
STATISTIC (NumGVNInstrDeleted, "Number of instructions deleted") | |
STATISTIC (NumGVNBlocksDeleted, "Number of blocks deleted") | |
STATISTIC (NumGVNOpsSimplified, "Number of Expressions simplified") | |
STATISTIC (NumGVNPhisAllSame, "Number of PHIs whos arguments are all the same") | |
STATISTIC (NumGVNMaxIterations, "Maximum Number of iterations it took to converge GVN") | |
STATISTIC (NumGVNLeaderChanges, "Number of leader changes") | |
STATISTIC (NumGVNSortedLeaderChanges, "Number of sorted leader changes") | |
STATISTIC (NumGVNAvoidedSortedLeaderChanges, "Number of avoided sorted leader changes") | |
STATISTIC (NumGVNDeadStores, "Number of redundant/dead stores eliminated") | |
STATISTIC (NumGVNPHIOfOpsCreated, "Number of PHI of ops created") | |
STATISTIC (NumGVNPHIOfOpsEliminations, "Number of things eliminated using PHI of ops") | |
DEBUG_COUNTER (VNCounter, "newgvn-vn", "Controls which instructions are value numbered") | |
DEBUG_COUNTER (PHIOfOpsCounter, "newgvn-phi", "Controls which instructions we create phi of ops for") | |
template<typename T > | |
static bool | equalsLoadStoreHelper (const T &LHS, const Expression &RHS) |
static std::string | getBlockName (const BasicBlock *B) |
static Value * | getCopyOf (const Value *V) |
static bool | isCopyOfPHI (const Value *V, const PHINode *PN) |
static bool | isCopyOfAPHI (const Value *V) |
static bool | alwaysAvailable (Value *V) |
static bool | okayForPHIOfOps (const Instruction *I) |
static void | patchAndReplaceAllUsesWith (Instruction *I, Value *Repl) |
Variables | |
static cl::opt< bool > | EnableStoreRefinement ("enable-store-refinement", cl::init(false), cl::Hidden) |
static cl::opt< bool > | EnablePhiOfOps ("enable-phi-of-ops", cl::init(true), cl::Hidden) |
Currently, the generation "phi of ops" can result in correctness issues. | |
This file implements the new LLVM's Global Value Numbering pass.
GVN partitions values computed by a function into congruence classes. Values ending up in the same congruence class are guaranteed to be the same for every execution of the program. In that respect, congruency is a compile-time approximation of equivalence of values at runtime. The algorithm implemented here uses a sparse formulation and it's based on the ideas described in the paper: "A Sparse Algorithm for Predicated Global Value Numbering" from Karthik Gargi.
A brief overview of the algorithm: The algorithm is essentially the same as the standard RPO value numbering algorithm (a good reference is the paper "SCC based value numbering" by L. Taylor Simpson) with one major difference: The RPO algorithm proceeds, on every iteration, to process every reachable block and every instruction in that block. This is because the standard RPO algorithm does not track what things have the same value number, it only tracks what the value number of a given operation is (the mapping is operation -> value number). Thus, when a value number of an operation changes, it must reprocess everything to ensure all uses of a value number get updated properly. In constrast, the sparse algorithm we use also tracks what operations have a given value number (IE it also tracks the reverse mapping from value number -> operations with that value number), so that it only needs to reprocess the instructions that are affected when something's value number changes. The vast majority of complexity and code in this file is devoted to tracking what value numbers could change for what instructions when various things happen. The rest of the algorithm is devoted to performing symbolic evaluation, forward propagation, and simplification of operations based on the value numbers deduced so far
In order to make the GVN mostly-complete, we use a technique derived from "Detection of Redundant Expressions: A Complete and Polynomial-time Algorithm in SSA" by R.R. Pai. The source of incompleteness in most SSA based GVN algorithms is related to their inability to detect equivalence between phi of ops (IE phi(a+b, c+d)) and op of phis (phi(a,c) + phi(b, d)). We resolve this issue by generating the equivalent "phi of ops" form for each op of phis we see, in a way that only takes polynomial time to resolve.
We also do not perform elimination by using any published algorithm. All published algorithms are O(Instructions). Instead, we use a technique that is O(number of operations with the same value number), enabling us to skip trying to eliminate things that have unique value numbers.
Definition in file NewGVN.cpp.
#define DEBUG_TYPE "newgvn" |
Definition at line 127 of file NewGVN.cpp.
Definition at line 1041 of file NewGVN.cpp.
DEBUG_COUNTER | ( | PHIOfOpsCounter | , |
"newgvn-phi" | , | ||
"Controls which instructions we create phi of ops for" | |||
) |
DEBUG_COUNTER | ( | VNCounter | , |
"newgvn-vn" | , | ||
"Controls which instructions are value numbered" | |||
) |
|
static |
Definition at line 928 of file NewGVN.cpp.
Referenced by llvm::GVNExpression::LoadExpression::equals(), and llvm::GVNExpression::StoreExpression::equals().
|
static |
Definition at line 968 of file NewGVN.cpp.
References B.
Definition at line 1011 of file NewGVN.cpp.
References II.
Referenced by isCopyOfAPHI(), and isCopyOfPHI().
Definition at line 1023 of file NewGVN.cpp.
References getCopyOf().
Definition at line 1019 of file NewGVN.cpp.
References getCopyOf().
|
static |
Definition at line 2621 of file NewGVN.cpp.
References EnablePhiOfOps, and I.
|
static |
Definition at line 3738 of file NewGVN.cpp.
References I, and llvm::patchReplacementInstruction().
STATISTIC | ( | NumGVNAvoidedSortedLeaderChanges | , |
"Number of avoided sorted leader changes" | |||
) |
STATISTIC | ( | NumGVNBlocksDeleted | , |
"Number of blocks deleted" | |||
) |
STATISTIC | ( | NumGVNDeadStores | , |
"Number of redundant/dead stores eliminated" | |||
) |
STATISTIC | ( | NumGVNInstrDeleted | , |
"Number of instructions deleted" | |||
) |
STATISTIC | ( | NumGVNLeaderChanges | , |
"Number of leader changes" | |||
) |
STATISTIC | ( | NumGVNMaxIterations | , |
"Maximum Number of iterations it took to converge GVN" | |||
) |
STATISTIC | ( | NumGVNOpsSimplified | , |
"Number of Expressions simplified" | |||
) |
STATISTIC | ( | NumGVNPHIOfOpsEliminations | , |
"Number of things eliminated using PHI of ops" | |||
) |
STATISTIC | ( | NumGVNPhisAllSame | , |
"Number of PHIs whos arguments are all the same" | |||
) |
STATISTIC | ( | NumGVNSortedLeaderChanges | , |
"Number of sorted leader changes" | |||
) |
|
static |
Currently, the generation "phi of ops" can result in correctness issues.
Referenced by okayForPHIOfOps().