diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-12-22 11:49:39 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-12-22 11:49:39 -0800 |
commit | 1e9d5df67061e962ed148d13258a903f03ce715c (patch) | |
tree | aa36919b70bc5084227307d48ae6da8f0b391524 | |
parent | 8ce3964b44fba5e43fc3156320fed9f7446413fa (diff) |
add pass to simplify allocas, so they can better be nativized later
-rw-r--r-- | lib/Target/CppBackend/OptPasses.h | 22 | ||||
-rw-r--r-- | lib/Target/CppBackend/SimplifyAllocas.cpp | 136 |
2 files changed, 158 insertions, 0 deletions
diff --git a/lib/Target/CppBackend/OptPasses.h b/lib/Target/CppBackend/OptPasses.h new file mode 100644 index 0000000000..99f1459462 --- /dev/null +++ b/lib/Target/CppBackend/OptPasses.h @@ -0,0 +1,22 @@ +//===-- CPPTargetMachine.h - TargetMachine for the C++ backend --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef OPT_PASSES_H +#define OPT_PASSES_H + +#include "llvm/Pass.h" + +namespace llvm { + + extern FunctionPass *createSimplifyAllocasPass(); + +} // End llvm namespace + +#endif + diff --git a/lib/Target/CppBackend/SimplifyAllocas.cpp b/lib/Target/CppBackend/SimplifyAllocas.cpp new file mode 100644 index 0000000000..8fbda0b97c --- /dev/null +++ b/lib/Target/CppBackend/SimplifyAllocas.cpp @@ -0,0 +1,136 @@ +//===-- CPPTargetMachine.h - TargetMachine for the C++ backend --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <OptPasses.h> + +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Function.h" + +// XXX +#include "llvm/Support/FormattedStream.h" +#include <stdio.h> +#define dump(x) fprintf(stderr, x "\n") +#define dumpv(x, ...) fprintf(stderr, x "\n", __VA_ARGS__) +#define dumpfail(x) { fprintf(stderr, x "\n"); fprintf(stderr, "%s : %d\n", __FILE__, __LINE__); report_fatal_error("fail"); } +#define dumpfailv(x, ...) { fprintf(stderr, x "\n", __VA_ARGS__); fprintf(stderr, "%s : %d\n", __FILE__, __LINE__); report_fatal_error("fail"); } +#define dumpIR(value) { \ + std::string temp; \ + raw_string_ostream stream(temp); \ + stream << *(value); \ + fprintf(stderr, "%s\n", temp.c_str()); \ +} +#undef assert +#define assert(x) { if (!(x)) dumpfail(#x); } +// XXX + +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. + */ + +struct SimplifyAllocas : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + SimplifyAllocas() : FunctionPass(ID) {} + // XXX initialize..(*PassRegistry::getPassRegistry()); } + + virtual bool runOnFunction(Function &Func); +}; + +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::use_iterator UI = AI->use_begin(), UE = AI->use_end(); UI != UE && !Fail; ++UI) { + Instruction *U = dyn_cast<Instruction>(*UI); + if (!U) { Fail = true; break; } + switch (U->getOpcode()) { + case Instruction::Load: { + CHECK_TYPE(U->getType()); + break; + } + case Instruction::Store: { + CHECK_TYPE(U->getOperand(0)->getType()); + if (U->getOperand(0) == AI) Fail = true; + break; + } + case Instruction::BitCast: { + // bitcasting just to do loads and stores is ok + for (Instruction::use_iterator BUI = U->use_begin(), BUE = U->use_end(); BUI != BUE && !Fail; ++BUI) { + Instruction *BU = dyn_cast<Instruction>(*BUI); + if (!BU) { Fail = true; break; } + 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); + break; + } + default: { Fail = true; break; } + } + } + if (!Fail && Aliases.size() > 0) { +dump("win!"); +dumpv("%s", Func.getName().str().c_str()); +dumpIR(AI); + // 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()); + AI->replaceAllUsesWith(NA); + ToRemove.push_back(AI); + for (unsigned i = 0; i < Aliases.size(); i++) { + Aliases[i]->replaceAllUsesWith(NA); + ToRemove.push_back(Aliases[i]); + } + Changed = true; + } + } + } + for (unsigned i = 0; i < ToRemove.size(); i++) { + ToRemove[i]->removeFromParent(); + } + return Changed; +} + +// + +extern FunctionPass *createSimplifyAllocasPass() { + return new SimplifyAllocas(); +} + +} // End llvm namespace + |