aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/Utils/LowerAllocations.cpp
blob: d08235cd9d79f4918a78e38042287c8271af6e21 (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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LowerAllocations transformation is a target-dependent tranformation
// because it depends on the size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

namespace {
  Statistic<> NumLowered("lowerallocs", "Number of allocations lowered");

  /// LowerAllocations - Turn malloc and free instructions into %malloc and
  /// %free calls.
  ///
  class VISIBILITY_HIDDEN LowerAllocations : public BasicBlockPass {
    Function *MallocFunc;   // Functions in the module we are processing
    Function *FreeFunc;     // Initialized by doInitialization
    bool LowerMallocArgToInteger;
  public:
    LowerAllocations(bool LowerToInt = false)
      : MallocFunc(0), FreeFunc(0), LowerMallocArgToInteger(LowerToInt) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<TargetData>();
      AU.setPreservesCFG();

      // This is a cluster of orthogonal Transforms:	
      AU.addPreserved<UnifyFunctionExitNodes>();
      AU.addPreservedID(PromoteMemoryToRegisterID);
      AU.addPreservedID(LowerSelectID);
      AU.addPreservedID(LowerSwitchID);
      AU.addPreservedID(LowerInvokePassID);
    }

    /// 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);

    virtual bool doInitialization(Function &F) {
      return BasicBlockPass::doInitialization(F);
    }

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

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

// Publically exposed interface to pass...
const PassInfo *llvm::LowerAllocationsID = X.getPassInfo();
// createLowerAllocationsPass - Interface to this file...
FunctionPass *llvm::createLowerAllocationsPass(bool LowerMallocArgToInteger) {
  return new LowerAllocations(LowerMallocArgToInteger);
}


// 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 Type *SBPTy = PointerType::get(Type::SByteTy);
  MallocFunc = M.getNamedFunction("malloc");
  FreeFunc   = M.getNamedFunction("free");

  if (MallocFunc == 0) {
    // Prototype malloc as "void* malloc(...)", because we don't know in
    // doInitialization whether size_t is int or long.
    FunctionType *FT = FunctionType::get(SBPTy,std::vector<const Type*>(),true);
    MallocFunc = M.getOrInsertFunction("malloc", FT);
  }
  if (FreeFunc == 0)
    FreeFunc = M.getOrInsertFunction("free"  , Type::VoidTy, SBPTy, (Type *)0);

  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();

  const TargetData &TD = getAnalysis<TargetData>();
  const Type *IntPtrTy = TD.getIntPtrType();

  // 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)) {
      const Type *AllocTy = MI->getType()->getElementType();

      // malloc(type) becomes sbyte *malloc(size)
      Value *MallocArg;
      if (LowerMallocArgToInteger)
        MallocArg = ConstantInt::get(Type::ULongTy, TD.getTypeSize(AllocTy));
      else
        MallocArg = ConstantExpr::getSizeOf(AllocTy);
      MallocArg = ConstantExpr::getCast(cast<Constant>(MallocArg), IntPtrTy);

      if (MI->isArrayAllocation()) {
        if (isa<ConstantInt>(MallocArg) &&
            cast<ConstantInt>(MallocArg)->getZExtValue() == 1) {
          MallocArg = MI->getOperand(0);         // Operand * 1 = Operand
        } else if (Constant *CO = dyn_cast<Constant>(MI->getOperand(0))) {
          CO = ConstantExpr::getCast(CO, IntPtrTy);
          MallocArg = ConstantExpr::getMul(CO, cast<Constant>(MallocArg));
        } else {
          Value *Scale = MI->getOperand(0);
          if (Scale->getType() != IntPtrTy)
            Scale = new CastInst(Scale, IntPtrTy, "", I);

          // Multiply it by the array size if necessary...
          MallocArg = BinaryOperator::create(Instruction::Mul, Scale,
                                             MallocArg, "", I);
        }
      }

      const FunctionType *MallocFTy = MallocFunc->getFunctionType();
      std::vector<Value*> MallocArgs;

      if (MallocFTy->getNumParams() > 0 || MallocFTy->isVarArg()) {
        if (MallocFTy->isVarArg()) {
          if (MallocArg->getType() != IntPtrTy)
            MallocArg = new CastInst(MallocArg, IntPtrTy, "", I);
        } else if (MallocFTy->getNumParams() > 0 &&
                   MallocFTy->getParamType(0) != Type::UIntTy)
          MallocArg = new CastInst(MallocArg, MallocFTy->getParamType(0), "",I);
        MallocArgs.push_back(MallocArg);
      }

      // If malloc is prototyped to take extra arguments, pass nulls.
      for (unsigned i = 1; i < MallocFTy->getNumParams(); ++i)
       MallocArgs.push_back(Constant::getNullValue(MallocFTy->getParamType(i)));

      // Create the call to Malloc...
      CallInst *MCall = new CallInst(MallocFunc, MallocArgs, "", I);
      MCall->setTailCall();

      // Create a cast instruction to convert to the right type...
      Value *MCast;
      if (MCall->getType() != Type::VoidTy)
        MCast = new CastInst(MCall, MI->getType(), "", I);
      else
        MCast = Constant::getNullValue(MI->getType());

      // Replace all uses of the old malloc inst with the cast inst
      MI->replaceAllUsesWith(MCast);
      I = --BBIL.erase(I);         // remove and delete the malloc instr...
      Changed = true;
      ++NumLowered;
    } else if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      const FunctionType *FreeFTy = FreeFunc->getFunctionType();
      std::vector<Value*> FreeArgs;

      if (FreeFTy->getNumParams() > 0 || FreeFTy->isVarArg()) {
        Value *MCast = FI->getOperand(0);
        if (FreeFTy->getNumParams() > 0 &&
            FreeFTy->getParamType(0) != MCast->getType())
          MCast = new CastInst(MCast, FreeFTy->getParamType(0), "", I);
        FreeArgs.push_back(MCast);
      }

      // If malloc is prototyped to take extra arguments, pass nulls.
      for (unsigned i = 1; i < FreeFTy->getNumParams(); ++i)
       FreeArgs.push_back(Constant::getNullValue(FreeFTy->getParamType(i)));

      // Insert a call to the free function...
      (new CallInst(FreeFunc, FreeArgs, "", I))->setTailCall();

      // Delete the old free instruction
      I = --BBIL.erase(I);
      Changed = true;
      ++NumLowered;
    }
  }

  return Changed;
}