15b65a827899a4b53bdcf964c8ff7d02342f662a
[oota-llvm.git] / lib / Target / ARM / ARMGlobalMerge.cpp
1 //===-- ARMGlobalMerge.cpp - Internal globals merging  --------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //===----------------------------------------------------------------------===//
11
12 #define DEBUG_TYPE "arm-global-merge"
13 #include "ARM.h"
14 #include "llvm/CodeGen/Passes.h"
15 #include "llvm/Attributes.h"
16 #include "llvm/Constants.h"
17 #include "llvm/DerivedTypes.h"
18 #include "llvm/Function.h"
19 #include "llvm/GlobalVariable.h"
20 #include "llvm/Instructions.h"
21 #include "llvm/Intrinsics.h"
22 #include "llvm/Module.h"
23 #include "llvm/Pass.h"
24 #include "llvm/Target/TargetData.h"
25 #include "llvm/Target/TargetLowering.h"
26 using namespace llvm;
27
28 namespace {
29   class VISIBILITY_HIDDEN ARMGlobalMerge : public FunctionPass {
30     /// TLI - Keep a pointer of a TargetLowering to consult for determining
31     /// target type sizes.
32     const TargetLowering *TLI;
33     bool doMerge(std::vector<GlobalVariable*> &Globals, Module &M, bool) const;
34
35   public:
36     static char ID;             // Pass identification, replacement for typeid.
37     explicit ARMGlobalMerge(const TargetLowering *tli)
38       : FunctionPass(&ID), TLI(tli) {}
39
40     virtual bool doInitialization(Module &M);
41     virtual bool runOnFunction(Function& F);
42
43     const char *getPassName() const {
44       return "Merge internal globals";
45     }
46
47     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
48       AU.setPreservesCFG();
49       FunctionPass::getAnalysisUsage(AU);
50     }
51
52     struct GlobalCmp {
53       const TargetData *TD;
54
55       GlobalCmp(const TargetData *td):
56         TD(td) { };
57
58       bool operator() (const GlobalVariable* GV1,
59                        const GlobalVariable* GV2) {
60         const Type* Ty1 = cast<PointerType>(GV1->getType())->getElementType();
61         const Type* Ty2 = cast<PointerType>(GV2->getType())->getElementType();
62
63         return (TD->getTypeAllocSize(Ty1) <
64                 TD->getTypeAllocSize(Ty2));
65       }
66     };
67   };
68 } // end anonymous namespace
69
70 char ARMGlobalMerge::ID = 0;
71
72 #define MAX_OFFSET 4095
73
74 bool ARMGlobalMerge::doMerge(std::vector<GlobalVariable*> &Globals,
75                              Module &M, bool isConst) const {
76   const TargetData *TD = TLI->getTargetData();
77
78   // FIXME: Find better heuristics
79   std::stable_sort(Globals.begin(), Globals.end(), GlobalCmp(TD));
80
81   const Type *Int32Ty = Type::getInt32Ty(M.getContext());
82
83   for (size_t i = 0, e = Globals.size(); i != e; ) {
84     size_t j = 0;
85     uint64_t MergedSize = 0;
86     std::vector<const Type*> Tys;
87     std::vector<Constant*> Inits;
88     for (j = i; MergedSize < MAX_OFFSET && j != e; ++j) {
89       const Type* Ty = Globals[j]->getType()->getElementType();
90       Tys.push_back(Ty);
91       Inits.push_back(Globals[j]->getInitializer());
92       MergedSize += TD->getTypeAllocSize(Ty);
93     }
94
95     StructType* MergedTy = StructType::get(M.getContext(), Tys);
96     Constant* MergedInit = ConstantStruct::get(MergedTy, Inits);
97     GlobalVariable* MergedGV = new GlobalVariable(M, MergedTy, isConst,
98                                                   GlobalValue::InternalLinkage,
99                                                   MergedInit, "merged");
100     for (size_t k = i; k < j; ++k) {
101       SmallVector<Constant*, 2> Idx;
102       Idx.push_back(ConstantInt::get(Int32Ty, 0));
103       Idx.push_back(ConstantInt::get(Int32Ty, k-i));
104
105       Constant* GEP =
106         ConstantExpr::getInBoundsGetElementPtr(MergedGV,
107                                                &Idx[0], Idx.size());
108
109       Globals[k]->replaceAllUsesWith(GEP);
110       Globals[k]->eraseFromParent();
111     }
112     i = j;
113   }
114
115   return true;
116 }
117
118
119 bool ARMGlobalMerge::doInitialization(Module& M) {
120   std::vector<GlobalVariable*> Globals, ConstGlobals;
121   bool Changed = false;
122   const TargetData *TD = TLI->getTargetData();
123
124   // Grab all non-const globals.
125   for (Module::global_iterator I = M.global_begin(),
126          E = M.global_end(); I != E; ++I) {
127     // Ignore fancy-aligned globals for now.
128     if (I->hasLocalLinkage() && I->getAlignment() == 0 &&
129         TD->getTypeAllocSize(I->getType()) < MAX_OFFSET) {
130       if (I->isConstant())
131         ConstGlobals.push_back(I);
132       else
133         Globals.push_back(I);
134     }
135   }
136
137   Changed |= doMerge(Globals, M, false);
138   Changed |= doMerge(ConstGlobals, M, true);
139
140   return Changed;
141 }
142
143 bool ARMGlobalMerge::runOnFunction(Function& F) {
144   return false;
145 }
146
147 FunctionPass *llvm::createARMGlobalMergePass(const TargetLowering *tli) {
148   return new ARMGlobalMerge(tli);
149 }