From ed7b41ea90a17c826f195acbc456c4bb733113d6 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 27 May 2003 15:45:27 +0000 Subject: [PATCH] Implementation of the simple "scalar replacement of aggregates" transformation git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6346 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Scalar/ScalarReplAggregates.cpp | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 lib/Transforms/Scalar/ScalarReplAggregates.cpp diff --git a/lib/Transforms/Scalar/ScalarReplAggregates.cpp b/lib/Transforms/Scalar/ScalarReplAggregates.cpp new file mode 100644 index 00000000000..0ca7e69d19c --- /dev/null +++ b/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -0,0 +1,164 @@ +//===- ScalarReplAggregates.cpp - Scalar Replacement of Aggregates --------===// +// +// This transformation implements the well known scalar replacement of +// aggregates transformation. This xform breaks up alloca instructions of +// aggregate type (structure or array) into individual alloca instructions for +// each member (if possible). +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar.h" +#include "llvm/Function.h" +#include "llvm/Pass.h" +#include "llvm/iMemory.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Constants.h" +#include "Support/StringExtras.h" +#include "Support/Statistic.h" + +namespace { + Statistic<> NumReplaced("scalarrepl", "Number of alloca's broken up"); + + struct SROA : public FunctionPass { + bool runOnFunction(Function &F); + + private: + AllocaInst *AddNewAlloca(Function &F, const Type *Ty, AllocationInst *Base); + }; + + RegisterOpt X("scalarrepl", "Scalar Replacement of Aggregates"); +} + +Pass *createScalarReplAggregatesPass() { return new SROA(); } + + +// runOnFunction - This algorithm is a simple worklist driven algorithm, which +// runs on all of the malloc/alloca instructions in the function, removing them +// if they are only used by getelementptr instructions. +// +bool SROA::runOnFunction(Function &F) { + std::vector WorkList; + + // Scan the entry basic block, adding any alloca's and mallocs to the worklist + BasicBlock &BB = F.getEntryNode(); + for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) + if (AllocationInst *A = dyn_cast(I)) + WorkList.push_back(A); + + // Process the worklist + bool Changed = false; + while (!WorkList.empty()) { + AllocationInst *AI = WorkList.back(); + WorkList.pop_back(); + + // We cannot transform the allocation instruction if it is an array + // allocation, and an allocation of a scalar value cannot be decomposed + if (AI->isArrayAllocation() || + (!isa(AI->getAllocatedType()) /*&& + !isa(AI->getAllocatedType())*/ + )) continue; + + // Loop over the use list of the alloca. We can only transform it if there + // are only getelementptr instructions (with a zero first index) and free + // instructions. + // + bool CannotTransform = false; + for (Value::use_iterator I = AI->use_begin(), E = AI->use_end(); + I != E; ++I) { + Instruction *User = cast(*I); + if (GetElementPtrInst *GEPI = dyn_cast(User)) { + // The GEP is safe to transform if it is of the form GEP , 0, + if (GEPI->getNumOperands() <= 2 || + GEPI->getOperand(1) != Constant::getNullValue(Type::LongTy) || + !isa(GEPI->getOperand(2)) || + isa(GEPI->getOperand(2))) { + DEBUG(std::cerr << "Cannot transform: " << *AI << " due to user: " + << User); + CannotTransform = true; + break; + } + } else { + DEBUG(std::cerr << "Cannot transform: " << *AI << " due to user: " + << User); + CannotTransform = true; + break; + } + } + + if (CannotTransform) continue; + + DEBUG(std::cerr << "Found inst to xform: " << *AI); + Changed = true; + + std::vector ElementAllocas; + if (const StructType *ST = dyn_cast(AI->getAllocatedType())) { + ElementAllocas.reserve(ST->getNumContainedTypes()); + for (unsigned i = 0, e = ST->getNumContainedTypes(); i != e; ++i) { + AllocaInst *NA = new AllocaInst(ST->getContainedType(i), 0, + AI->getName() + "." + utostr(i), AI); + ElementAllocas.push_back(NA); + WorkList.push_back(NA); // Add to worklist for recursive processing + } + } else { + const ArrayType *AT = cast(AI->getAllocatedType()); + ElementAllocas.reserve(AT->getNumElements()); + const Type *ElTy = AT->getElementType(); + for (unsigned i = 0, e = AT->getNumElements(); i != e; ++i) { + AllocaInst *NA = new AllocaInst(ElTy, 0, + AI->getName() + "." + utostr(i), AI); + ElementAllocas.push_back(NA); + WorkList.push_back(NA); // Add to worklist for recursive processing + } + } + + // Now that we have created the alloca instructions that we want to use, + // expand the getelementptr instructions to use them. + // + for (Value::use_iterator I = AI->use_begin(), E = AI->use_end(); + I != E; ++I) { + Instruction *User = cast(*I); + if (GetElementPtrInst *GEPI = dyn_cast(User)) { + // We now know that the GEP is of the form: GEP , 0, + uint64_t Idx; + if (ConstantSInt *CSI = dyn_cast(GEPI->getOperand(2))) + Idx = CSI->getValue(); + else + Idx = cast(GEPI->getOperand(2))->getValue(); + + assert(Idx < ElementAllocas.size() && "Index out of range?"); + AllocaInst *AllocaToUse = ElementAllocas[Idx]; + + Value *RepValue; + if (GEPI->getNumOperands() == 3) { + // Do not insert a new getelementptr instruction with zero indices, + // only to have it optimized out later. + RepValue = AllocaToUse; + } else { + // We are indexing deeply into the structure, so we still need a + // getelement ptr instruction to finish the indexing. This may be + // expanded itself once the worklist is rerun. + // + std::string OldName = GEPI->getName(); // Steal the old name... + GEPI->setName(""); + RepValue = + new GetElementPtrInst(AllocaToUse, + std::vector(GEPI->op_begin()+3, + GEPI->op_end()), + OldName, GEPI); + } + + // Move all of the users over to the new GEP. + GEPI->replaceAllUsesWith(RepValue); + // Delete the old GEP + GEPI->getParent()->getInstList().erase(GEPI); + } else { + assert(0 && "Unexpected instruction type!"); + } + } + + // Finally, delete the Alloca instruction + AI->getParent()->getInstList().erase(AI); + } + + return Changed; +}