summaryrefslogtreecommitdiff
path: root/lib/Transforms/Utils/LowerAllocations.cpp
blob: 486061fdf738f1b3a2918ea5e5b6b27c2286958f (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
//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===//
//
// The LowerAllocations transformation is a target dependant tranformation
// because it depends on the size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetData.h"
#include "Support/StatisticReporter.h"

static Statistic<> NumLowered("lowerallocs\t- Number of allocations lowered");
using std::vector;

namespace {

// LowerAllocations - Turn malloc and free instructions into %malloc and %free
// calls.
//
class LowerAllocations : public BasicBlockPass {
  Function *MallocFunc;   // Functions in the module we are processing
  Function *FreeFunc;     // Initialized by doInitialization

  const TargetData &DataLayout;
public:
  LowerAllocations(const TargetData &TD) : DataLayout(TD) {
    MallocFunc = FreeFunc = 0;
  }

  // doPassInitialization - For the lower allocations pass, this ensures that a
  // module contains a declaration for a malloc and a free function.
  //
  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);
};
}

// createLowerAllocationsPass - Interface to this file...
Pass *createLowerAllocationsPass(const TargetData &TD) {
  return new LowerAllocations(TD);
}

static RegisterPass<LowerAllocations>
X("lowerallocs", "Lower allocations from instructions to calls (TD)",
  createLowerAllocationsPass);


// doInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
// This function is always successful.
//
bool LowerAllocations::doInitialization(Module &M) {
  const FunctionType *MallocType = 
    FunctionType::get(PointerType::get(Type::SByteTy),
                      vector<const Type*>(1, Type::UIntTy), false);
  const FunctionType *FreeType = 
    FunctionType::get(Type::VoidTy,
                      vector<const Type*>(1, PointerType::get(Type::SByteTy)),
                      false);

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

  return true;
}

// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  assert(MallocFunc && FreeFunc && "Pass not initialized!");

  BasicBlock::InstListType &BBIL = BB.getInstList();

  // Loop over all of the instructions, looking for malloc or free instructions
  for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
    if (MallocInst *MI = dyn_cast<MallocInst>(&*I)) {
      BBIL.remove(I);   // remove the malloc instr...

      const Type *AllocTy = MI->getType()->getElementType();
      
      // Get the number of bytes to be allocated for one element of the
      // requested type...
      unsigned Size = DataLayout.getTypeSize(AllocTy);
      
      // malloc(type) becomes sbyte *malloc(constint)
      Value *MallocArg = ConstantUInt::get(Type::UIntTy, Size);
      if (MI->getNumOperands() && Size == 1) {
        MallocArg = MI->getOperand(0);         // Operand * 1 = Operand
      } else if (MI->getNumOperands()) {
        // Multiply it by the array size if neccesary...
        MallocArg = BinaryOperator::create(Instruction::Mul,MI->getOperand(0),
                                           MallocArg);
        I = ++BBIL.insert(I, cast<Instruction>(MallocArg));
      }
      
      // Create the call to Malloc...
      CallInst *MCall = new CallInst(MallocFunc,
                                     vector<Value*>(1, MallocArg));
      I = BBIL.insert(I, MCall);
      
      // Create a cast instruction to convert to the right type...
      CastInst *MCast = new CastInst(MCall, MI->getType());
      I = BBIL.insert(++I, MCast);
      
      // Replace all uses of the old malloc inst with the cast inst
      MI->replaceAllUsesWith(MCast);
      delete MI;                          // Delete the malloc inst
      Changed = true;
      ++NumLowered;
    } else if (FreeInst *FI = dyn_cast<FreeInst>(&*I)) {
      BBIL.remove(I);
      
      // Cast the argument to free into a ubyte*...
      CastInst *MCast = new CastInst(FI->getOperand(0), 
                                     PointerType::get(Type::UByteTy));
      I = ++BBIL.insert(I, MCast);
      
      // Insert a call to the free function...
      CallInst *FCall = new CallInst(FreeFunc, vector<Value*>(1, MCast));
      I = BBIL.insert(I, FCall);
      
      // Delete the old free instruction
      delete FI;
      Changed = true;
      ++NumLowered;
    }
  }

  return Changed;
}