//===- GVNSink.cpp - sink expressions into successors ---------------------===// // // 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 GVNSink.cpp /// This pass attempts to sink instructions into successors, reducing static /// instruction count and enabling if-conversion. /// /// We use a variant of global value numbering to decide what can be sunk. /// Consider: /// /// [ %a1 = add i32 %b, 1 ] [ %c1 = add i32 %d, 1 ] /// [ %a2 = xor i32 %a1, 1 ] [ %c2 = xor i32 %c1, 1 ] /// \ / /// [ %e = phi i32 %a2, %c2 ] /// [ add i32 %e, 4 ] /// /// /// GVN would number %a1 and %c1 differently because they compute different /// results - the VN of an instruction is a function of its opcode and the /// transitive closure of its operands. This is the key property for hoisting /// and CSE. /// /// What we want when sinking however is for a numbering that is a function of /// the *uses* of an instruction, which allows us to answer the question "if I /// replace %a1 with %c1, will it contribute in an equivalent way to all /// successive instructions?". The PostValueTable class in GVN provides this /// mapping. // //===----------------------------------------------------------------------===// #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" #include "llvm/IR/Value.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ArrayRecycler.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GVNExpression.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include <algorithm> #include <cassert> #include <cstddef> #include <cstdint> #include <iterator> #include <utility> usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(NumRemoved, "Number of instructions removed"); namespace llvm { namespace GVNExpression { LLVM_DUMP_METHOD void Expression::dump() const { … } } // end namespace GVNExpression } // end namespace llvm namespace { static bool isMemoryInst(const Instruction *I) { … } /// Iterates through instructions in a set of blocks in reverse order from the /// first non-terminator. For example (assume all blocks have size n): /// LockstepReverseIterator I([B1, B2, B3]); /// *I-- = [B1[n], B2[n], B3[n]]; /// *I-- = [B1[n-1], B2[n-1], B3[n-1]]; /// *I-- = [B1[n-2], B2[n-2], B3[n-2]]; /// ... /// /// It continues until all blocks have been exhausted. Use \c getActiveBlocks() /// to /// determine which blocks are still going and the order they appear in the /// list returned by operator*. class LockstepReverseIterator { … }; //===----------------------------------------------------------------------===// /// Candidate solution for sinking. There may be different ways to /// sink instructions, differing in the number of instructions sunk, /// the number of predecessors sunk from and the number of PHIs /// required. struct SinkingInstructionCandidate { … }; #ifndef NDEBUG raw_ostream &operator<<(raw_ostream &OS, const SinkingInstructionCandidate &C) { OS << "<Candidate Cost=" << C.Cost << " #Blocks=" << C.NumBlocks << " #Insts=" << C.NumInstructions << " #PHIs=" << C.NumPHIs << ">"; return OS; } #endif //===----------------------------------------------------------------------===// /// Describes a PHI node that may or may not exist. These track the PHIs /// that must be created if we sunk a sequence of instructions. It provides /// a hash function for efficient equality comparisons. class ModelledPHI { … }; template <typename ModelledPHI> struct DenseMapInfo { … }; ModelledPHISet; //===----------------------------------------------------------------------===// // ValueTable //===----------------------------------------------------------------------===// // This is a value number table where the value number is a function of the // *uses* of a value, rather than its operands. Thus, if VN(A) == VN(B) we know // that the program would be equivalent if we replaced A with PHI(A, B). //===----------------------------------------------------------------------===// /// A GVN expression describing how an instruction is used. The operands /// field of BasicExpression is used to store uses, not operands. /// /// This class also contains fields for discriminators used when determining /// equivalence of instructions with sideeffects. class InstructionUseExpr : public GVNExpression::BasicExpression { … }; BasicBlocksSet; class ValueTable { … }; //===----------------------------------------------------------------------===// class GVNSink { … }; std::optional<SinkingInstructionCandidate> GVNSink::analyzeInstructionForSinking(LockstepReverseIterator &LRI, unsigned &InstNum, unsigned &MemoryInstNum, ModelledPHISet &NeededPHIs, SmallPtrSetImpl<Value *> &PHIContents) { … } unsigned GVNSink::sinkBB(BasicBlock *BBEnd) { … } void GVNSink::sinkLastInstruction(ArrayRef<BasicBlock *> Blocks, BasicBlock *BBEnd) { … } } // end anonymous namespace PreservedAnalyses GVNSinkPass::run(Function &F, FunctionAnalysisManager &AM) { … }