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 830b57cec5SDimitry Andric void insert(const GepNode *N) { Map.insert(std::make_pair(N, ++LastNum)); } 840b57cec5SDimitry Andric void clear() { Map.clear(); } 850b57cec5SDimitry Andric 860b57cec5SDimitry 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 1010b57cec5SDimitry Andric HexagonCommonGEP() : FunctionPass(ID) { 1020b57cec5SDimitry Andric initializeHexagonCommonGEPPass(*PassRegistry::getPassRegistry()); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric bool runOnFunction(Function &F) override; 1060b57cec5SDimitry Andric StringRef getPassName() const override { return "Hexagon Common GEP"; } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry 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 2070b57cec5SDimitry Andric GepNode() : Parent(nullptr) {} 2080b57cec5SDimitry 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 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> 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; 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; 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 { 3080b57cec5SDimitry Andric in_set(const NodeSet &S) : NS(S) {} 3090b57cec5SDimitry Andric 3100b57cec5SDimitry 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 3200b57cec5SDimitry Andric inline void *operator new(size_t, SpecificBumpPtrAllocator<GepNode> &A) { 3210b57cec5SDimitry Andric return A.Allocate(); 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 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 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 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 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 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 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 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. 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 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 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 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) { 596*0fca6ea1SDimitry Andric GepNode *Min = *llvm::min_element(S, 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> 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> 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> 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 7410b57cec5SDimitry Andric static bool is_empty(const BasicBlock *B) { 7420b57cec5SDimitry Andric return B->empty() || (&*B->begin() == B->getTerminator()); 7430b57cec5SDimitry Andric } 7440b57cec5SDimitry Andric 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 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 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 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 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 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 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 { 9170b57cec5SDimitry Andric LocationAsBlock(const NodeToValueMap &L) : Map(L) {} 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric const NodeToValueMap ⤅ 9200b57cec5SDimitry Andric }; 9210b57cec5SDimitry Andric 9220b57cec5SDimitry Andric raw_ostream &operator<< (raw_ostream &OS, 9230b57cec5SDimitry Andric const LocationAsBlock &Loc) LLVM_ATTRIBUTE_UNUSED ; 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 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 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 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 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 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 } 1112*0fca6ea1SDimitry 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 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 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 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 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 12910b57cec5SDimitry Andric FunctionPass *createHexagonCommonGEP() { 12920b57cec5SDimitry Andric return new HexagonCommonGEP(); 12930b57cec5SDimitry Andric } 12940b57cec5SDimitry Andric 12950b57cec5SDimitry Andric } // end namespace llvm 1296