summaryrefslogtreecommitdiffstats
path: root/lib/Transforms/IPO/RaiseAllocations.cpp
blob: 42e1a28af7a5369944634c9ea66d10df063a8634 (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
//===- RaiseAllocations.cpp - Convert %malloc & %free calls to insts ------===//
//
// This file defines the RaiseAllocations pass which convert malloc and free
// calls to malloc and free instructions.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/Pass.h"
#include "Support/StatisticReporter.h"

static Statistic<> NumRaised("raiseallocs\t- Number of allocations raised");

namespace {

// RaiseAllocations - Turn %malloc and %free calls into the appropriate
// instruction.
//
class RaiseAllocations : public BasicBlockPass {
  Function *MallocFunc;   // Functions in the module we are processing
  Function *FreeFunc;     // Initialized by doPassInitializationVirt
public:
  inline RaiseAllocations() : MallocFunc(0), FreeFunc(0) {}

  const char *getPassName() const { return "Raise Allocations"; }

  // doPassInitialization - For the raise allocations pass, this finds a
  // declaration for malloc and free if they exist.
  //
  bool doInitialization(Module &M);

  // runOnBasicBlock - This method does the actual work of converting
  // instructions over, assuming that the pass has already been initialized.
  //
  bool runOnBasicBlock(BasicBlock &BB);
};

}  // end anonymous namespace


// createRaiseAllocationsPass - The interface to this file...
Pass *createRaiseAllocationsPass() {
  return new RaiseAllocations();
}


bool RaiseAllocations::doInitialization(Module &M) {
  // If the module has a symbol table, they might be referring to the malloc
  // and free functions.  If this is the case, grab the method pointers that 
  // the module is using.
  //
  // Lookup %malloc and %free in the symbol table, for later use.  If they
  // don't exist, or are not external, we do not worry about converting calls
  // to that function into the appropriate instruction.
  //
  const FunctionType *MallocType =   // Get the type for malloc
    FunctionType::get(PointerType::get(Type::SByteTy),
                    std::vector<const Type*>(1, Type::UIntTy), false);

  const FunctionType *FreeType =     // Get the type for free
    FunctionType::get(Type::VoidTy,
                   std::vector<const Type*>(1, PointerType::get(Type::SByteTy)),
                      false);

  MallocFunc = M.getFunction("malloc", MallocType);
  FreeFunc   = M.getFunction("free"  , FreeType);

  // Check to see if the prototype is missing, giving us sbyte*(...) * malloc
  // This handles the common declaration of: 'char *malloc();'
  if (MallocFunc == 0) {
    MallocType = FunctionType::get(PointerType::get(Type::SByteTy),
                                   std::vector<const Type*>(), true);
    MallocFunc = M.getFunction("malloc", MallocType);
  }

  // Check to see if the prototype was forgotten, giving us void (...) * free
  // This handles the common forward declaration of: 'void free();'
  if (FreeFunc == 0) {
    FreeType = FunctionType::get(Type::VoidTy, std::vector<const Type*>(),true);
    FreeFunc = M.getFunction("free", FreeType);
  }


  // Don't mess with locally defined versions of these functions...
  if (MallocFunc && !MallocFunc->isExternal()) MallocFunc = 0;
  if (FreeFunc && !FreeFunc->isExternal())     FreeFunc = 0;
  return false;
}

// runOnBasicBlock - Process a basic block, fixing it up...
//
bool RaiseAllocations::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  BasicBlock::InstListType &BIL = BB.getInstList();

  for (BasicBlock::iterator BI = BB.begin(); BI != BB.end();) {
    Instruction *I = BI;

    if (CallInst *CI = dyn_cast<CallInst>(I)) {
      if (CI->getCalledValue() == MallocFunc) {      // Replace call to malloc?
        const Type *PtrSByte = PointerType::get(Type::SByteTy);
        Value *Source = CI->getOperand(1);
        
        // If no prototype was provided for malloc, we may need to cast the
        // source size.
        if (Source->getType() != Type::UIntTy) {
          CastInst *New = new CastInst(Source, Type::UIntTy, "MallocAmtCast");
          BI = ++BIL.insert(BI, New);
          Source = New;
        }

        MallocInst *MallocI = new MallocInst(PtrSByte, Source, CI->getName());
                                             
        CI->setName("");
        ReplaceInstWithInst(BIL, BI, MallocI);
        Changed = true;
        ++NumRaised;
        continue;  // Skip the ++BI
      } else if (CI->getCalledValue() == FreeFunc) { // Replace call to free?
        // If no prototype was provided for free, we may need to cast the
        // source pointer.  This should be really uncommon, but it's neccesary
        // just in case we are dealing with wierd code like this:
        //   free((long)ptr);
        //
        Value *Source = CI->getOperand(1);
        if (!isa<PointerType>(Source->getType())) {
          CastInst *New = new CastInst(Source, PointerType::get(Type::SByteTy),
                                       "FreePtrCast");
          BI = ++BIL.insert(BI, New);
          Source = New;
        }

        ReplaceInstWithInst(BIL, BI, new FreeInst(Source));
        Changed = true;
        continue;  // Skip the ++BI
        ++NumRaised;
      }
    }

    ++BI;
  }

  return Changed;
}