From 6000e253d4b59677030fdf2f53f8d1e5fa00a1a4 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 26 Oct 2009 19:12:14 +0000 Subject: [PATCH] Check in the experimental GEP splitter pass. This pass splits complex GEPs (more than one non-zero index) into simple GEPs (at most one non-zero index). In some simple experiments using this it's not uncommon to see 3% overall code size wins, because it exposes redundancies that can be eliminated, however it's tricky to use because instcombine aggressively undoes the work that this pass does. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85144 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/LinkAllPasses.h | 1 + include/llvm/Transforms/Scalar.h | 6 ++ lib/Transforms/Scalar/GEPSplitter.cpp | 81 +++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 lib/Transforms/Scalar/GEPSplitter.cpp diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 9335976f33a..bc5722e82e9 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -141,6 +141,7 @@ namespace { (void) llvm::createPartialInliningPass(); (void) llvm::createSSIPass(); (void) llvm::createSSIEverythingPass(); + (void) llvm::createGEPSplitterPass(); (void)new llvm::IntervalPartition(); (void)new llvm::FindUsedTypes(); diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index fee4e659381..c5378994fdc 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -341,6 +341,12 @@ FunctionPass *createSSIPass(); // FunctionPass *createSSIEverythingPass(); +//===----------------------------------------------------------------------===// +// +// GEPSplitter - Split complex GEPs into simple ones +// +FunctionPass *createGEPSplitterPass(); + } // End llvm namespace #endif diff --git a/lib/Transforms/Scalar/GEPSplitter.cpp b/lib/Transforms/Scalar/GEPSplitter.cpp new file mode 100644 index 00000000000..610a41dae44 --- /dev/null +++ b/lib/Transforms/Scalar/GEPSplitter.cpp @@ -0,0 +1,81 @@ +//===- GEPSplitter.cpp - Split complex GEPs into simple ones --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This function breaks GEPs with more than 2 non-zero operands into smaller +// GEPs each with no more than 2 non-zero operands. This exposes redundancy +// between GEPs with common initial operand sequences. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "split-geps" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/Instructions.h" +#include "llvm/Pass.h" +using namespace llvm; + +namespace { + class GEPSplitter : public FunctionPass { + virtual bool runOnFunction(Function &F); + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + public: + static char ID; // Pass identification, replacement for typeid + explicit GEPSplitter() : FunctionPass(&ID) {} + }; +} + +char GEPSplitter::ID = 0; +static RegisterPass X("split-geps", + "split complex GEPs into simple GEPs"); + +FunctionPass *llvm::createGEPSplitterPass() { + return new GEPSplitter(); +} + +bool GEPSplitter::runOnFunction(Function &F) { + bool Changed = false; + + // Visit each GEP instruction. + for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) + for (BasicBlock::iterator II = I->begin(), IE = I->end(); II != IE; ) + if (GetElementPtrInst *GEP = dyn_cast(II++)) { + unsigned NumOps = GEP->getNumOperands(); + // Ignore GEPs which are already simple. + if (NumOps <= 2) + continue; + bool FirstIndexIsZero = isa(GEP->getOperand(1)) && + cast(GEP->getOperand(1))->isZero(); + if (NumOps == 3 && FirstIndexIsZero) + continue; + // The first index is special and gets expanded with a 2-operand GEP + // (unless it's zero, in which case we can skip this). + Value *NewGEP = FirstIndexIsZero ? + GEP->getOperand(0) : + GetElementPtrInst::Create(GEP->getOperand(0), GEP->getOperand(1), + "tmp", GEP); + // All remaining indices get expanded with a 3-operand GEP with zero + // as the second operand. + Value *Idxs[2]; + Idxs[0] = ConstantInt::get(Type::getInt64Ty(F.getContext()), 0); + for (unsigned i = 2; i != NumOps; ++i) { + Idxs[1] = GEP->getOperand(i); + NewGEP = GetElementPtrInst::Create(NewGEP, Idxs, Idxs+2, "tmp", GEP); + } + GEP->replaceAllUsesWith(NewGEP); + GEP->eraseFromParent(); + Changed = true; + } + + return Changed; +} + +void GEPSplitter::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); +}