blob: ebc92f7585646cf1cb3a319a4e0c040f9ccf2bb6 [file] [log] [blame]
//===-- SimplifyAllocas.cpp - Alloca optimization ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===-----------------------------------------------------------------------===//
//
// There shouldn't be any opportunities for this pass to do anything if the
// regular LLVM optimizer passes are run. However, it does make things nicer
// at -O0.
//
//===-----------------------------------------------------------------------===//
#include "OptPasses.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Constants.h"
namespace llvm {
/*
* Find cases where an alloca is used only to load and store a single value,
* even though it is bitcast. Then replace it with a direct alloca of that
* simple type, and avoid the bitcasts.
*/
struct SimplifyAllocas : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
SimplifyAllocas() : FunctionPass(ID) {}
// XXX initialize..(*PassRegistry::getPassRegistry()); }
bool runOnFunction(Function &Func) override;
StringRef getPassName() const override { return "SimplifyAllocas"; }
};
char SimplifyAllocas::ID = 0;
bool SimplifyAllocas::runOnFunction(Function &Func) {
bool Changed = false;
Type *i32 = Type::getInt32Ty(Func.getContext());
std::vector<Instruction*> ToRemove; // removing can invalidate our iterators, so do it all at the end
for (Function::iterator B = Func.begin(), E = Func.end(); B != E; ++B) {
for (BasicBlock::iterator BI = B->begin(), BE = B->end(); BI != BE; ) {
Instruction *I = &*BI++;
AllocaInst *AI = dyn_cast<AllocaInst>(I);
if (!AI) continue;
if (!isa<ConstantInt>(AI->getArraySize())) continue;
bool Fail = false;
Type *ActualType = NULL;
#define CHECK_TYPE(TT) { \
Type *T = TT; \
if (!ActualType) { \
ActualType = T; \
} else { \
if (T != ActualType) Fail = true; \
} \
}
std::vector<Instruction*> Aliases; // the bitcasts of this alloca
for (Instruction::user_iterator UI = AI->user_begin(), UE = AI->user_end(); UI != UE && !Fail; ++UI) {
Instruction *U = cast<Instruction>(*UI);
if (U->getOpcode() != Instruction::BitCast) { Fail = true; break; }
// bitcasting just to do loads and stores is ok
for (Instruction::user_iterator BUI = U->user_begin(), BUE = U->user_end(); BUI != BUE && !Fail; ++BUI) {
Instruction *BU = cast<Instruction>(*BUI);
if (BU->getOpcode() == Instruction::Load) {
CHECK_TYPE(BU->getType());
break;
}
if (BU->getOpcode() != Instruction::Store) { Fail = true; break; }
CHECK_TYPE(BU->getOperand(0)->getType());
if (BU->getOperand(0) == U) { Fail = true; break; }
}
if (!Fail) Aliases.push_back(U);
}
if (!Fail && Aliases.size() > 0 && ActualType) {
// success, replace the alloca and the bitcast aliases with a single simple alloca
AllocaInst *NA = new AllocaInst(ActualType, ConstantInt::get(i32, 1), "", I);
NA->takeName(AI);
NA->setAlignment(AI->getAlignment());
NA->setDebugLoc(AI->getDebugLoc());
for (unsigned i = 0; i < Aliases.size(); i++) {
Aliases[i]->replaceAllUsesWith(NA);
ToRemove.push_back(Aliases[i]);
}
ToRemove.push_back(AI);
Changed = true;
}
}
}
for (unsigned i = 0; i < ToRemove.size(); i++) {
ToRemove[i]->eraseFromParent();
}
return Changed;
}
//
extern FunctionPass *createEmscriptenSimplifyAllocasPass() {
return new SimplifyAllocas();
}
} // End llvm namespace