summaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2001-12-14 16:52:21 +0000
committerChris Lattner <sabre@nondot.org>2001-12-14 16:52:21 +0000
commit8a2a3119395915cf57c771c2d555e1018628751c (patch)
tree86220a6f42c5d4bd928f319769f9c7cc878814e8 /lib/Transforms
parent2d8a523490addd509bbaa3371b622bde3cb58c6a (diff)
downloadllvm-8a2a3119395915cf57c771c2d555e1018628751c.tar.gz
llvm-8a2a3119395915cf57c771c2d555e1018628751c.tar.bz2
llvm-8a2a3119395915cf57c771c2d555e1018628751c.tar.xz
initial checkin
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1480 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms')
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
new file mode 100644
index 0000000000..87f8ed1897
--- /dev/null
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -0,0 +1,150 @@
+//===- InstructionCombining.cpp - Combine multiple instructions -------------=//
+//
+// InstructionCombining - Combine instructions to form fewer, simple
+// instructions. This pass does not modify the CFG, and has a tendancy to
+// make instructions dead, so a subsequent DCE pass is useful.
+//
+// This pass combines things like:
+// %Y = add int 1, %X
+// %Z = add int 1, %Y
+// into:
+// %Z = add int 2, %X
+//
+// This is a simple worklist driven algorithm.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/InstructionCombining.h"
+#include "../TransformInternals.h"
+#include "llvm/Optimizations/ConstantHandling.h"
+#include "llvm/Method.h"
+#include "llvm/iMemory.h"
+
+using namespace opt;
+
+static Instruction *CombineBinOp(BinaryOperator *I) {
+ bool Changed = false;
+
+ // First thing we do is make sure that this instruction has a constant on the
+ // right hand side if it has any constant arguments.
+ //
+ if (isa<Constant>(I->getOperand(0)) && !isa<Constant>(I->getOperand(1)))
+ if (!I->swapOperands())
+ Changed = true;
+
+ bool LocalChange = true;
+ while (LocalChange) {
+ LocalChange = false;
+ Value *Op1 = I->getOperand(0);
+ if (Constant *Op2 = dyn_cast<Constant>(I->getOperand(1))) {
+ if (I->getOpcode() == Instruction::Add) {
+ if (Instruction *IOp1 = dyn_cast<Instruction>(Op1)) {
+ if (IOp1->getOpcode() == Instruction::Add &&
+ isa<Constant>(IOp1->getOperand(1))) {
+ // Fold:
+ // %Y = add int %X, 1
+ // %Z = add int %Y, 1
+ // into:
+ // %Z = add int %X, 2
+ //
+ // Constant fold both constants...
+ Constant *Val = *Op2 + *cast<Constant>(IOp1->getOperand(1));
+
+ if (Val) {
+ I->setOperand(0, IOp1->getOperand(0));
+ I->setOperand(1, Val);
+ LocalChange = true;
+ }
+ }
+
+ }
+ }
+ }
+ Changed |= LocalChange;
+ }
+
+ if (!Changed) return 0;
+ return I;
+}
+
+// Combine Indices - If the source pointer to this mem access instruction is a
+// getelementptr instruction, combine the indices of the GEP into this
+// instruction
+//
+static Instruction *CombineIndicies(MemAccessInst *MAI) {
+ GetElementPtrInst *Src =
+ dyn_cast<GetElementPtrInst>(MAI->getPointerOperand());
+ if (!Src) return 0;
+
+ vector<Value *> Indices;
+
+ // Only special case we have to watch out for is pointer arithmetic on the
+ // 0th index of MAI.
+ unsigned FirstIdx = MAI->getFirstIndexOperandNumber();
+ if (FirstIdx == MAI->getNumOperands() ||
+ (FirstIdx == MAI->getNumOperands()-1 &&
+ MAI->getOperand(FirstIdx) == ConstantUInt::get(Type::UIntTy, 0))) {
+ // Replace the index list on this MAI with the index on the getelementptr
+ Indices.insert(Indices.end(), Src->idx_begin(), Src->idx_end());
+ } else if (*MAI->idx_begin() == ConstantUInt::get(Type::UIntTy, 0)) {
+ // Otherwise we can do the fold if the first index of the GEP is a zero
+ Indices.insert(Indices.end(), Src->idx_begin(), Src->idx_end());
+ Indices.insert(Indices.end(), MAI->idx_begin()+1, MAI->idx_end());
+ }
+
+ if (Indices.empty()) return 0; // Can't do the fold?
+
+ switch (MAI->getOpcode()) {
+ case Instruction::GetElementPtr:
+ return new GetElementPtrInst(Src->getOperand(0), Indices, MAI->getName());
+ case Instruction::Load:
+ return new LoadInst(Src->getOperand(0), Indices, MAI->getName());
+ case Instruction::Store:
+ return new StoreInst(MAI->getOperand(0), Src->getOperand(0),
+ Indices, MAI->getName());
+ default:
+ assert(0 && "Unknown memaccessinst!");
+ break;
+ }
+ abort();
+ return 0;
+}
+
+bool InstructionCombining::CombineInstruction(Instruction *I) {
+ Instruction *Result = 0;
+ if (BinaryOperator *BOP = dyn_cast<BinaryOperator>(I))
+ Result = CombineBinOp(BOP);
+ else if (MemAccessInst *MAI = dyn_cast<MemAccessInst>(I))
+ Result = CombineIndicies(MAI);
+
+ if (!Result) return false;
+ if (Result == I) return true;
+
+ // If we get to here, we are to replace I with Result.
+ ReplaceInstWithInst(I, Result);
+ return true;
+}
+
+
+bool InstructionCombining::doit(Method *M) {
+ // Start the worklist out with all of the instructions in the method in it.
+ vector<Instruction*> WorkList(M->inst_begin(), M->inst_end());
+
+ while (!WorkList.empty()) {
+ Instruction *I = WorkList.back(); // Get an instruction from the worklist
+ WorkList.pop_back();
+
+ // Now that we have an instruction, try combining it to simplify it...
+ if (CombineInstruction(I)) {
+ // The instruction was simplified, add all users of the instruction to
+ // the work lists because they might get more simplified now...
+ //
+ for (Value::use_iterator UI = I->use_begin(), UE = I->use_end();
+ UI != UE; ++UI)
+ if (Instruction *User = dyn_cast<Instruction>(*UI))
+ WorkList.push_back(User);
+ }
+ }
+
+ return false;
+}