aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/ConstantMerge.cpp
blob: 28c6519478f5a0f23726cbb8f45641c5dba0d03d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//===- ConstantMerge.cpp - Merge duplicate global constants -----------------=//
//
// This file defines the interface to a pass that merges duplicate global
// constants together into a single constant that is shared.  This is useful
// because some passes (ie TraceValues) insert a lot of string constants into
// the program, regardless of whether or not an existing string is available.
//
// Algorithm: ConstantMerge is designed to build up a map of available constants
// and eliminate duplicates when it is initialized.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "Support/StatisticReporter.h"

namespace {
  struct ConstantMerge : public Pass {
    // run - For this pass, process all of the globals in the module,
    // eliminating duplicate constants.
    //
    bool run(Module &M);

  private:
    void replaceUsesOfWith(GlobalVariable *Old, GlobalVariable *New);
    void replaceConstantWith(Constant *Old, Constant *New);
  };

  Statistic<> NumMerged("constmerge\t\t- Number of global constants merged");
  RegisterOpt<ConstantMerge> X("constmerge","Merge Duplicate Global Constants");
}

Pass *createConstantMergePass() { return new ConstantMerge(); }


bool ConstantMerge::run(Module &M) {
  std::map<Constant*, GlobalVariable*> CMap;
  bool MadeChanges = false;
  
  for (Module::giterator GV = M.gbegin(), E = M.gend(); GV != E; ++GV)
    if (GV->isConstant()) {  // Only process constants
      assert(GV->hasInitializer() && "Globals constants must have inits!");
      Constant *Init = GV->getInitializer();

      // Check to see if the initializer is already known...
      std::map<Constant*, GlobalVariable*>::iterator I = CMap.find(Init);

      if (I == CMap.end()) {    // Nope, add it to the map
        CMap.insert(I, std::make_pair(Init, GV));
      } else {                  // Yup, this is a duplicate!
        // Make all uses of the duplicate constant use the cannonical version...
        replaceUsesOfWith(GV, I->second);

        // Delete the global value from the module... and back up iterator to
        // not skip the next global...
        GV = --M.getGlobalList().erase(GV);

        ++NumMerged;
        MadeChanges = true;
      }
    }

  return MadeChanges;
}

/// replaceUsesOfWith - Replace all uses of Old with New.  For instructions,
/// this is a really simple matter of replacing the reference to Old with a
/// reference to New.  For constants references, however, we must carefully
/// build replacement constants to substitute in.
///
void ConstantMerge::replaceUsesOfWith(GlobalVariable *Old, GlobalVariable *New){
  while (!Old->use_empty()) {
    User *U = Old->use_back();
    if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(U))
      replaceConstantWith(CPR, ConstantPointerRef::get(New));
    else
      U->replaceUsesOfWith(Old, New);
  }
}

/// replaceWith - Ok, so we have a constant 'Old' and we want to replace it with
/// 'New'.  To do this, we have to recursively go through the uses of Old,
/// replacing them with new things.  The problem is that if a constant uses Old,
/// then we need to replace the uses of the constant with uses of the equivalent
/// constant that uses New instead.
///
void ConstantMerge::replaceConstantWith(Constant *Old, Constant *New) {
  while (!Old->use_empty()) {
    User *U = Old->use_back();

    if (Constant *C = dyn_cast<Constant>(U)) {
      Constant *Replacement = 0;
      
      // Depending on the type of constant, build a suitable replacement...
      if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
        if (CE->getOpcode() == Instruction::GetElementPtr) {
          std::vector<Constant*> Indices;
          Constant *Pointer = cast<Constant>(CE->getOperand(0));
          Indices.reserve(CE->getNumOperands()-1);
          if (Pointer == Old) Pointer = New;

          for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i) {
            Constant *Val = cast<Constant>(CE->getOperand(i));
            if (Val == Old) Val = New;
            Indices.push_back(Val);
          }
          Replacement = ConstantExpr::getGetElementPtr(Pointer, Indices);
        } else if (CE->getOpcode() == Instruction::Cast) {
          assert(CE->getOperand(0) == Old && "Cast only has one use!");
          Replacement = ConstantExpr::getCast(New, CE->getType());
        } else if (CE->getNumOperands() == 2) {
          Constant *C1 = cast<Constant>(CE->getOperand(0));
          Constant *C2 = cast<Constant>(CE->getOperand(1));
          if (C1 == Old) C1 = New;
          if (C2 == Old) C2 = New;
          Replacement = ConstantExpr::get(CE->getOpcode(), C1, C2);
        } else {
          assert(0 && "Unknown ConstantExpr type!");
        }


      } else if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) {
        std::vector<Constant*> Values;
        Values.reserve(CA->getValues().size());
        for (unsigned i = 0, e = CA->getValues().size(); i != e; ++i) {
          Constant *Val = cast<Constant>(CA->getValues()[i]);
          if (Val == Old) Val = New;
          Values.push_back(Val);
        }

        Replacement = ConstantArray::get(CA->getType(), Values);
      } else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) {
        std::vector<Constant*> Values;
        Values.reserve(CS->getValues().size());

        for (unsigned i = 0, e = CS->getValues().size(); i != e; ++i) {
          Constant *Val = cast<Constant>(CS->getValues()[i]);
          if (Val == Old) Val = New;
          Values.push_back(Val);
        }

        Replacement = ConstantStruct::get(CS->getType(), Values);
      } else {
        assert(0 && "Unexpected/unknown constant type!");
      }
      
      // Now that we have a suitable replacement, recursively eliminate C.
      replaceConstantWith(C, Replacement);

    } else {
      // If it is not a constant, we can simply replace uses of Old with New.
      U->replaceUsesOfWith(Old, New);
    }

  }

  // No-one refers to this old dead constant now, destroy it!
  Old->destroyConstant();
}