aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-12-22 11:49:39 -0800
committerAlon Zakai <alonzakai@gmail.com>2013-12-22 11:49:39 -0800
commit1e9d5df67061e962ed148d13258a903f03ce715c (patch)
treeaa36919b70bc5084227307d48ae6da8f0b391524
parent8ce3964b44fba5e43fc3156320fed9f7446413fa (diff)
add pass to simplify allocas, so they can better be nativized later
-rw-r--r--lib/Target/CppBackend/OptPasses.h22
-rw-r--r--lib/Target/CppBackend/SimplifyAllocas.cpp136
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
+