LLVM 20.0.0git
Classes | Namespaces | Macros | Functions | Variables
NewGVN.cpp File Reference

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 ValuegetCopyOf (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< boolEnableStoreRefinement ("enable-store-refinement", cl::init(false), cl::Hidden)
 
static cl::opt< boolEnablePhiOfOps ("enable-phi-of-ops", cl::init(true), cl::Hidden)
 Currently, the generation "phi of ops" can result in correctness issues.
 

Detailed Description

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.

Macro Definition Documentation

◆ DEBUG_TYPE

#define DEBUG_TYPE   "newgvn"

Definition at line 127 of file NewGVN.cpp.

Function Documentation

◆ alwaysAvailable()

static bool alwaysAvailable ( Value V)
static

Definition at line 1041 of file NewGVN.cpp.

◆ DEBUG_COUNTER() [1/2]

DEBUG_COUNTER ( PHIOfOpsCounter  ,
"newgvn-phi"  ,
"Controls which instructions we create phi of ops for"   
)

◆ DEBUG_COUNTER() [2/2]

DEBUG_COUNTER ( VNCounter  ,
"newgvn-vn"  ,
"Controls which instructions are value numbered"   
)

◆ equalsLoadStoreHelper()

template<typename T >
static bool equalsLoadStoreHelper ( const T LHS,
const Expression RHS 
)
static

◆ getBlockName()

static std::string getBlockName ( const BasicBlock B)
static

Definition at line 968 of file NewGVN.cpp.

References B.

◆ getCopyOf()

static Value * getCopyOf ( const Value V)
static

Definition at line 1011 of file NewGVN.cpp.

References II.

Referenced by isCopyOfAPHI(), and isCopyOfPHI().

◆ isCopyOfAPHI()

static bool isCopyOfAPHI ( const Value V)
static

Definition at line 1023 of file NewGVN.cpp.

References getCopyOf().

◆ isCopyOfPHI()

static bool isCopyOfPHI ( const Value V,
const PHINode PN 
)
static

Definition at line 1019 of file NewGVN.cpp.

References getCopyOf().

◆ okayForPHIOfOps()

static bool okayForPHIOfOps ( const Instruction I)
static

Definition at line 2621 of file NewGVN.cpp.

References EnablePhiOfOps, and I.

◆ patchAndReplaceAllUsesWith()

static void patchAndReplaceAllUsesWith ( Instruction I,
Value Repl 
)
static

Definition at line 3738 of file NewGVN.cpp.

References I, and llvm::patchReplacementInstruction().

◆ STATISTIC() [1/11]

STATISTIC ( NumGVNAvoidedSortedLeaderChanges  ,
"Number of avoided sorted leader changes"   
)

◆ STATISTIC() [2/11]

STATISTIC ( NumGVNBlocksDeleted  ,
"Number of blocks deleted"   
)

◆ STATISTIC() [3/11]

STATISTIC ( NumGVNDeadStores  ,
"Number of redundant/dead stores eliminated"   
)

◆ STATISTIC() [4/11]

STATISTIC ( NumGVNInstrDeleted  ,
"Number of instructions deleted"   
)

◆ STATISTIC() [5/11]

STATISTIC ( NumGVNLeaderChanges  ,
"Number of leader changes"   
)

◆ STATISTIC() [6/11]

STATISTIC ( NumGVNMaxIterations  ,
"Maximum Number of iterations it took to converge GVN"   
)

◆ STATISTIC() [7/11]

STATISTIC ( NumGVNOpsSimplified  ,
"Number of Expressions simplified"   
)

◆ STATISTIC() [8/11]

STATISTIC ( NumGVNPHIOfOpsCreated  ,
"Number of PHI of ops created"   
)

◆ STATISTIC() [9/11]

STATISTIC ( NumGVNPHIOfOpsEliminations  ,
"Number of things eliminated using PHI of ops"   
)

◆ STATISTIC() [10/11]

STATISTIC ( NumGVNPhisAllSame  ,
"Number of PHIs whos arguments are all the same"   
)

◆ STATISTIC() [11/11]

STATISTIC ( NumGVNSortedLeaderChanges  ,
"Number of sorted leader changes"   
)

Variable Documentation

◆ EnablePhiOfOps

cl::opt< bool > EnablePhiOfOps("enable-phi-of-ops", cl::init(true), cl::Hidden) ( "enable-phi-of-ops"  ,
cl::init(true ,
cl::Hidden   
)
static

Currently, the generation "phi of ops" can result in correctness issues.

Referenced by okayForPHIOfOps().

◆ EnableStoreRefinement

cl::opt< bool > EnableStoreRefinement("enable-store-refinement", cl::init(false), cl::Hidden) ( "enable-store-refinement"  ,
cl::init(false)  ,
cl::Hidden   
)
static