10b57cec5SDimitry Andric //===- HexagonCommonGEP.cpp -----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
100b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h"
110b57cec5SDimitry Andric #include "llvm/ADT/GraphTraits.h"
120b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
13480093f4SDimitry Andric #include "llvm/ADT/SetVector.h"
14fe6060f1SDimitry Andric #include "llvm/ADT/SmallVector.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
160b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
170b57cec5SDimitry Andric #include "llvm/Analysis/PostDominators.h"
180b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
190b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
200b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
210b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
220b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
230b57cec5SDimitry Andric #include "llvm/IR/Function.h"
240b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
250b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
260b57cec5SDimitry Andric #include "llvm/IR/Type.h"
270b57cec5SDimitry Andric #include "llvm/IR/Use.h"
280b57cec5SDimitry Andric #include "llvm/IR/User.h"
290b57cec5SDimitry Andric #include "llvm/IR/Value.h"
300b57cec5SDimitry Andric #include "llvm/IR/Verifier.h"
31480093f4SDimitry Andric #include "llvm/InitializePasses.h"
320b57cec5SDimitry Andric #include "llvm/Pass.h"
330b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
340b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
350b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
360b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
370b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
380b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
39480093f4SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
400b57cec5SDimitry Andric #include <algorithm>
410b57cec5SDimitry Andric #include <cassert>
420b57cec5SDimitry Andric #include <cstddef>
430b57cec5SDimitry Andric #include <cstdint>
440b57cec5SDimitry Andric #include <iterator>
450b57cec5SDimitry Andric #include <map>
460b57cec5SDimitry Andric #include <set>
470b57cec5SDimitry Andric #include <utility>
480b57cec5SDimitry Andric #include <vector>
490b57cec5SDimitry Andric 
50480093f4SDimitry Andric #define DEBUG_TYPE "commgep"
51480093f4SDimitry Andric 
520b57cec5SDimitry Andric using namespace llvm;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric static cl::opt<bool> OptSpeculate("commgep-speculate", cl::init(true),
5581ad6265SDimitry Andric                                   cl::Hidden);
560b57cec5SDimitry Andric 
5781ad6265SDimitry Andric static cl::opt<bool> OptEnableInv("commgep-inv", cl::init(true), cl::Hidden);
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric static cl::opt<bool> OptEnableConst("commgep-const", cl::init(true),
6081ad6265SDimitry Andric                                     cl::Hidden);
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric namespace llvm {
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   void initializeHexagonCommonGEPPass(PassRegistry&);
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric } // end namespace llvm
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric namespace {
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   struct GepNode;
710b57cec5SDimitry Andric   using NodeSet = std::set<GepNode *>;
720b57cec5SDimitry Andric   using NodeToValueMap = std::map<GepNode *, Value *>;
730b57cec5SDimitry Andric   using NodeVect = std::vector<GepNode *>;
740b57cec5SDimitry Andric   using NodeChildrenMap = std::map<GepNode *, NodeVect>;
750b57cec5SDimitry Andric   using UseSet = SetVector<Use *>;
760b57cec5SDimitry Andric   using NodeToUsesMap = std::map<GepNode *, UseSet>;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // Numbering map for gep nodes. Used to keep track of ordering for
790b57cec5SDimitry Andric   // gep nodes.
800b57cec5SDimitry Andric   struct NodeOrdering {
810b57cec5SDimitry Andric     NodeOrdering() = default;
820b57cec5SDimitry Andric 
insert__anon2a64d1560111::NodeOrdering830b57cec5SDimitry Andric     void insert(const GepNode *N) { Map.insert(std::make_pair(N, ++LastNum)); }
clear__anon2a64d1560111::NodeOrdering840b57cec5SDimitry Andric     void clear() { Map.clear(); }
850b57cec5SDimitry Andric 
operator ()__anon2a64d1560111::NodeOrdering860b57cec5SDimitry Andric     bool operator()(const GepNode *N1, const GepNode *N2) const {
870b57cec5SDimitry Andric       auto F1 = Map.find(N1), F2 = Map.find(N2);
880b57cec5SDimitry Andric       assert(F1 != Map.end() && F2 != Map.end());
890b57cec5SDimitry Andric       return F1->second < F2->second;
900b57cec5SDimitry Andric     }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   private:
930b57cec5SDimitry Andric     std::map<const GepNode *, unsigned> Map;
940b57cec5SDimitry Andric     unsigned LastNum = 0;
950b57cec5SDimitry Andric   };
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   class HexagonCommonGEP : public FunctionPass {
980b57cec5SDimitry Andric   public:
990b57cec5SDimitry Andric     static char ID;
1000b57cec5SDimitry Andric 
HexagonCommonGEP()1010b57cec5SDimitry Andric     HexagonCommonGEP() : FunctionPass(ID) {
1020b57cec5SDimitry Andric       initializeHexagonCommonGEPPass(*PassRegistry::getPassRegistry());
1030b57cec5SDimitry Andric     }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric     bool runOnFunction(Function &F) override;
getPassName() const1060b57cec5SDimitry Andric     StringRef getPassName() const override { return "Hexagon Common GEP"; }
1070b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const1080b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
1090b57cec5SDimitry Andric       AU.addRequired<DominatorTreeWrapperPass>();
1100b57cec5SDimitry Andric       AU.addPreserved<DominatorTreeWrapperPass>();
1110b57cec5SDimitry Andric       AU.addRequired<PostDominatorTreeWrapperPass>();
1120b57cec5SDimitry Andric       AU.addPreserved<PostDominatorTreeWrapperPass>();
1130b57cec5SDimitry Andric       AU.addRequired<LoopInfoWrapperPass>();
1140b57cec5SDimitry Andric       AU.addPreserved<LoopInfoWrapperPass>();
1150b57cec5SDimitry Andric       FunctionPass::getAnalysisUsage(AU);
1160b57cec5SDimitry Andric     }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   private:
1190b57cec5SDimitry Andric     using ValueToNodeMap = std::map<Value *, GepNode *>;
1200b57cec5SDimitry Andric     using ValueVect = std::vector<Value *>;
1210b57cec5SDimitry Andric     using NodeToValuesMap = std::map<GepNode *, ValueVect>;
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     void getBlockTraversalOrder(BasicBlock *Root, ValueVect &Order);
1240b57cec5SDimitry Andric     bool isHandledGepForm(GetElementPtrInst *GepI);
1250b57cec5SDimitry Andric     void processGepInst(GetElementPtrInst *GepI, ValueToNodeMap &NM);
1260b57cec5SDimitry Andric     void collect();
1270b57cec5SDimitry Andric     void common();
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric     BasicBlock *recalculatePlacement(GepNode *Node, NodeChildrenMap &NCM,
1300b57cec5SDimitry Andric                                      NodeToValueMap &Loc);
1310b57cec5SDimitry Andric     BasicBlock *recalculatePlacementRec(GepNode *Node, NodeChildrenMap &NCM,
1320b57cec5SDimitry Andric                                         NodeToValueMap &Loc);
1330b57cec5SDimitry Andric     bool isInvariantIn(Value *Val, Loop *L);
1340b57cec5SDimitry Andric     bool isInvariantIn(GepNode *Node, Loop *L);
1350b57cec5SDimitry Andric     bool isInMainPath(BasicBlock *B, Loop *L);
1360b57cec5SDimitry Andric     BasicBlock *adjustForInvariance(GepNode *Node, NodeChildrenMap &NCM,
1370b57cec5SDimitry Andric                                     NodeToValueMap &Loc);
1380b57cec5SDimitry Andric     void separateChainForNode(GepNode *Node, Use *U, NodeToValueMap &Loc);
1390b57cec5SDimitry Andric     void separateConstantChains(GepNode *Node, NodeChildrenMap &NCM,
1400b57cec5SDimitry Andric                                 NodeToValueMap &Loc);
1410b57cec5SDimitry Andric     void computeNodePlacement(NodeToValueMap &Loc);
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric     Value *fabricateGEP(NodeVect &NA, BasicBlock::iterator At,
1440b57cec5SDimitry Andric                         BasicBlock *LocB);
1450b57cec5SDimitry Andric     void getAllUsersForNode(GepNode *Node, ValueVect &Values,
1460b57cec5SDimitry Andric                             NodeChildrenMap &NCM);
1470b57cec5SDimitry Andric     void materialize(NodeToValueMap &Loc);
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric     void removeDeadCode();
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric     NodeVect Nodes;
1520b57cec5SDimitry Andric     NodeToUsesMap Uses;
1530b57cec5SDimitry Andric     NodeOrdering NodeOrder;   // Node ordering, for deterministic behavior.
1540b57cec5SDimitry Andric     SpecificBumpPtrAllocator<GepNode> *Mem;
1550b57cec5SDimitry Andric     LLVMContext *Ctx;
1560b57cec5SDimitry Andric     LoopInfo *LI;
1570b57cec5SDimitry Andric     DominatorTree *DT;
1580b57cec5SDimitry Andric     PostDominatorTree *PDT;
1590b57cec5SDimitry Andric     Function *Fn;
1600b57cec5SDimitry Andric   };
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric } // end anonymous namespace
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric char HexagonCommonGEP::ID = 0;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(HexagonCommonGEP, "hcommgep", "Hexagon Common GEP",
1670b57cec5SDimitry Andric       false, false)
1680b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
1690b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
1700b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
1710b57cec5SDimitry Andric INITIALIZE_PASS_END(HexagonCommonGEP, "hcommgep", "Hexagon Common GEP",
1720b57cec5SDimitry Andric       false, false)
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric namespace {
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   struct GepNode {
1770b57cec5SDimitry Andric     enum {
1780b57cec5SDimitry Andric       None      = 0,
1790b57cec5SDimitry Andric       Root      = 0x01,
1800b57cec5SDimitry Andric       Internal  = 0x02,
1810b57cec5SDimitry Andric       Used      = 0x04,
182fe6060f1SDimitry Andric       InBounds  = 0x08,
183fe6060f1SDimitry Andric       Pointer   = 0x10,   // See note below.
1840b57cec5SDimitry Andric     };
185fe6060f1SDimitry Andric     // Note: GEP indices generally traverse nested types, and so a GepNode
186fe6060f1SDimitry Andric     // (representing a single index) can be associated with some composite
187fe6060f1SDimitry Andric     // type. The exception is the GEP input, which is a pointer, and not
188fe6060f1SDimitry Andric     // a composite type (at least not in the sense of having sub-types).
189fe6060f1SDimitry Andric     // Also, the corresponding index plays a different role as well: it is
190fe6060f1SDimitry Andric     // simply added to the input pointer. Since pointer types are becoming
191fe6060f1SDimitry Andric     // opaque (i.e. are no longer going to include the pointee type), the
192fe6060f1SDimitry Andric     // two pieces of information (1) the fact that it's a pointer, and
193fe6060f1SDimitry Andric     // (2) the pointee type, need to be stored separately. The pointee type
194fe6060f1SDimitry Andric     // will be stored in the PTy member, while the fact that the node
195fe6060f1SDimitry Andric     // operates on a pointer will be reflected by the flag "Pointer".
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric     uint32_t Flags = 0;
1980b57cec5SDimitry Andric     union {
1990b57cec5SDimitry Andric       GepNode *Parent;
2000b57cec5SDimitry Andric       Value *BaseVal;
2010b57cec5SDimitry Andric     };
2020b57cec5SDimitry Andric     Value *Idx = nullptr;
203fe6060f1SDimitry Andric     Type *PTy = nullptr;    // Type indexed by this node. For pointer nodes
204fe6060f1SDimitry Andric                             // this is the "pointee" type, and indexing a
205fe6060f1SDimitry Andric                             // pointer does not change the type.
2060b57cec5SDimitry Andric 
GepNode__anon2a64d1560211::GepNode2070b57cec5SDimitry Andric     GepNode() : Parent(nullptr) {}
GepNode__anon2a64d1560211::GepNode2080b57cec5SDimitry Andric     GepNode(const GepNode *N) : Flags(N->Flags), Idx(N->Idx), PTy(N->PTy) {
2090b57cec5SDimitry Andric       if (Flags & Root)
2100b57cec5SDimitry Andric         BaseVal = N->BaseVal;
2110b57cec5SDimitry Andric       else
2120b57cec5SDimitry Andric         Parent = N->Parent;
2130b57cec5SDimitry Andric     }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const GepNode &GN);
2160b57cec5SDimitry Andric   };
2170b57cec5SDimitry Andric 
operator <<(raw_ostream & OS,const GepNode & GN)2180b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const GepNode &GN) {
2190b57cec5SDimitry Andric     OS << "{ {";
2200b57cec5SDimitry Andric     bool Comma = false;
2210b57cec5SDimitry Andric     if (GN.Flags & GepNode::Root) {
2220b57cec5SDimitry Andric       OS << "root";
2230b57cec5SDimitry Andric       Comma = true;
2240b57cec5SDimitry Andric     }
2250b57cec5SDimitry Andric     if (GN.Flags & GepNode::Internal) {
2260b57cec5SDimitry Andric       if (Comma)
2270b57cec5SDimitry Andric         OS << ',';
2280b57cec5SDimitry Andric       OS << "internal";
2290b57cec5SDimitry Andric       Comma = true;
2300b57cec5SDimitry Andric     }
2310b57cec5SDimitry Andric     if (GN.Flags & GepNode::Used) {
2320b57cec5SDimitry Andric       if (Comma)
2330b57cec5SDimitry Andric         OS << ',';
2340b57cec5SDimitry Andric       OS << "used";
2350b57cec5SDimitry Andric     }
2360b57cec5SDimitry Andric     if (GN.Flags & GepNode::InBounds) {
2370b57cec5SDimitry Andric       if (Comma)
2380b57cec5SDimitry Andric         OS << ',';
2390b57cec5SDimitry Andric       OS << "inbounds";
2400b57cec5SDimitry Andric     }
241fe6060f1SDimitry Andric     if (GN.Flags & GepNode::Pointer) {
242fe6060f1SDimitry Andric       if (Comma)
243fe6060f1SDimitry Andric         OS << ',';
244fe6060f1SDimitry Andric       OS << "pointer";
245fe6060f1SDimitry Andric     }
2460b57cec5SDimitry Andric     OS << "} ";
2470b57cec5SDimitry Andric     if (GN.Flags & GepNode::Root)
2480b57cec5SDimitry Andric       OS << "BaseVal:" << GN.BaseVal->getName() << '(' << GN.BaseVal << ')';
2490b57cec5SDimitry Andric     else
2500b57cec5SDimitry Andric       OS << "Parent:" << GN.Parent;
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric     OS << " Idx:";
2530b57cec5SDimitry Andric     if (ConstantInt *CI = dyn_cast<ConstantInt>(GN.Idx))
2540b57cec5SDimitry Andric       OS << CI->getValue().getSExtValue();
2550b57cec5SDimitry Andric     else if (GN.Idx->hasName())
2560b57cec5SDimitry Andric       OS << GN.Idx->getName();
2570b57cec5SDimitry Andric     else
2580b57cec5SDimitry Andric       OS << "<anon> =" << *GN.Idx;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric     OS << " PTy:";
2610b57cec5SDimitry Andric     if (GN.PTy->isStructTy()) {
2620b57cec5SDimitry Andric       StructType *STy = cast<StructType>(GN.PTy);
2630b57cec5SDimitry Andric       if (!STy->isLiteral())
2640b57cec5SDimitry Andric         OS << GN.PTy->getStructName();
2650b57cec5SDimitry Andric       else
2660b57cec5SDimitry Andric         OS << "<anon-struct>:" << *STy;
2670b57cec5SDimitry Andric     }
2680b57cec5SDimitry Andric     else
2690b57cec5SDimitry Andric       OS << *GN.PTy;
2700b57cec5SDimitry Andric     OS << " }";
2710b57cec5SDimitry Andric     return OS;
2720b57cec5SDimitry Andric   }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   template <typename NodeContainer>
dump_node_container(raw_ostream & OS,const NodeContainer & S)2750b57cec5SDimitry Andric   void dump_node_container(raw_ostream &OS, const NodeContainer &S) {
2760b57cec5SDimitry Andric     using const_iterator = typename NodeContainer::const_iterator;
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric     for (const_iterator I = S.begin(), E = S.end(); I != E; ++I)
2790b57cec5SDimitry Andric       OS << *I << ' ' << **I << '\n';
2800b57cec5SDimitry Andric   }
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS,
2830b57cec5SDimitry Andric                            const NodeVect &S) LLVM_ATTRIBUTE_UNUSED;
operator <<(raw_ostream & OS,const NodeVect & S)2840b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const NodeVect &S) {
2850b57cec5SDimitry Andric     dump_node_container(OS, S);
2860b57cec5SDimitry Andric     return OS;
2870b57cec5SDimitry Andric   }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS,
2900b57cec5SDimitry Andric                            const NodeToUsesMap &M) LLVM_ATTRIBUTE_UNUSED;
operator <<(raw_ostream & OS,const NodeToUsesMap & M)2910b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const NodeToUsesMap &M){
29204eeddc0SDimitry Andric     for (const auto &I : M) {
29304eeddc0SDimitry Andric       const UseSet &Us = I.second;
29404eeddc0SDimitry Andric       OS << I.first << " -> #" << Us.size() << '{';
29504eeddc0SDimitry Andric       for (const Use *U : Us) {
29604eeddc0SDimitry Andric         User *R = U->getUser();
2970b57cec5SDimitry Andric         if (R->hasName())
2980b57cec5SDimitry Andric           OS << ' ' << R->getName();
2990b57cec5SDimitry Andric         else
3000b57cec5SDimitry Andric           OS << " <?>(" << *R << ')';
3010b57cec5SDimitry Andric       }
3020b57cec5SDimitry Andric       OS << " }\n";
3030b57cec5SDimitry Andric     }
3040b57cec5SDimitry Andric     return OS;
3050b57cec5SDimitry Andric   }
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric   struct in_set {
in_set__anon2a64d1560211::in_set3080b57cec5SDimitry Andric     in_set(const NodeSet &S) : NS(S) {}
3090b57cec5SDimitry Andric 
operator ()__anon2a64d1560211::in_set3100b57cec5SDimitry Andric     bool operator() (GepNode *N) const {
3110b57cec5SDimitry Andric       return NS.find(N) != NS.end();
3120b57cec5SDimitry Andric     }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   private:
3150b57cec5SDimitry Andric     const NodeSet &NS;
3160b57cec5SDimitry Andric   };
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric } // end anonymous namespace
3190b57cec5SDimitry Andric 
operator new(size_t,SpecificBumpPtrAllocator<GepNode> & A)3200b57cec5SDimitry Andric inline void *operator new(size_t, SpecificBumpPtrAllocator<GepNode> &A) {
3210b57cec5SDimitry Andric   return A.Allocate();
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric 
getBlockTraversalOrder(BasicBlock * Root,ValueVect & Order)3240b57cec5SDimitry Andric void HexagonCommonGEP::getBlockTraversalOrder(BasicBlock *Root,
3250b57cec5SDimitry Andric       ValueVect &Order) {
3260b57cec5SDimitry Andric   // Compute block ordering for a typical DT-based traversal of the flow
3270b57cec5SDimitry Andric   // graph: "before visiting a block, all of its dominators must have been
3280b57cec5SDimitry Andric   // visited".
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   Order.push_back(Root);
3310b57cec5SDimitry Andric   for (auto *DTN : children<DomTreeNode*>(DT->getNode(Root)))
3320b57cec5SDimitry Andric     getBlockTraversalOrder(DTN->getBlock(), Order);
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric 
isHandledGepForm(GetElementPtrInst * GepI)3350b57cec5SDimitry Andric bool HexagonCommonGEP::isHandledGepForm(GetElementPtrInst *GepI) {
3360b57cec5SDimitry Andric   // No vector GEPs.
3370b57cec5SDimitry Andric   if (!GepI->getType()->isPointerTy())
3380b57cec5SDimitry Andric     return false;
3390b57cec5SDimitry Andric   // No GEPs without any indices.  (Is this possible?)
3400b57cec5SDimitry Andric   if (GepI->idx_begin() == GepI->idx_end())
3410b57cec5SDimitry Andric     return false;
3420b57cec5SDimitry Andric   return true;
3430b57cec5SDimitry Andric }
3440b57cec5SDimitry Andric 
processGepInst(GetElementPtrInst * GepI,ValueToNodeMap & NM)3450b57cec5SDimitry Andric void HexagonCommonGEP::processGepInst(GetElementPtrInst *GepI,
3460b57cec5SDimitry Andric       ValueToNodeMap &NM) {
3470b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Visiting GEP: " << *GepI << '\n');
3480b57cec5SDimitry Andric   GepNode *N = new (*Mem) GepNode;
3490b57cec5SDimitry Andric   Value *PtrOp = GepI->getPointerOperand();
3500b57cec5SDimitry Andric   uint32_t InBounds = GepI->isInBounds() ? GepNode::InBounds : 0;
3510b57cec5SDimitry Andric   ValueToNodeMap::iterator F = NM.find(PtrOp);
3520b57cec5SDimitry Andric   if (F == NM.end()) {
3530b57cec5SDimitry Andric     N->BaseVal = PtrOp;
3540b57cec5SDimitry Andric     N->Flags |= GepNode::Root | InBounds;
3550b57cec5SDimitry Andric   } else {
3560b57cec5SDimitry Andric     // If PtrOp was a GEP instruction, it must have already been processed.
3570b57cec5SDimitry Andric     // The ValueToNodeMap entry for it is the last gep node in the generated
3580b57cec5SDimitry Andric     // chain. Link to it here.
3590b57cec5SDimitry Andric     N->Parent = F->second;
3600b57cec5SDimitry Andric   }
361fe6060f1SDimitry Andric   N->PTy = GepI->getSourceElementType();
362fe6060f1SDimitry Andric   N->Flags |= GepNode::Pointer;
3630b57cec5SDimitry Andric   N->Idx = *GepI->idx_begin();
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   // Collect the list of users of this GEP instruction. Will add it to the
3660b57cec5SDimitry Andric   // last node created for it.
3670b57cec5SDimitry Andric   UseSet Us;
3680b57cec5SDimitry Andric   for (Value::user_iterator UI = GepI->user_begin(), UE = GepI->user_end();
3690b57cec5SDimitry Andric        UI != UE; ++UI) {
3700b57cec5SDimitry Andric     // Check if this gep is used by anything other than other geps that
3710b57cec5SDimitry Andric     // we will process.
3720b57cec5SDimitry Andric     if (isa<GetElementPtrInst>(*UI)) {
3730b57cec5SDimitry Andric       GetElementPtrInst *UserG = cast<GetElementPtrInst>(*UI);
3740b57cec5SDimitry Andric       if (isHandledGepForm(UserG))
3750b57cec5SDimitry Andric         continue;
3760b57cec5SDimitry Andric     }
3770b57cec5SDimitry Andric     Us.insert(&UI.getUse());
3780b57cec5SDimitry Andric   }
3790b57cec5SDimitry Andric   Nodes.push_back(N);
3800b57cec5SDimitry Andric   NodeOrder.insert(N);
3810b57cec5SDimitry Andric 
382fe6060f1SDimitry Andric   // Skip the first index operand, since it was already handled above. This
383fe6060f1SDimitry Andric   // dereferences the pointer operand.
3840b57cec5SDimitry Andric   GepNode *PN = N;
385fe6060f1SDimitry Andric   Type *PtrTy = GepI->getSourceElementType();
386349cc55cSDimitry Andric   for (Use &U : llvm::drop_begin(GepI->indices())) {
387349cc55cSDimitry Andric     Value *Op = U;
3880b57cec5SDimitry Andric     GepNode *Nx = new (*Mem) GepNode;
3890b57cec5SDimitry Andric     Nx->Parent = PN;  // Link Nx to the previous node.
3900b57cec5SDimitry Andric     Nx->Flags |= GepNode::Internal | InBounds;
3910b57cec5SDimitry Andric     Nx->PTy = PtrTy;
3920b57cec5SDimitry Andric     Nx->Idx = Op;
3930b57cec5SDimitry Andric     Nodes.push_back(Nx);
3940b57cec5SDimitry Andric     NodeOrder.insert(Nx);
3950b57cec5SDimitry Andric     PN = Nx;
3960b57cec5SDimitry Andric 
397fe6060f1SDimitry Andric     PtrTy = GetElementPtrInst::getTypeAtIndex(PtrTy, Op);
3980b57cec5SDimitry Andric   }
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   // After last node has been created, update the use information.
4010b57cec5SDimitry Andric   if (!Us.empty()) {
4020b57cec5SDimitry Andric     PN->Flags |= GepNode::Used;
4030b57cec5SDimitry Andric     Uses[PN].insert(Us.begin(), Us.end());
4040b57cec5SDimitry Andric   }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   // Link the last node with the originating GEP instruction. This is to
4070b57cec5SDimitry Andric   // help with linking chained GEP instructions.
4080b57cec5SDimitry Andric   NM.insert(std::make_pair(GepI, PN));
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric 
collect()4110b57cec5SDimitry Andric void HexagonCommonGEP::collect() {
4120b57cec5SDimitry Andric   // Establish depth-first traversal order of the dominator tree.
4130b57cec5SDimitry Andric   ValueVect BO;
4140b57cec5SDimitry Andric   getBlockTraversalOrder(&Fn->front(), BO);
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   // The creation of gep nodes requires DT-traversal. When processing a GEP
4170b57cec5SDimitry Andric   // instruction that uses another GEP instruction as the base pointer, the
4180b57cec5SDimitry Andric   // gep node for the base pointer should already exist.
4190b57cec5SDimitry Andric   ValueToNodeMap NM;
42004eeddc0SDimitry Andric   for (Value *I : BO) {
42104eeddc0SDimitry Andric     BasicBlock *B = cast<BasicBlock>(I);
42204eeddc0SDimitry Andric     for (Instruction &J : *B)
42304eeddc0SDimitry Andric       if (auto *GepI = dyn_cast<GetElementPtrInst>(&J))
4240b57cec5SDimitry Andric         if (isHandledGepForm(GepI))
4250b57cec5SDimitry Andric           processGepInst(GepI, NM);
4260b57cec5SDimitry Andric   }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Gep nodes after initial collection:\n" << Nodes);
4290b57cec5SDimitry Andric }
4300b57cec5SDimitry Andric 
invert_find_roots(const NodeVect & Nodes,NodeChildrenMap & NCM,NodeVect & Roots)4310b57cec5SDimitry Andric static void invert_find_roots(const NodeVect &Nodes, NodeChildrenMap &NCM,
4320b57cec5SDimitry Andric                               NodeVect &Roots) {
43304eeddc0SDimitry Andric   for (GepNode *N : Nodes) {
4340b57cec5SDimitry Andric     if (N->Flags & GepNode::Root) {
4350b57cec5SDimitry Andric       Roots.push_back(N);
4360b57cec5SDimitry Andric       continue;
4370b57cec5SDimitry Andric     }
4380b57cec5SDimitry Andric     GepNode *PN = N->Parent;
4390b57cec5SDimitry Andric     NCM[PN].push_back(N);
4400b57cec5SDimitry Andric   }
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric 
nodes_for_root(GepNode * Root,NodeChildrenMap & NCM,NodeSet & Nodes)4430b57cec5SDimitry Andric static void nodes_for_root(GepNode *Root, NodeChildrenMap &NCM,
4440b57cec5SDimitry Andric                            NodeSet &Nodes) {
4450b57cec5SDimitry Andric     NodeVect Work;
4460b57cec5SDimitry Andric     Work.push_back(Root);
4470b57cec5SDimitry Andric     Nodes.insert(Root);
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric     while (!Work.empty()) {
4500b57cec5SDimitry Andric       NodeVect::iterator First = Work.begin();
4510b57cec5SDimitry Andric       GepNode *N = *First;
4520b57cec5SDimitry Andric       Work.erase(First);
4530b57cec5SDimitry Andric       NodeChildrenMap::iterator CF = NCM.find(N);
4540b57cec5SDimitry Andric       if (CF != NCM.end()) {
455e8d8bef9SDimitry Andric         llvm::append_range(Work, CF->second);
4560b57cec5SDimitry Andric         Nodes.insert(CF->second.begin(), CF->second.end());
4570b57cec5SDimitry Andric       }
4580b57cec5SDimitry Andric     }
4590b57cec5SDimitry Andric }
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric namespace {
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric   using NodeSymRel = std::set<NodeSet>;
4640b57cec5SDimitry Andric   using NodePair = std::pair<GepNode *, GepNode *>;
4650b57cec5SDimitry Andric   using NodePairSet = std::set<NodePair>;
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric } // end anonymous namespace
4680b57cec5SDimitry Andric 
node_class(GepNode * N,NodeSymRel & Rel)4690b57cec5SDimitry Andric static const NodeSet *node_class(GepNode *N, NodeSymRel &Rel) {
4704824e7fdSDimitry Andric   for (const NodeSet &S : Rel)
4714824e7fdSDimitry Andric     if (S.count(N))
4724824e7fdSDimitry Andric       return &S;
4730b57cec5SDimitry Andric   return nullptr;
4740b57cec5SDimitry Andric }
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   // Create an ordered pair of GepNode pointers. The pair will be used in
4770b57cec5SDimitry Andric   // determining equality. The only purpose of the ordering is to eliminate
4780b57cec5SDimitry Andric   // duplication due to the commutativity of equality/non-equality.
node_pair(GepNode * N1,GepNode * N2)4790b57cec5SDimitry Andric static NodePair node_pair(GepNode *N1, GepNode *N2) {
480e8d8bef9SDimitry Andric   uintptr_t P1 = reinterpret_cast<uintptr_t>(N1);
481e8d8bef9SDimitry Andric   uintptr_t P2 = reinterpret_cast<uintptr_t>(N2);
4820b57cec5SDimitry Andric   if (P1 <= P2)
4830b57cec5SDimitry Andric     return std::make_pair(N1, N2);
4840b57cec5SDimitry Andric   return std::make_pair(N2, N1);
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric 
node_hash(GepNode * N)4870b57cec5SDimitry Andric static unsigned node_hash(GepNode *N) {
4880b57cec5SDimitry Andric     // Include everything except flags and parent.
4890b57cec5SDimitry Andric     FoldingSetNodeID ID;
4900b57cec5SDimitry Andric     ID.AddPointer(N->Idx);
4910b57cec5SDimitry Andric     ID.AddPointer(N->PTy);
4920b57cec5SDimitry Andric     return ID.ComputeHash();
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric 
node_eq(GepNode * N1,GepNode * N2,NodePairSet & Eq,NodePairSet & Ne)4950b57cec5SDimitry Andric static bool node_eq(GepNode *N1, GepNode *N2, NodePairSet &Eq,
4960b57cec5SDimitry Andric                     NodePairSet &Ne) {
4970b57cec5SDimitry Andric     // Don't cache the result for nodes with different hashes. The hash
4980b57cec5SDimitry Andric     // comparison is fast enough.
4990b57cec5SDimitry Andric     if (node_hash(N1) != node_hash(N2))
5000b57cec5SDimitry Andric       return false;
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric     NodePair NP = node_pair(N1, N2);
5030b57cec5SDimitry Andric     NodePairSet::iterator FEq = Eq.find(NP);
5040b57cec5SDimitry Andric     if (FEq != Eq.end())
5050b57cec5SDimitry Andric       return true;
5060b57cec5SDimitry Andric     NodePairSet::iterator FNe = Ne.find(NP);
5070b57cec5SDimitry Andric     if (FNe != Ne.end())
5080b57cec5SDimitry Andric       return false;
5090b57cec5SDimitry Andric     // Not previously compared.
5100b57cec5SDimitry Andric     bool Root1 = N1->Flags & GepNode::Root;
511fe6060f1SDimitry Andric     uint32_t CmpFlags = GepNode::Root | GepNode::Pointer;
512fe6060f1SDimitry Andric     bool Different = (N1->Flags & CmpFlags) != (N2->Flags & CmpFlags);
5130b57cec5SDimitry Andric     NodePair P = node_pair(N1, N2);
514fe6060f1SDimitry Andric     // If the root/pointer flags have different values, the nodes are
515fe6060f1SDimitry Andric     // different.
5160b57cec5SDimitry Andric     // If both nodes are root nodes, but their base pointers differ,
5170b57cec5SDimitry Andric     // they are different.
518fe6060f1SDimitry Andric     if (Different || (Root1 && N1->BaseVal != N2->BaseVal)) {
5190b57cec5SDimitry Andric       Ne.insert(P);
5200b57cec5SDimitry Andric       return false;
5210b57cec5SDimitry Andric     }
522fe6060f1SDimitry Andric     // Here the root/pointer flags are identical, and for root nodes the
5230b57cec5SDimitry Andric     // base pointers are equal, so the root nodes are equal.
5240b57cec5SDimitry Andric     // For non-root nodes, compare their parent nodes.
5250b57cec5SDimitry Andric     if (Root1 || node_eq(N1->Parent, N2->Parent, Eq, Ne)) {
5260b57cec5SDimitry Andric       Eq.insert(P);
5270b57cec5SDimitry Andric       return true;
5280b57cec5SDimitry Andric     }
5290b57cec5SDimitry Andric     return false;
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric 
common()5320b57cec5SDimitry Andric void HexagonCommonGEP::common() {
5330b57cec5SDimitry Andric   // The essence of this commoning is finding gep nodes that are equal.
5340b57cec5SDimitry Andric   // To do this we need to compare all pairs of nodes. To save time,
5350b57cec5SDimitry Andric   // first, partition the set of all nodes into sets of potentially equal
5360b57cec5SDimitry Andric   // nodes, and then compare pairs from within each partition.
5370b57cec5SDimitry Andric   using NodeSetMap = std::map<unsigned, NodeSet>;
5380b57cec5SDimitry Andric   NodeSetMap MaybeEq;
5390b57cec5SDimitry Andric 
54004eeddc0SDimitry Andric   for (GepNode *N : Nodes) {
5410b57cec5SDimitry Andric     unsigned H = node_hash(N);
5420b57cec5SDimitry Andric     MaybeEq[H].insert(N);
5430b57cec5SDimitry Andric   }
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric   // Compute the equivalence relation for the gep nodes.  Use two caches,
5460b57cec5SDimitry Andric   // one for equality and the other for non-equality.
5470b57cec5SDimitry Andric   NodeSymRel EqRel;  // Equality relation (as set of equivalence classes).
5480b57cec5SDimitry Andric   NodePairSet Eq, Ne;  // Caches.
54904eeddc0SDimitry Andric   for (auto &I : MaybeEq) {
55004eeddc0SDimitry Andric     NodeSet &S = I.second;
5510b57cec5SDimitry Andric     for (NodeSet::iterator NI = S.begin(), NE = S.end(); NI != NE; ++NI) {
5520b57cec5SDimitry Andric       GepNode *N = *NI;
5530b57cec5SDimitry Andric       // If node already has a class, then the class must have been created
5540b57cec5SDimitry Andric       // in a prior iteration of this loop. Since equality is transitive,
5550b57cec5SDimitry Andric       // nothing more will be added to that class, so skip it.
5560b57cec5SDimitry Andric       if (node_class(N, EqRel))
5570b57cec5SDimitry Andric         continue;
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric       // Create a new class candidate now.
5600b57cec5SDimitry Andric       NodeSet C;
5610b57cec5SDimitry Andric       for (NodeSet::iterator NJ = std::next(NI); NJ != NE; ++NJ)
5620b57cec5SDimitry Andric         if (node_eq(N, *NJ, Eq, Ne))
5630b57cec5SDimitry Andric           C.insert(*NJ);
5640b57cec5SDimitry Andric       // If Tmp is empty, N would be the only element in it. Don't bother
5650b57cec5SDimitry Andric       // creating a class for it then.
5660b57cec5SDimitry Andric       if (!C.empty()) {
5670b57cec5SDimitry Andric         C.insert(N);  // Finalize the set before adding it to the relation.
5680b57cec5SDimitry Andric         std::pair<NodeSymRel::iterator, bool> Ins = EqRel.insert(C);
5690b57cec5SDimitry Andric         (void)Ins;
5700b57cec5SDimitry Andric         assert(Ins.second && "Cannot add a class");
5710b57cec5SDimitry Andric       }
5720b57cec5SDimitry Andric     }
5730b57cec5SDimitry Andric   }
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric   LLVM_DEBUG({
5760b57cec5SDimitry Andric     dbgs() << "Gep node equality:\n";
5770b57cec5SDimitry Andric     for (NodePairSet::iterator I = Eq.begin(), E = Eq.end(); I != E; ++I)
5780b57cec5SDimitry Andric       dbgs() << "{ " << I->first << ", " << I->second << " }\n";
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric     dbgs() << "Gep equivalence classes:\n";
5814824e7fdSDimitry Andric     for (const NodeSet &S : EqRel) {
5820b57cec5SDimitry Andric       dbgs() << '{';
5830b57cec5SDimitry Andric       for (NodeSet::const_iterator J = S.begin(), F = S.end(); J != F; ++J) {
5840b57cec5SDimitry Andric         if (J != S.begin())
5850b57cec5SDimitry Andric           dbgs() << ',';
5860b57cec5SDimitry Andric         dbgs() << ' ' << *J;
5870b57cec5SDimitry Andric       }
5880b57cec5SDimitry Andric       dbgs() << " }\n";
5890b57cec5SDimitry Andric     }
5900b57cec5SDimitry Andric   });
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   // Create a projection from a NodeSet to the minimal element in it.
5930b57cec5SDimitry Andric   using ProjMap = std::map<const NodeSet *, GepNode *>;
5940b57cec5SDimitry Andric   ProjMap PM;
5954824e7fdSDimitry Andric   for (const NodeSet &S : EqRel) {
5960b57cec5SDimitry Andric     GepNode *Min = *std::min_element(S.begin(), S.end(), NodeOrder);
5970b57cec5SDimitry Andric     std::pair<ProjMap::iterator,bool> Ins = PM.insert(std::make_pair(&S, Min));
5980b57cec5SDimitry Andric     (void)Ins;
5990b57cec5SDimitry Andric     assert(Ins.second && "Cannot add minimal element");
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric     // Update the min element's flags, and user list.
6020b57cec5SDimitry Andric     uint32_t Flags = 0;
6030b57cec5SDimitry Andric     UseSet &MinUs = Uses[Min];
60404eeddc0SDimitry Andric     for (GepNode *N : S) {
6050b57cec5SDimitry Andric       uint32_t NF = N->Flags;
6060b57cec5SDimitry Andric       // If N is used, append all original values of N to the list of
6070b57cec5SDimitry Andric       // original values of Min.
6080b57cec5SDimitry Andric       if (NF & GepNode::Used)
6090b57cec5SDimitry Andric         MinUs.insert(Uses[N].begin(), Uses[N].end());
6100b57cec5SDimitry Andric       Flags |= NF;
6110b57cec5SDimitry Andric     }
6120b57cec5SDimitry Andric     if (MinUs.empty())
6130b57cec5SDimitry Andric       Uses.erase(Min);
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric     // The collected flags should include all the flags from the min element.
6160b57cec5SDimitry Andric     assert((Min->Flags & Flags) == Min->Flags);
6170b57cec5SDimitry Andric     Min->Flags = Flags;
6180b57cec5SDimitry Andric   }
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric   // Commoning: for each non-root gep node, replace "Parent" with the
6210b57cec5SDimitry Andric   // selected (minimum) node from the corresponding equivalence class.
6220b57cec5SDimitry Andric   // If a given parent does not have an equivalence class, leave it
6230b57cec5SDimitry Andric   // unchanged (it means that it's the only element in its class).
62404eeddc0SDimitry Andric   for (GepNode *N : Nodes) {
6250b57cec5SDimitry Andric     if (N->Flags & GepNode::Root)
6260b57cec5SDimitry Andric       continue;
6270b57cec5SDimitry Andric     const NodeSet *PC = node_class(N->Parent, EqRel);
6280b57cec5SDimitry Andric     if (!PC)
6290b57cec5SDimitry Andric       continue;
6300b57cec5SDimitry Andric     ProjMap::iterator F = PM.find(PC);
6310b57cec5SDimitry Andric     if (F == PM.end())
6320b57cec5SDimitry Andric       continue;
6330b57cec5SDimitry Andric     // Found a replacement, use it.
6340b57cec5SDimitry Andric     GepNode *Rep = F->second;
6350b57cec5SDimitry Andric     N->Parent = Rep;
6360b57cec5SDimitry Andric   }
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Gep nodes after commoning:\n" << Nodes);
6390b57cec5SDimitry Andric 
6400b57cec5SDimitry Andric   // Finally, erase the nodes that are no longer used.
6410b57cec5SDimitry Andric   NodeSet Erase;
64204eeddc0SDimitry Andric   for (GepNode *N : Nodes) {
6430b57cec5SDimitry Andric     const NodeSet *PC = node_class(N, EqRel);
6440b57cec5SDimitry Andric     if (!PC)
6450b57cec5SDimitry Andric       continue;
6460b57cec5SDimitry Andric     ProjMap::iterator F = PM.find(PC);
6470b57cec5SDimitry Andric     if (F == PM.end())
6480b57cec5SDimitry Andric       continue;
6490b57cec5SDimitry Andric     if (N == F->second)
6500b57cec5SDimitry Andric       continue;
6510b57cec5SDimitry Andric     // Node for removal.
65204eeddc0SDimitry Andric     Erase.insert(N);
6530b57cec5SDimitry Andric   }
654e8d8bef9SDimitry Andric   erase_if(Nodes, in_set(Erase));
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Gep nodes after post-commoning cleanup:\n" << Nodes);
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric template <typename T>
nearest_common_dominator(DominatorTree * DT,T & Blocks)6600b57cec5SDimitry Andric static BasicBlock *nearest_common_dominator(DominatorTree *DT, T &Blocks) {
6610b57cec5SDimitry Andric   LLVM_DEBUG({
6620b57cec5SDimitry Andric     dbgs() << "NCD of {";
6630b57cec5SDimitry Andric     for (typename T::iterator I = Blocks.begin(), E = Blocks.end(); I != E;
6640b57cec5SDimitry Andric          ++I) {
6650b57cec5SDimitry Andric       if (!*I)
6660b57cec5SDimitry Andric         continue;
6670b57cec5SDimitry Andric       BasicBlock *B = cast<BasicBlock>(*I);
6680b57cec5SDimitry Andric       dbgs() << ' ' << B->getName();
6690b57cec5SDimitry Andric     }
6700b57cec5SDimitry Andric     dbgs() << " }\n";
6710b57cec5SDimitry Andric   });
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric   // Allow null basic blocks in Blocks.  In such cases, return nullptr.
6740b57cec5SDimitry Andric   typename T::iterator I = Blocks.begin(), E = Blocks.end();
6750b57cec5SDimitry Andric   if (I == E || !*I)
6760b57cec5SDimitry Andric     return nullptr;
6770b57cec5SDimitry Andric   BasicBlock *Dom = cast<BasicBlock>(*I);
6780b57cec5SDimitry Andric   while (++I != E) {
6790b57cec5SDimitry Andric     BasicBlock *B = cast_or_null<BasicBlock>(*I);
6800b57cec5SDimitry Andric     Dom = B ? DT->findNearestCommonDominator(Dom, B) : nullptr;
6810b57cec5SDimitry Andric     if (!Dom)
6820b57cec5SDimitry Andric       return nullptr;
6830b57cec5SDimitry Andric     }
6840b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "computed:" << Dom->getName() << '\n');
6850b57cec5SDimitry Andric     return Dom;
6860b57cec5SDimitry Andric }
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric template <typename T>
nearest_common_dominatee(DominatorTree * DT,T & Blocks)6890b57cec5SDimitry Andric static BasicBlock *nearest_common_dominatee(DominatorTree *DT, T &Blocks) {
6900b57cec5SDimitry Andric     // If two blocks, A and B, dominate a block C, then A dominates B,
6910b57cec5SDimitry Andric     // or B dominates A.
6920b57cec5SDimitry Andric     typename T::iterator I = Blocks.begin(), E = Blocks.end();
6930b57cec5SDimitry Andric     // Find the first non-null block.
6940b57cec5SDimitry Andric     while (I != E && !*I)
6950b57cec5SDimitry Andric       ++I;
6960b57cec5SDimitry Andric     if (I == E)
6970b57cec5SDimitry Andric       return DT->getRoot();
6980b57cec5SDimitry Andric     BasicBlock *DomB = cast<BasicBlock>(*I);
6990b57cec5SDimitry Andric     while (++I != E) {
7000b57cec5SDimitry Andric       if (!*I)
7010b57cec5SDimitry Andric         continue;
7020b57cec5SDimitry Andric       BasicBlock *B = cast<BasicBlock>(*I);
7030b57cec5SDimitry Andric       if (DT->dominates(B, DomB))
7040b57cec5SDimitry Andric         continue;
7050b57cec5SDimitry Andric       if (!DT->dominates(DomB, B))
7060b57cec5SDimitry Andric         return nullptr;
7070b57cec5SDimitry Andric       DomB = B;
7080b57cec5SDimitry Andric     }
7090b57cec5SDimitry Andric     return DomB;
7100b57cec5SDimitry Andric }
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric // Find the first use in B of any value from Values. If no such use,
7130b57cec5SDimitry Andric // return B->end().
7140b57cec5SDimitry Andric template <typename T>
first_use_of_in_block(T & Values,BasicBlock * B)7150b57cec5SDimitry Andric static BasicBlock::iterator first_use_of_in_block(T &Values, BasicBlock *B) {
7160b57cec5SDimitry Andric     BasicBlock::iterator FirstUse = B->end(), BEnd = B->end();
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric     using iterator = typename T::iterator;
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric     for (iterator I = Values.begin(), E = Values.end(); I != E; ++I) {
7210b57cec5SDimitry Andric       Value *V = *I;
7220b57cec5SDimitry Andric       // If V is used in a PHI node, the use belongs to the incoming block,
7230b57cec5SDimitry Andric       // not the block with the PHI node. In the incoming block, the use
7240b57cec5SDimitry Andric       // would be considered as being at the end of it, so it cannot
7250b57cec5SDimitry Andric       // influence the position of the first use (which is assumed to be
7260b57cec5SDimitry Andric       // at the end to start with).
7270b57cec5SDimitry Andric       if (isa<PHINode>(V))
7280b57cec5SDimitry Andric         continue;
7290b57cec5SDimitry Andric       if (!isa<Instruction>(V))
7300b57cec5SDimitry Andric         continue;
7310b57cec5SDimitry Andric       Instruction *In = cast<Instruction>(V);
7320b57cec5SDimitry Andric       if (In->getParent() != B)
7330b57cec5SDimitry Andric         continue;
7340b57cec5SDimitry Andric       BasicBlock::iterator It = In->getIterator();
7350b57cec5SDimitry Andric       if (std::distance(FirstUse, BEnd) < std::distance(It, BEnd))
7360b57cec5SDimitry Andric         FirstUse = It;
7370b57cec5SDimitry Andric     }
7380b57cec5SDimitry Andric     return FirstUse;
7390b57cec5SDimitry Andric }
7400b57cec5SDimitry Andric 
is_empty(const BasicBlock * B)7410b57cec5SDimitry Andric static bool is_empty(const BasicBlock *B) {
7420b57cec5SDimitry Andric     return B->empty() || (&*B->begin() == B->getTerminator());
7430b57cec5SDimitry Andric }
7440b57cec5SDimitry Andric 
recalculatePlacement(GepNode * Node,NodeChildrenMap & NCM,NodeToValueMap & Loc)7450b57cec5SDimitry Andric BasicBlock *HexagonCommonGEP::recalculatePlacement(GepNode *Node,
7460b57cec5SDimitry Andric       NodeChildrenMap &NCM, NodeToValueMap &Loc) {
7470b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Loc for node:" << Node << '\n');
7480b57cec5SDimitry Andric   // Recalculate the placement for Node, assuming that the locations of
7490b57cec5SDimitry Andric   // its children in Loc are valid.
7500b57cec5SDimitry Andric   // Return nullptr if there is no valid placement for Node (for example, it
7510b57cec5SDimitry Andric   // uses an index value that is not available at the location required
7520b57cec5SDimitry Andric   // to dominate all children, etc.).
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   // Find the nearest common dominator for:
7550b57cec5SDimitry Andric   // - all users, if the node is used, and
7560b57cec5SDimitry Andric   // - all children.
7570b57cec5SDimitry Andric   ValueVect Bs;
7580b57cec5SDimitry Andric   if (Node->Flags & GepNode::Used) {
7590b57cec5SDimitry Andric     // Append all blocks with uses of the original values to the
7600b57cec5SDimitry Andric     // block vector Bs.
7610b57cec5SDimitry Andric     NodeToUsesMap::iterator UF = Uses.find(Node);
7620b57cec5SDimitry Andric     assert(UF != Uses.end() && "Used node with no use information");
7630b57cec5SDimitry Andric     UseSet &Us = UF->second;
76404eeddc0SDimitry Andric     for (Use *U : Us) {
7650b57cec5SDimitry Andric       User *R = U->getUser();
7660b57cec5SDimitry Andric       if (!isa<Instruction>(R))
7670b57cec5SDimitry Andric         continue;
7680b57cec5SDimitry Andric       BasicBlock *PB = isa<PHINode>(R)
7690b57cec5SDimitry Andric           ? cast<PHINode>(R)->getIncomingBlock(*U)
7700b57cec5SDimitry Andric           : cast<Instruction>(R)->getParent();
7710b57cec5SDimitry Andric       Bs.push_back(PB);
7720b57cec5SDimitry Andric     }
7730b57cec5SDimitry Andric   }
7740b57cec5SDimitry Andric   // Append the location of each child.
7750b57cec5SDimitry Andric   NodeChildrenMap::iterator CF = NCM.find(Node);
7760b57cec5SDimitry Andric   if (CF != NCM.end()) {
7770b57cec5SDimitry Andric     NodeVect &Cs = CF->second;
77804eeddc0SDimitry Andric     for (GepNode *CN : Cs) {
7790b57cec5SDimitry Andric       NodeToValueMap::iterator LF = Loc.find(CN);
7800b57cec5SDimitry Andric       // If the child is only used in GEP instructions (i.e. is not used in
7810b57cec5SDimitry Andric       // non-GEP instructions), the nearest dominator computed for it may
7820b57cec5SDimitry Andric       // have been null. In such case it won't have a location available.
7830b57cec5SDimitry Andric       if (LF == Loc.end())
7840b57cec5SDimitry Andric         continue;
7850b57cec5SDimitry Andric       Bs.push_back(LF->second);
7860b57cec5SDimitry Andric     }
7870b57cec5SDimitry Andric   }
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   BasicBlock *DomB = nearest_common_dominator(DT, Bs);
7900b57cec5SDimitry Andric   if (!DomB)
7910b57cec5SDimitry Andric     return nullptr;
7920b57cec5SDimitry Andric   // Check if the index used by Node dominates the computed dominator.
7930b57cec5SDimitry Andric   Instruction *IdxI = dyn_cast<Instruction>(Node->Idx);
7940b57cec5SDimitry Andric   if (IdxI && !DT->dominates(IdxI->getParent(), DomB))
7950b57cec5SDimitry Andric     return nullptr;
7960b57cec5SDimitry Andric 
7970b57cec5SDimitry Andric   // Avoid putting nodes into empty blocks.
7980b57cec5SDimitry Andric   while (is_empty(DomB)) {
7990b57cec5SDimitry Andric     DomTreeNode *N = (*DT)[DomB]->getIDom();
8000b57cec5SDimitry Andric     if (!N)
8010b57cec5SDimitry Andric       break;
8020b57cec5SDimitry Andric     DomB = N->getBlock();
8030b57cec5SDimitry Andric   }
8040b57cec5SDimitry Andric 
8050b57cec5SDimitry Andric   // Otherwise, DomB is fine. Update the location map.
8060b57cec5SDimitry Andric   Loc[Node] = DomB;
8070b57cec5SDimitry Andric   return DomB;
8080b57cec5SDimitry Andric }
8090b57cec5SDimitry Andric 
recalculatePlacementRec(GepNode * Node,NodeChildrenMap & NCM,NodeToValueMap & Loc)8100b57cec5SDimitry Andric BasicBlock *HexagonCommonGEP::recalculatePlacementRec(GepNode *Node,
8110b57cec5SDimitry Andric       NodeChildrenMap &NCM, NodeToValueMap &Loc) {
8120b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "LocRec begin for node:" << Node << '\n');
8130b57cec5SDimitry Andric   // Recalculate the placement of Node, after recursively recalculating the
8140b57cec5SDimitry Andric   // placements of all its children.
8150b57cec5SDimitry Andric   NodeChildrenMap::iterator CF = NCM.find(Node);
8160b57cec5SDimitry Andric   if (CF != NCM.end()) {
8170b57cec5SDimitry Andric     NodeVect &Cs = CF->second;
81804eeddc0SDimitry Andric     for (GepNode *C : Cs)
81904eeddc0SDimitry Andric       recalculatePlacementRec(C, NCM, Loc);
8200b57cec5SDimitry Andric   }
8210b57cec5SDimitry Andric   BasicBlock *LB = recalculatePlacement(Node, NCM, Loc);
8220b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "LocRec end for node:" << Node << '\n');
8230b57cec5SDimitry Andric   return LB;
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric 
isInvariantIn(Value * Val,Loop * L)8260b57cec5SDimitry Andric bool HexagonCommonGEP::isInvariantIn(Value *Val, Loop *L) {
8270b57cec5SDimitry Andric   if (isa<Constant>(Val) || isa<Argument>(Val))
8280b57cec5SDimitry Andric     return true;
8290b57cec5SDimitry Andric   Instruction *In = dyn_cast<Instruction>(Val);
8300b57cec5SDimitry Andric   if (!In)
8310b57cec5SDimitry Andric     return false;
8320b57cec5SDimitry Andric   BasicBlock *HdrB = L->getHeader(), *DefB = In->getParent();
8330b57cec5SDimitry Andric   return DT->properlyDominates(DefB, HdrB);
8340b57cec5SDimitry Andric }
8350b57cec5SDimitry Andric 
isInvariantIn(GepNode * Node,Loop * L)8360b57cec5SDimitry Andric bool HexagonCommonGEP::isInvariantIn(GepNode *Node, Loop *L) {
8370b57cec5SDimitry Andric   if (Node->Flags & GepNode::Root)
8380b57cec5SDimitry Andric     if (!isInvariantIn(Node->BaseVal, L))
8390b57cec5SDimitry Andric       return false;
8400b57cec5SDimitry Andric   return isInvariantIn(Node->Idx, L);
8410b57cec5SDimitry Andric }
8420b57cec5SDimitry Andric 
isInMainPath(BasicBlock * B,Loop * L)8430b57cec5SDimitry Andric bool HexagonCommonGEP::isInMainPath(BasicBlock *B, Loop *L) {
8440b57cec5SDimitry Andric   BasicBlock *HB = L->getHeader();
8450b57cec5SDimitry Andric   BasicBlock *LB = L->getLoopLatch();
8460b57cec5SDimitry Andric   // B must post-dominate the loop header or dominate the loop latch.
8470b57cec5SDimitry Andric   if (PDT->dominates(B, HB))
8480b57cec5SDimitry Andric     return true;
8490b57cec5SDimitry Andric   if (LB && DT->dominates(B, LB))
8500b57cec5SDimitry Andric     return true;
8510b57cec5SDimitry Andric   return false;
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric 
preheader(DominatorTree * DT,Loop * L)8540b57cec5SDimitry Andric static BasicBlock *preheader(DominatorTree *DT, Loop *L) {
8550b57cec5SDimitry Andric   if (BasicBlock *PH = L->getLoopPreheader())
8560b57cec5SDimitry Andric     return PH;
8570b57cec5SDimitry Andric   if (!OptSpeculate)
8580b57cec5SDimitry Andric     return nullptr;
8590b57cec5SDimitry Andric   DomTreeNode *DN = DT->getNode(L->getHeader());
8600b57cec5SDimitry Andric   if (!DN)
8610b57cec5SDimitry Andric     return nullptr;
8620b57cec5SDimitry Andric   return DN->getIDom()->getBlock();
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric 
adjustForInvariance(GepNode * Node,NodeChildrenMap & NCM,NodeToValueMap & Loc)8650b57cec5SDimitry Andric BasicBlock *HexagonCommonGEP::adjustForInvariance(GepNode *Node,
8660b57cec5SDimitry Andric       NodeChildrenMap &NCM, NodeToValueMap &Loc) {
8670b57cec5SDimitry Andric   // Find the "topmost" location for Node: it must be dominated by both,
8680b57cec5SDimitry Andric   // its parent (or the BaseVal, if it's a root node), and by the index
8690b57cec5SDimitry Andric   // value.
8700b57cec5SDimitry Andric   ValueVect Bs;
8710b57cec5SDimitry Andric   if (Node->Flags & GepNode::Root) {
8720b57cec5SDimitry Andric     if (Instruction *PIn = dyn_cast<Instruction>(Node->BaseVal))
8730b57cec5SDimitry Andric       Bs.push_back(PIn->getParent());
8740b57cec5SDimitry Andric   } else {
8750b57cec5SDimitry Andric     Bs.push_back(Loc[Node->Parent]);
8760b57cec5SDimitry Andric   }
8770b57cec5SDimitry Andric   if (Instruction *IIn = dyn_cast<Instruction>(Node->Idx))
8780b57cec5SDimitry Andric     Bs.push_back(IIn->getParent());
8790b57cec5SDimitry Andric   BasicBlock *TopB = nearest_common_dominatee(DT, Bs);
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric   // Traverse the loop nest upwards until we find a loop in which Node
8820b57cec5SDimitry Andric   // is no longer invariant, or until we get to the upper limit of Node's
8830b57cec5SDimitry Andric   // placement. The traversal will also stop when a suitable "preheader"
8840b57cec5SDimitry Andric   // cannot be found for a given loop. The "preheader" may actually be
8850b57cec5SDimitry Andric   // a regular block outside of the loop (i.e. not guarded), in which case
8860b57cec5SDimitry Andric   // the Node will be speculated.
8870b57cec5SDimitry Andric   // For nodes that are not in the main path of the containing loop (i.e.
8880b57cec5SDimitry Andric   // are not executed in each iteration), do not move them out of the loop.
8890b57cec5SDimitry Andric   BasicBlock *LocB = cast_or_null<BasicBlock>(Loc[Node]);
8900b57cec5SDimitry Andric   if (LocB) {
8910b57cec5SDimitry Andric     Loop *Lp = LI->getLoopFor(LocB);
8920b57cec5SDimitry Andric     while (Lp) {
8930b57cec5SDimitry Andric       if (!isInvariantIn(Node, Lp) || !isInMainPath(LocB, Lp))
8940b57cec5SDimitry Andric         break;
8950b57cec5SDimitry Andric       BasicBlock *NewLoc = preheader(DT, Lp);
8960b57cec5SDimitry Andric       if (!NewLoc || !DT->dominates(TopB, NewLoc))
8970b57cec5SDimitry Andric         break;
8980b57cec5SDimitry Andric       Lp = Lp->getParentLoop();
8990b57cec5SDimitry Andric       LocB = NewLoc;
9000b57cec5SDimitry Andric     }
9010b57cec5SDimitry Andric   }
9020b57cec5SDimitry Andric   Loc[Node] = LocB;
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric   // Recursively compute the locations of all children nodes.
9050b57cec5SDimitry Andric   NodeChildrenMap::iterator CF = NCM.find(Node);
9060b57cec5SDimitry Andric   if (CF != NCM.end()) {
9070b57cec5SDimitry Andric     NodeVect &Cs = CF->second;
90804eeddc0SDimitry Andric     for (GepNode *C : Cs)
90904eeddc0SDimitry Andric       adjustForInvariance(C, NCM, Loc);
9100b57cec5SDimitry Andric   }
9110b57cec5SDimitry Andric   return LocB;
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric namespace {
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric   struct LocationAsBlock {
LocationAsBlock__anon2a64d1560611::LocationAsBlock9170b57cec5SDimitry Andric     LocationAsBlock(const NodeToValueMap &L) : Map(L) {}
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric     const NodeToValueMap &Map;
9200b57cec5SDimitry Andric   };
9210b57cec5SDimitry Andric 
9220b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS,
9230b57cec5SDimitry Andric                            const LocationAsBlock &Loc) LLVM_ATTRIBUTE_UNUSED ;
operator <<(raw_ostream & OS,const LocationAsBlock & Loc)9240b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const LocationAsBlock &Loc) {
92504eeddc0SDimitry Andric     for (const auto &I : Loc.Map) {
92604eeddc0SDimitry Andric       OS << I.first << " -> ";
92704eeddc0SDimitry Andric       if (BasicBlock *B = cast_or_null<BasicBlock>(I.second))
9280b57cec5SDimitry Andric         OS << B->getName() << '(' << B << ')';
929fe6060f1SDimitry Andric       else
930fe6060f1SDimitry Andric         OS << "<null-block>";
9310b57cec5SDimitry Andric       OS << '\n';
9320b57cec5SDimitry Andric     }
9330b57cec5SDimitry Andric     return OS;
9340b57cec5SDimitry Andric   }
9350b57cec5SDimitry Andric 
is_constant(GepNode * N)9360b57cec5SDimitry Andric   inline bool is_constant(GepNode *N) {
9370b57cec5SDimitry Andric     return isa<ConstantInt>(N->Idx);
9380b57cec5SDimitry Andric   }
9390b57cec5SDimitry Andric 
9400b57cec5SDimitry Andric } // end anonymous namespace
9410b57cec5SDimitry Andric 
separateChainForNode(GepNode * Node,Use * U,NodeToValueMap & Loc)9420b57cec5SDimitry Andric void HexagonCommonGEP::separateChainForNode(GepNode *Node, Use *U,
9430b57cec5SDimitry Andric       NodeToValueMap &Loc) {
9440b57cec5SDimitry Andric   User *R = U->getUser();
9450b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Separating chain for node (" << Node << ") user: " << *R
9460b57cec5SDimitry Andric                     << '\n');
9470b57cec5SDimitry Andric   BasicBlock *PB = cast<Instruction>(R)->getParent();
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric   GepNode *N = Node;
9500b57cec5SDimitry Andric   GepNode *C = nullptr, *NewNode = nullptr;
9510b57cec5SDimitry Andric   while (is_constant(N) && !(N->Flags & GepNode::Root)) {
9520b57cec5SDimitry Andric     // XXX if (single-use) dont-replicate;
9530b57cec5SDimitry Andric     GepNode *NewN = new (*Mem) GepNode(N);
9540b57cec5SDimitry Andric     Nodes.push_back(NewN);
9550b57cec5SDimitry Andric     Loc[NewN] = PB;
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric     if (N == Node)
9580b57cec5SDimitry Andric       NewNode = NewN;
9590b57cec5SDimitry Andric     NewN->Flags &= ~GepNode::Used;
9600b57cec5SDimitry Andric     if (C)
9610b57cec5SDimitry Andric       C->Parent = NewN;
9620b57cec5SDimitry Andric     C = NewN;
9630b57cec5SDimitry Andric     N = N->Parent;
9640b57cec5SDimitry Andric   }
9650b57cec5SDimitry Andric   if (!NewNode)
9660b57cec5SDimitry Andric     return;
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric   // Move over all uses that share the same user as U from Node to NewNode.
9690b57cec5SDimitry Andric   NodeToUsesMap::iterator UF = Uses.find(Node);
9700b57cec5SDimitry Andric   assert(UF != Uses.end());
9710b57cec5SDimitry Andric   UseSet &Us = UF->second;
9720b57cec5SDimitry Andric   UseSet NewUs;
9730b57cec5SDimitry Andric   for (Use *U : Us) {
9740b57cec5SDimitry Andric     if (U->getUser() == R)
9750b57cec5SDimitry Andric       NewUs.insert(U);
9760b57cec5SDimitry Andric   }
9770b57cec5SDimitry Andric   for (Use *U : NewUs)
9780b57cec5SDimitry Andric     Us.remove(U); // erase takes an iterator.
9790b57cec5SDimitry Andric 
9800b57cec5SDimitry Andric   if (Us.empty()) {
9810b57cec5SDimitry Andric     Node->Flags &= ~GepNode::Used;
9820b57cec5SDimitry Andric     Uses.erase(UF);
9830b57cec5SDimitry Andric   }
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric   // Should at least have U in NewUs.
9860b57cec5SDimitry Andric   NewNode->Flags |= GepNode::Used;
9870b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "new node: " << NewNode << "  " << *NewNode << '\n');
9880b57cec5SDimitry Andric   assert(!NewUs.empty());
9890b57cec5SDimitry Andric   Uses[NewNode] = NewUs;
9900b57cec5SDimitry Andric }
9910b57cec5SDimitry Andric 
separateConstantChains(GepNode * Node,NodeChildrenMap & NCM,NodeToValueMap & Loc)9920b57cec5SDimitry Andric void HexagonCommonGEP::separateConstantChains(GepNode *Node,
9930b57cec5SDimitry Andric       NodeChildrenMap &NCM, NodeToValueMap &Loc) {
9940b57cec5SDimitry Andric   // First approximation: extract all chains.
9950b57cec5SDimitry Andric   NodeSet Ns;
9960b57cec5SDimitry Andric   nodes_for_root(Node, NCM, Ns);
9970b57cec5SDimitry Andric 
9980b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Separating constant chains for node: " << Node << '\n');
9990b57cec5SDimitry Andric   // Collect all used nodes together with the uses from loads and stores,
10000b57cec5SDimitry Andric   // where the GEP node could be folded into the load/store instruction.
10010b57cec5SDimitry Andric   NodeToUsesMap FNs; // Foldable nodes.
100204eeddc0SDimitry Andric   for (GepNode *N : Ns) {
10030b57cec5SDimitry Andric     if (!(N->Flags & GepNode::Used))
10040b57cec5SDimitry Andric       continue;
10050b57cec5SDimitry Andric     NodeToUsesMap::iterator UF = Uses.find(N);
10060b57cec5SDimitry Andric     assert(UF != Uses.end());
10070b57cec5SDimitry Andric     UseSet &Us = UF->second;
10080b57cec5SDimitry Andric     // Loads/stores that use the node N.
10090b57cec5SDimitry Andric     UseSet LSs;
101004eeddc0SDimitry Andric     for (Use *U : Us) {
10110b57cec5SDimitry Andric       User *R = U->getUser();
10120b57cec5SDimitry Andric       // We're interested in uses that provide the address. It can happen
10130b57cec5SDimitry Andric       // that the value may also be provided via GEP, but we won't handle
10140b57cec5SDimitry Andric       // those cases here for now.
10150b57cec5SDimitry Andric       if (LoadInst *Ld = dyn_cast<LoadInst>(R)) {
10160b57cec5SDimitry Andric         unsigned PtrX = LoadInst::getPointerOperandIndex();
10170b57cec5SDimitry Andric         if (&Ld->getOperandUse(PtrX) == U)
10180b57cec5SDimitry Andric           LSs.insert(U);
10190b57cec5SDimitry Andric       } else if (StoreInst *St = dyn_cast<StoreInst>(R)) {
10200b57cec5SDimitry Andric         unsigned PtrX = StoreInst::getPointerOperandIndex();
10210b57cec5SDimitry Andric         if (&St->getOperandUse(PtrX) == U)
10220b57cec5SDimitry Andric           LSs.insert(U);
10230b57cec5SDimitry Andric       }
10240b57cec5SDimitry Andric     }
10250b57cec5SDimitry Andric     // Even if the total use count is 1, separating the chain may still be
10260b57cec5SDimitry Andric     // beneficial, since the constant chain may be longer than the GEP alone
10270b57cec5SDimitry Andric     // would be (e.g. if the parent node has a constant index and also has
10280b57cec5SDimitry Andric     // other children).
10290b57cec5SDimitry Andric     if (!LSs.empty())
10300b57cec5SDimitry Andric       FNs.insert(std::make_pair(N, LSs));
10310b57cec5SDimitry Andric   }
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Nodes with foldable users:\n" << FNs);
10340b57cec5SDimitry Andric 
103504eeddc0SDimitry Andric   for (auto &FN : FNs) {
103604eeddc0SDimitry Andric     GepNode *N = FN.first;
103704eeddc0SDimitry Andric     UseSet &Us = FN.second;
103804eeddc0SDimitry Andric     for (Use *U : Us)
103904eeddc0SDimitry Andric       separateChainForNode(N, U, Loc);
10400b57cec5SDimitry Andric   }
10410b57cec5SDimitry Andric }
10420b57cec5SDimitry Andric 
computeNodePlacement(NodeToValueMap & Loc)10430b57cec5SDimitry Andric void HexagonCommonGEP::computeNodePlacement(NodeToValueMap &Loc) {
10440b57cec5SDimitry Andric   // Compute the inverse of the Node.Parent links. Also, collect the set
10450b57cec5SDimitry Andric   // of root nodes.
10460b57cec5SDimitry Andric   NodeChildrenMap NCM;
10470b57cec5SDimitry Andric   NodeVect Roots;
10480b57cec5SDimitry Andric   invert_find_roots(Nodes, NCM, Roots);
10490b57cec5SDimitry Andric 
10500b57cec5SDimitry Andric   // Compute the initial placement determined by the users' locations, and
10510b57cec5SDimitry Andric   // the locations of the child nodes.
105204eeddc0SDimitry Andric   for (GepNode *Root : Roots)
105304eeddc0SDimitry Andric     recalculatePlacementRec(Root, NCM, Loc);
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Initial node placement:\n" << LocationAsBlock(Loc));
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric   if (OptEnableInv) {
105804eeddc0SDimitry Andric     for (GepNode *Root : Roots)
105904eeddc0SDimitry Andric       adjustForInvariance(Root, NCM, Loc);
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Node placement after adjustment for invariance:\n"
10620b57cec5SDimitry Andric                       << LocationAsBlock(Loc));
10630b57cec5SDimitry Andric   }
10640b57cec5SDimitry Andric   if (OptEnableConst) {
106504eeddc0SDimitry Andric     for (GepNode *Root : Roots)
106604eeddc0SDimitry Andric       separateConstantChains(Root, NCM, Loc);
10670b57cec5SDimitry Andric   }
10680b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Node use information:\n" << Uses);
10690b57cec5SDimitry Andric 
10700b57cec5SDimitry Andric   // At the moment, there is no further refinement of the initial placement.
10710b57cec5SDimitry Andric   // Such a refinement could include splitting the nodes if they are placed
10720b57cec5SDimitry Andric   // too far from some of its users.
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Final node placement:\n" << LocationAsBlock(Loc));
10750b57cec5SDimitry Andric }
10760b57cec5SDimitry Andric 
fabricateGEP(NodeVect & NA,BasicBlock::iterator At,BasicBlock * LocB)10770b57cec5SDimitry Andric Value *HexagonCommonGEP::fabricateGEP(NodeVect &NA, BasicBlock::iterator At,
10780b57cec5SDimitry Andric       BasicBlock *LocB) {
10790b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Fabricating GEP in " << LocB->getName()
10800b57cec5SDimitry Andric                     << " for nodes:\n"
10810b57cec5SDimitry Andric                     << NA);
10820b57cec5SDimitry Andric   unsigned Num = NA.size();
10830b57cec5SDimitry Andric   GepNode *RN = NA[0];
10840b57cec5SDimitry Andric   assert((RN->Flags & GepNode::Root) && "Creating GEP for non-root");
10850b57cec5SDimitry Andric 
10860b57cec5SDimitry Andric   GetElementPtrInst *NewInst = nullptr;
10870b57cec5SDimitry Andric   Value *Input = RN->BaseVal;
1088fe6060f1SDimitry Andric   Type *InpTy = RN->PTy;
1089fe6060f1SDimitry Andric 
1090fe6060f1SDimitry Andric   unsigned Idx = 0;
10910b57cec5SDimitry Andric   do {
1092fe6060f1SDimitry Andric     SmallVector<Value*, 4> IdxList;
10930b57cec5SDimitry Andric     // If the type of the input of the first node is not a pointer,
10940b57cec5SDimitry Andric     // we need to add an artificial i32 0 to the indices (because the
10950b57cec5SDimitry Andric     // actual input in the IR will be a pointer).
1096fe6060f1SDimitry Andric     if (!(NA[Idx]->Flags & GepNode::Pointer)) {
10970b57cec5SDimitry Andric       Type *Int32Ty = Type::getInt32Ty(*Ctx);
1098fe6060f1SDimitry Andric       IdxList.push_back(ConstantInt::get(Int32Ty, 0));
10990b57cec5SDimitry Andric     }
11000b57cec5SDimitry Andric 
11010b57cec5SDimitry Andric     // Keep adding indices from NA until we have to stop and generate
11020b57cec5SDimitry Andric     // an "intermediate" GEP.
1103fe6060f1SDimitry Andric     while (++Idx <= Num) {
1104fe6060f1SDimitry Andric       GepNode *N = NA[Idx-1];
1105fe6060f1SDimitry Andric       IdxList.push_back(N->Idx);
1106fe6060f1SDimitry Andric       if (Idx < Num) {
1107fe6060f1SDimitry Andric         // We have to stop if we reach a pointer.
1108fe6060f1SDimitry Andric         if (NA[Idx]->Flags & GepNode::Pointer)
11090b57cec5SDimitry Andric           break;
11100b57cec5SDimitry Andric       }
11110b57cec5SDimitry Andric     }
1112fe6060f1SDimitry Andric     NewInst = GetElementPtrInst::Create(InpTy, Input, IdxList, "cgep", &*At);
11130b57cec5SDimitry Andric     NewInst->setIsInBounds(RN->Flags & GepNode::InBounds);
11140b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "new GEP: " << *NewInst << '\n');
1115fe6060f1SDimitry Andric     if (Idx < Num) {
11160b57cec5SDimitry Andric       Input = NewInst;
1117fe6060f1SDimitry Andric       InpTy = NA[Idx]->PTy;
1118fe6060f1SDimitry Andric     }
1119fe6060f1SDimitry Andric   } while (Idx <= Num);
11200b57cec5SDimitry Andric 
11210b57cec5SDimitry Andric   return NewInst;
11220b57cec5SDimitry Andric }
11230b57cec5SDimitry Andric 
getAllUsersForNode(GepNode * Node,ValueVect & Values,NodeChildrenMap & NCM)11240b57cec5SDimitry Andric void HexagonCommonGEP::getAllUsersForNode(GepNode *Node, ValueVect &Values,
11250b57cec5SDimitry Andric       NodeChildrenMap &NCM) {
11260b57cec5SDimitry Andric   NodeVect Work;
11270b57cec5SDimitry Andric   Work.push_back(Node);
11280b57cec5SDimitry Andric 
11290b57cec5SDimitry Andric   while (!Work.empty()) {
11300b57cec5SDimitry Andric     NodeVect::iterator First = Work.begin();
11310b57cec5SDimitry Andric     GepNode *N = *First;
11320b57cec5SDimitry Andric     Work.erase(First);
11330b57cec5SDimitry Andric     if (N->Flags & GepNode::Used) {
11340b57cec5SDimitry Andric       NodeToUsesMap::iterator UF = Uses.find(N);
11350b57cec5SDimitry Andric       assert(UF != Uses.end() && "No use information for used node");
11360b57cec5SDimitry Andric       UseSet &Us = UF->second;
113704eeddc0SDimitry Andric       for (const auto &U : Us)
113804eeddc0SDimitry Andric         Values.push_back(U->getUser());
11390b57cec5SDimitry Andric     }
11400b57cec5SDimitry Andric     NodeChildrenMap::iterator CF = NCM.find(N);
11410b57cec5SDimitry Andric     if (CF != NCM.end()) {
11420b57cec5SDimitry Andric       NodeVect &Cs = CF->second;
1143e8d8bef9SDimitry Andric       llvm::append_range(Work, Cs);
11440b57cec5SDimitry Andric     }
11450b57cec5SDimitry Andric   }
11460b57cec5SDimitry Andric }
11470b57cec5SDimitry Andric 
materialize(NodeToValueMap & Loc)11480b57cec5SDimitry Andric void HexagonCommonGEP::materialize(NodeToValueMap &Loc) {
11490b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Nodes before materialization:\n" << Nodes << '\n');
11500b57cec5SDimitry Andric   NodeChildrenMap NCM;
11510b57cec5SDimitry Andric   NodeVect Roots;
11520b57cec5SDimitry Andric   // Compute the inversion again, since computing placement could alter
11530b57cec5SDimitry Andric   // "parent" relation between nodes.
11540b57cec5SDimitry Andric   invert_find_roots(Nodes, NCM, Roots);
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric   while (!Roots.empty()) {
11570b57cec5SDimitry Andric     NodeVect::iterator First = Roots.begin();
11580b57cec5SDimitry Andric     GepNode *Root = *First, *Last = *First;
11590b57cec5SDimitry Andric     Roots.erase(First);
11600b57cec5SDimitry Andric 
11610b57cec5SDimitry Andric     NodeVect NA;  // Nodes to assemble.
11620b57cec5SDimitry Andric     // Append to NA all child nodes up to (and including) the first child
11630b57cec5SDimitry Andric     // that:
11640b57cec5SDimitry Andric     // (1) has more than 1 child, or
11650b57cec5SDimitry Andric     // (2) is used, or
11660b57cec5SDimitry Andric     // (3) has a child located in a different block.
11670b57cec5SDimitry Andric     bool LastUsed = false;
11680b57cec5SDimitry Andric     unsigned LastCN = 0;
11690b57cec5SDimitry Andric     // The location may be null if the computation failed (it can legitimately
11700b57cec5SDimitry Andric     // happen for nodes created from dead GEPs).
11710b57cec5SDimitry Andric     Value *LocV = Loc[Last];
11720b57cec5SDimitry Andric     if (!LocV)
11730b57cec5SDimitry Andric       continue;
11740b57cec5SDimitry Andric     BasicBlock *LastB = cast<BasicBlock>(LocV);
11750b57cec5SDimitry Andric     do {
11760b57cec5SDimitry Andric       NA.push_back(Last);
11770b57cec5SDimitry Andric       LastUsed = (Last->Flags & GepNode::Used);
11780b57cec5SDimitry Andric       if (LastUsed)
11790b57cec5SDimitry Andric         break;
11800b57cec5SDimitry Andric       NodeChildrenMap::iterator CF = NCM.find(Last);
11810b57cec5SDimitry Andric       LastCN = (CF != NCM.end()) ? CF->second.size() : 0;
11820b57cec5SDimitry Andric       if (LastCN != 1)
11830b57cec5SDimitry Andric         break;
11840b57cec5SDimitry Andric       GepNode *Child = CF->second.front();
11850b57cec5SDimitry Andric       BasicBlock *ChildB = cast_or_null<BasicBlock>(Loc[Child]);
11860b57cec5SDimitry Andric       if (ChildB != nullptr && LastB != ChildB)
11870b57cec5SDimitry Andric         break;
11880b57cec5SDimitry Andric       Last = Child;
11890b57cec5SDimitry Andric     } while (true);
11900b57cec5SDimitry Andric 
11910b57cec5SDimitry Andric     BasicBlock::iterator InsertAt = LastB->getTerminator()->getIterator();
11920b57cec5SDimitry Andric     if (LastUsed || LastCN > 0) {
11930b57cec5SDimitry Andric       ValueVect Urs;
11940b57cec5SDimitry Andric       getAllUsersForNode(Root, Urs, NCM);
11950b57cec5SDimitry Andric       BasicBlock::iterator FirstUse = first_use_of_in_block(Urs, LastB);
11960b57cec5SDimitry Andric       if (FirstUse != LastB->end())
11970b57cec5SDimitry Andric         InsertAt = FirstUse;
11980b57cec5SDimitry Andric     }
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric     // Generate a new instruction for NA.
12010b57cec5SDimitry Andric     Value *NewInst = fabricateGEP(NA, InsertAt, LastB);
12020b57cec5SDimitry Andric 
12030b57cec5SDimitry Andric     // Convert all the children of Last node into roots, and append them
12040b57cec5SDimitry Andric     // to the Roots list.
12050b57cec5SDimitry Andric     if (LastCN > 0) {
12060b57cec5SDimitry Andric       NodeVect &Cs = NCM[Last];
120704eeddc0SDimitry Andric       for (GepNode *CN : Cs) {
12080b57cec5SDimitry Andric         CN->Flags &= ~GepNode::Internal;
12090b57cec5SDimitry Andric         CN->Flags |= GepNode::Root;
12100b57cec5SDimitry Andric         CN->BaseVal = NewInst;
12110b57cec5SDimitry Andric         Roots.push_back(CN);
12120b57cec5SDimitry Andric       }
12130b57cec5SDimitry Andric     }
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric     // Lastly, if the Last node was used, replace all uses with the new GEP.
12160b57cec5SDimitry Andric     // The uses reference the original GEP values.
12170b57cec5SDimitry Andric     if (LastUsed) {
12180b57cec5SDimitry Andric       NodeToUsesMap::iterator UF = Uses.find(Last);
12190b57cec5SDimitry Andric       assert(UF != Uses.end() && "No use information found");
12200b57cec5SDimitry Andric       UseSet &Us = UF->second;
122104eeddc0SDimitry Andric       for (Use *U : Us)
12220b57cec5SDimitry Andric         U->set(NewInst);
12230b57cec5SDimitry Andric     }
12240b57cec5SDimitry Andric   }
12250b57cec5SDimitry Andric }
12260b57cec5SDimitry Andric 
removeDeadCode()12270b57cec5SDimitry Andric void HexagonCommonGEP::removeDeadCode() {
12280b57cec5SDimitry Andric   ValueVect BO;
12290b57cec5SDimitry Andric   BO.push_back(&Fn->front());
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric   for (unsigned i = 0; i < BO.size(); ++i) {
12320b57cec5SDimitry Andric     BasicBlock *B = cast<BasicBlock>(BO[i]);
1233bdd1243dSDimitry Andric     for (auto *DTN : children<DomTreeNode *>(DT->getNode(B)))
12340b57cec5SDimitry Andric       BO.push_back(DTN->getBlock());
12350b57cec5SDimitry Andric   }
12360b57cec5SDimitry Andric 
12370eae32dcSDimitry Andric   for (Value *V : llvm::reverse(BO)) {
12380eae32dcSDimitry Andric     BasicBlock *B = cast<BasicBlock>(V);
12390b57cec5SDimitry Andric     ValueVect Ins;
12400eae32dcSDimitry Andric     for (Instruction &I : llvm::reverse(*B))
12410eae32dcSDimitry Andric       Ins.push_back(&I);
124204eeddc0SDimitry Andric     for (Value *I : Ins) {
124304eeddc0SDimitry Andric       Instruction *In = cast<Instruction>(I);
12440b57cec5SDimitry Andric       if (isInstructionTriviallyDead(In))
12450b57cec5SDimitry Andric         In->eraseFromParent();
12460b57cec5SDimitry Andric     }
12470b57cec5SDimitry Andric   }
12480b57cec5SDimitry Andric }
12490b57cec5SDimitry Andric 
runOnFunction(Function & F)12500b57cec5SDimitry Andric bool HexagonCommonGEP::runOnFunction(Function &F) {
12510b57cec5SDimitry Andric   if (skipFunction(F))
12520b57cec5SDimitry Andric     return false;
12530b57cec5SDimitry Andric 
12540b57cec5SDimitry Andric   // For now bail out on C++ exception handling.
12554824e7fdSDimitry Andric   for (const BasicBlock &BB : F)
12564824e7fdSDimitry Andric     for (const Instruction &I : BB)
12570b57cec5SDimitry Andric       if (isa<InvokeInst>(I) || isa<LandingPadInst>(I))
12580b57cec5SDimitry Andric         return false;
12590b57cec5SDimitry Andric 
12600b57cec5SDimitry Andric   Fn = &F;
12610b57cec5SDimitry Andric   DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
12620b57cec5SDimitry Andric   PDT = &getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
12630b57cec5SDimitry Andric   LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
12640b57cec5SDimitry Andric   Ctx = &F.getContext();
12650b57cec5SDimitry Andric 
12660b57cec5SDimitry Andric   Nodes.clear();
12670b57cec5SDimitry Andric   Uses.clear();
12680b57cec5SDimitry Andric   NodeOrder.clear();
12690b57cec5SDimitry Andric 
12700b57cec5SDimitry Andric   SpecificBumpPtrAllocator<GepNode> Allocator;
12710b57cec5SDimitry Andric   Mem = &Allocator;
12720b57cec5SDimitry Andric 
12730b57cec5SDimitry Andric   collect();
12740b57cec5SDimitry Andric   common();
12750b57cec5SDimitry Andric 
12760b57cec5SDimitry Andric   NodeToValueMap Loc;
12770b57cec5SDimitry Andric   computeNodePlacement(Loc);
12780b57cec5SDimitry Andric   materialize(Loc);
12790b57cec5SDimitry Andric   removeDeadCode();
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS
12820b57cec5SDimitry Andric   // Run this only when expensive checks are enabled.
12835ffd83dbSDimitry Andric   if (verifyFunction(F, &dbgs()))
12845ffd83dbSDimitry Andric     report_fatal_error("Broken function");
12850b57cec5SDimitry Andric #endif
12860b57cec5SDimitry Andric   return true;
12870b57cec5SDimitry Andric }
12880b57cec5SDimitry Andric 
12890b57cec5SDimitry Andric namespace llvm {
12900b57cec5SDimitry Andric 
createHexagonCommonGEP()12910b57cec5SDimitry Andric   FunctionPass *createHexagonCommonGEP() {
12920b57cec5SDimitry Andric     return new HexagonCommonGEP();
12930b57cec5SDimitry Andric   }
12940b57cec5SDimitry Andric 
12950b57cec5SDimitry Andric } // end namespace llvm
1296