SROA: Replace the member function template contraption for recursively splitting aggregates into a real class.

No intended functionality change.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164135 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer 2012-09-18 16:20:46 +00:00
parent 36b07f2f07
commit 6e67b254ae

View File

@ -2465,83 +2465,96 @@ private:
// Conservative default is to not rewrite anything.
bool visitInstruction(Instruction &I) { return false; }
/// \brief Generic recursive split emission routine.
///
/// This method recursively splits an aggregate op (load or store) into
/// scalar or vector ops. It splits recursively until it hits a single value
/// and emits that single value operation via the template argument.
///
/// The logic of this routine relies on GEPs and insertvalue and extractvalue
/// all operating with the same fundamental index list, merely formatted
/// differently (GEPs need actual values).
///
/// \param IRB The builder used to form new instructions.
/// \param Ty The type being split recursively into smaller ops.
/// \param Agg The aggregate value being built up or stored, depending on
/// whether this is splitting a load or a store respectively.
/// \param Ptr The base pointer of the original op, used as a base for GEPing
/// the split operations.
/// \param Indices The indices which to be used with insert- or extractvalue
/// to select the appropriate value within the aggregate for \p Ty.
/// \param GEPIndices The indices to a GEP instruction which will move \p Ptr
/// to the correct slot within the aggregate for \p Ty.
template <void (AggLoadStoreRewriter::*emitFunc)(
IRBuilder<> &IRB, Type *Ty, Value *&Agg, Value *Ptr,
ArrayRef<unsigned>, ArrayRef<Value *>,
const Twine &Name)>
void emitSplitOps(IRBuilder<> &IRB, Type *Ty, Value *&Agg, Value *Ptr,
SmallVectorImpl<unsigned> &Indices,
SmallVectorImpl<Value *> &GEPIndices,
const Twine &Name) {
if (Ty->isSingleValueType())
return (this->*emitFunc)(IRB, Ty, Agg, Ptr, Indices, GEPIndices, Name);
/// \brief Generic recursive split emission class.
class OpSplitter {
protected:
/// The builder used to form new instructions.
IRBuilder<> IRB;
/// The indices which to be used with insert- or extractvalue to select the
/// appropriate value within the aggregate.
SmallVector<unsigned, 4> Indices;
/// The indices to a GEP instruction which will move Ptr to the correct slot
/// within the aggregate.
SmallVector<Value *, 4> GEPIndices;
/// The base pointer of the original op, used as a base for GEPing the
/// split operations.
Value *Ptr;
if (ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
unsigned OldSize = Indices.size();
(void)OldSize;
for (unsigned Idx = 0, Size = ATy->getNumElements(); Idx != Size; ++Idx) {
assert(Indices.size() == OldSize && "Did not return to the old size");
Indices.push_back(Idx);
GEPIndices.push_back(IRB.getInt32(Idx));
emitSplitOps<emitFunc>(IRB, ATy->getElementType(), Agg, Ptr,
Indices, GEPIndices, Name + "." + Twine(Idx));
GEPIndices.pop_back();
Indices.pop_back();
/// Initialize the splitter with an insertion point, Ptr and start with a
/// single zero GEP index.
OpSplitter(Instruction *InsertionPoint, Value *Ptr)
: IRB(InsertionPoint), Ptr(Ptr), GEPIndices(1, IRB.getInt32(0)) {}
public:
virtual void emitFunc(Type *Ty, Value *&Agg, const Twine &Name) = 0;
/// \brief Generic recursive split emission routine.
///
/// This method recursively splits an aggregate op (load or store) into
/// scalar or vector ops. It splits recursively until it hits a single value
/// and emits that single value operation via the template argument.
///
/// The logic of this routine relies on GEPs and insertvalue and
/// extractvalue all operating with the same fundamental index list, merely
/// formatted differently (GEPs need actual values).
///
/// \param Ty The type being split recursively into smaller ops.
/// \param Agg The aggregate value being built up or stored, depending on
/// whether this is splitting a load or a store respectively.
void emitSplitOps(Type *Ty, Value *&Agg, const Twine &Name) {
if (Ty->isSingleValueType())
return emitFunc(Ty, Agg, Name);
if (ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
unsigned OldSize = Indices.size();
(void)OldSize;
for (unsigned Idx = 0, Size = ATy->getNumElements(); Idx != Size;
++Idx) {
assert(Indices.size() == OldSize && "Did not return to the old size");
Indices.push_back(Idx);
GEPIndices.push_back(IRB.getInt32(Idx));
emitSplitOps(ATy->getElementType(), Agg, Name + "." + Twine(Idx));
GEPIndices.pop_back();
Indices.pop_back();
}
return;
}
return;
}
if (StructType *STy = dyn_cast<StructType>(Ty)) {
unsigned OldSize = Indices.size();
(void)OldSize;
for (unsigned Idx = 0, Size = STy->getNumElements(); Idx != Size; ++Idx) {
assert(Indices.size() == OldSize && "Did not return to the old size");
Indices.push_back(Idx);
GEPIndices.push_back(IRB.getInt32(Idx));
emitSplitOps<emitFunc>(IRB, STy->getElementType(Idx), Agg, Ptr,
Indices, GEPIndices, Name + "." + Twine(Idx));
GEPIndices.pop_back();
Indices.pop_back();
if (StructType *STy = dyn_cast<StructType>(Ty)) {
unsigned OldSize = Indices.size();
(void)OldSize;
for (unsigned Idx = 0, Size = STy->getNumElements(); Idx != Size;
++Idx) {
assert(Indices.size() == OldSize && "Did not return to the old size");
Indices.push_back(Idx);
GEPIndices.push_back(IRB.getInt32(Idx));
emitSplitOps(STy->getElementType(Idx), Agg, Name + "." + Twine(Idx));
GEPIndices.pop_back();
Indices.pop_back();
}
return;
}
return;
llvm_unreachable("Only arrays and structs are aggregate loadable types");
}
};
llvm_unreachable("Only arrays and structs are aggregate loadable types");
}
struct LoadOpSplitter : public OpSplitter {
LoadOpSplitter(Instruction *InsertionPoint, Value *Ptr)
: OpSplitter(InsertionPoint, Ptr) {}
/// Emit a leaf load of a single value. This is called at the leaves of the
/// recursive emission to actually load values.
void emitLoad(IRBuilder<> &IRB, Type *Ty, Value *&Agg, Value *Ptr,
ArrayRef<unsigned> Indices, ArrayRef<Value *> GEPIndices,
const Twine &Name) {
assert(Ty->isSingleValueType());
// Load the single value and insert it using the indices.
Value *Load = IRB.CreateLoad(IRB.CreateInBoundsGEP(Ptr, GEPIndices,
Name + ".gep"),
Name + ".load");
Agg = IRB.CreateInsertValue(Agg, Load, Indices, Name + ".insert");
DEBUG(dbgs() << " to: " << *Load << "\n");
}
/// Emit a leaf load of a single value. This is called at the leaves of the
/// recursive emission to actually load values.
virtual void emitFunc(Type *Ty, Value *&Agg, const Twine &Name) {
assert(Ty->isSingleValueType());
// Load the single value and insert it using the indices.
Value *Load = IRB.CreateLoad(IRB.CreateInBoundsGEP(Ptr, GEPIndices,
Name + ".gep"),
Name + ".load");
Agg = IRB.CreateInsertValue(Agg, Load, Indices, Name + ".insert");
DEBUG(dbgs() << " to: " << *Load << "\n");
}
};
bool visitLoadInst(LoadInst &LI) {
assert(LI.getPointerOperand() == *U);
@ -2550,31 +2563,30 @@ private:
// We have an aggregate being loaded, split it apart.
DEBUG(dbgs() << " original: " << LI << "\n");
IRBuilder<> IRB(&LI);
LoadOpSplitter Splitter(&LI, *U);
Value *V = UndefValue::get(LI.getType());
SmallVector<unsigned, 4> Indices;
SmallVector<Value *, 4> GEPIndices;
GEPIndices.push_back(IRB.getInt32(0));
emitSplitOps<&AggLoadStoreRewriter::emitLoad>(
IRB, LI.getType(), V, *U, Indices, GEPIndices, LI.getName() + ".fca");
Splitter.emitSplitOps(LI.getType(), V, LI.getName() + ".fca");
LI.replaceAllUsesWith(V);
LI.eraseFromParent();
return true;
}
/// Emit a leaf store of a single value. This is called at the leaves of the
/// recursive emission to actually produce stores.
void emitStore(IRBuilder<> &IRB, Type *Ty, Value *&Agg, Value *Ptr,
ArrayRef<unsigned> Indices, ArrayRef<Value *> GEPIndices,
const Twine &Name) {
assert(Ty->isSingleValueType());
// Extract the single value and store it using the indices.
Value *Store = IRB.CreateStore(
IRB.CreateExtractValue(Agg, Indices, Name + ".extract"),
IRB.CreateInBoundsGEP(Ptr, GEPIndices, Name + ".gep"));
(void)Store;
DEBUG(dbgs() << " to: " << *Store << "\n");
}
struct StoreOpSplitter : public OpSplitter {
StoreOpSplitter(Instruction *InsertionPoint, Value *Ptr)
: OpSplitter(InsertionPoint, Ptr) {}
/// Emit a leaf store of a single value. This is called at the leaves of the
/// recursive emission to actually produce stores.
virtual void emitFunc(Type *Ty, Value *&Agg, const Twine &Name) {
assert(Ty->isSingleValueType());
// Extract the single value and store it using the indices.
Value *Store = IRB.CreateStore(
IRB.CreateExtractValue(Agg, Indices, Name + ".extract"),
IRB.CreateInBoundsGEP(Ptr, GEPIndices, Name + ".gep"));
(void)Store;
DEBUG(dbgs() << " to: " << *Store << "\n");
}
};
bool visitStoreInst(StoreInst &SI) {
if (!SI.isSimple() || SI.getPointerOperand() != *U)
@ -2585,12 +2597,8 @@ private:
// We have an aggregate being stored, split it apart.
DEBUG(dbgs() << " original: " << SI << "\n");
IRBuilder<> IRB(&SI);
SmallVector<unsigned, 4> Indices;
SmallVector<Value *, 4> GEPIndices;
GEPIndices.push_back(IRB.getInt32(0));
emitSplitOps<&AggLoadStoreRewriter::emitStore>(
IRB, V->getType(), V, *U, Indices, GEPIndices, V->getName() + ".fca");
StoreOpSplitter Splitter(&SI, *U);
Splitter.emitSplitOps(V->getType(), V, V->getName() + ".fca");
SI.eraseFromParent();
return true;
}