mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-21 18:29:46 +00:00
Remove special-case SROA optimization of variable indexes to one-element and
two-element arrays. After restructuring the SROA code, it was not safe to do this without adding more checking. It is not clear that this special-case has really been useful, and removing this simplifies the code quite a bit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91828 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ff99b16637
commit
3c3af5d155
@ -107,12 +107,11 @@ namespace {
|
||||
int isSafeAllocaToScalarRepl(AllocaInst *AI);
|
||||
|
||||
void isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
||||
uint64_t ArrayOffset, AllocaInfo &Info);
|
||||
AllocaInfo &Info);
|
||||
void isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI, uint64_t &Offset,
|
||||
uint64_t &ArrayOffset, AllocaInfo &Info);
|
||||
void isSafeMemAccess(AllocaInst *AI, uint64_t Offset, uint64_t ArrayOffset,
|
||||
uint64_t MemSize, const Type *MemOpType, bool isStore,
|
||||
AllocaInfo &Info);
|
||||
AllocaInfo &Info);
|
||||
void isSafeMemAccess(AllocaInst *AI, uint64_t Offset, uint64_t MemSize,
|
||||
const Type *MemOpType, bool isStore, AllocaInfo &Info);
|
||||
bool TypeHasComponent(const Type *T, uint64_t Offset, uint64_t Size);
|
||||
uint64_t FindElementAndOffset(const Type *&T, uint64_t &Offset,
|
||||
const Type *&IdxTy);
|
||||
@ -120,7 +119,6 @@ namespace {
|
||||
void DoScalarReplacement(AllocaInst *AI,
|
||||
std::vector<AllocaInst*> &WorkList);
|
||||
void DeleteDeadInstructions();
|
||||
void CleanupGEP(GetElementPtrInst *GEP);
|
||||
void CleanupAllocaUsers(Value *V);
|
||||
AllocaInst *AddNewAlloca(Function &F, const Type *Ty, AllocaInst *Base);
|
||||
|
||||
@ -401,43 +399,33 @@ void SROA::DeleteDeadInstructions() {
|
||||
}
|
||||
}
|
||||
|
||||
/// AllUsersAreLoads - Return true if all users of this value are loads.
|
||||
static bool AllUsersAreLoads(Value *Ptr) {
|
||||
for (Value::use_iterator I = Ptr->use_begin(), E = Ptr->use_end();
|
||||
I != E; ++I)
|
||||
if (cast<Instruction>(*I)->getOpcode() != Instruction::Load)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// isSafeForScalarRepl - Check if instruction I is a safe use with regard to
|
||||
/// performing scalar replacement of alloca AI. The results are flagged in
|
||||
/// the Info parameter. Offset and ArrayOffset indicate the position within
|
||||
/// AI that is referenced by this instruction.
|
||||
/// the Info parameter. Offset indicates the position within AI that is
|
||||
/// referenced by this instruction.
|
||||
void SROA::isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
||||
uint64_t ArrayOffset, AllocaInfo &Info) {
|
||||
AllocaInfo &Info) {
|
||||
for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI!=E; ++UI) {
|
||||
Instruction *User = cast<Instruction>(*UI);
|
||||
|
||||
if (BitCastInst *BC = dyn_cast<BitCastInst>(User)) {
|
||||
isSafeForScalarRepl(BC, AI, Offset, ArrayOffset, Info);
|
||||
isSafeForScalarRepl(BC, AI, Offset, Info);
|
||||
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(User)) {
|
||||
uint64_t GEPArrayOffset = ArrayOffset;
|
||||
uint64_t GEPOffset = Offset;
|
||||
isSafeGEP(GEPI, AI, GEPOffset, GEPArrayOffset, Info);
|
||||
isSafeGEP(GEPI, AI, GEPOffset, Info);
|
||||
if (!Info.isUnsafe)
|
||||
isSafeForScalarRepl(GEPI, AI, GEPOffset, GEPArrayOffset, Info);
|
||||
isSafeForScalarRepl(GEPI, AI, GEPOffset, Info);
|
||||
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(UI)) {
|
||||
ConstantInt *Length = dyn_cast<ConstantInt>(MI->getLength());
|
||||
if (Length)
|
||||
isSafeMemAccess(AI, Offset, ArrayOffset, Length->getZExtValue(), 0,
|
||||
isSafeMemAccess(AI, Offset, Length->getZExtValue(), 0,
|
||||
UI.getOperandNo() == 1, Info);
|
||||
else
|
||||
MarkUnsafe(Info);
|
||||
} else if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
|
||||
if (!LI->isVolatile()) {
|
||||
const Type *LIType = LI->getType();
|
||||
isSafeMemAccess(AI, Offset, ArrayOffset, TD->getTypeAllocSize(LIType),
|
||||
isSafeMemAccess(AI, Offset, TD->getTypeAllocSize(LIType),
|
||||
LIType, false, Info);
|
||||
} else
|
||||
MarkUnsafe(Info);
|
||||
@ -445,7 +433,7 @@ void SROA::isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
||||
// Store is ok if storing INTO the pointer, not storing the pointer
|
||||
if (!SI->isVolatile() && SI->getOperand(0) != I) {
|
||||
const Type *SIType = SI->getOperand(0)->getType();
|
||||
isSafeMemAccess(AI, Offset, ArrayOffset, TD->getTypeAllocSize(SIType),
|
||||
isSafeMemAccess(AI, Offset, TD->getTypeAllocSize(SIType),
|
||||
SIType, true, Info);
|
||||
} else
|
||||
MarkUnsafe(Info);
|
||||
@ -469,12 +457,9 @@ void SROA::isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
||||
/// replacement. It is safe when all the indices are constant, in-bounds
|
||||
/// references, and when the resulting offset corresponds to an element within
|
||||
/// the alloca type. The results are flagged in the Info parameter. Upon
|
||||
/// return, Offset is adjusted as specified by the GEP indices. For the
|
||||
/// special case of a variable index to a 2-element array, ArrayOffset is set
|
||||
/// to the array element size.
|
||||
/// return, Offset is adjusted as specified by the GEP indices.
|
||||
void SROA::isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI,
|
||||
uint64_t &Offset, uint64_t &ArrayOffset,
|
||||
AllocaInfo &Info) {
|
||||
uint64_t &Offset, AllocaInfo &Info) {
|
||||
gep_type_iterator GEPIt = gep_type_begin(GEPI), E = gep_type_end(GEPI);
|
||||
if (GEPIt == E)
|
||||
return;
|
||||
@ -486,27 +471,6 @@ void SROA::isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI,
|
||||
if (++GEPIt == E)
|
||||
return;
|
||||
|
||||
// If the first index is a non-constant index into an array, see if we can
|
||||
// handle it as a special case.
|
||||
const Type *ArrayEltTy = 0;
|
||||
if (!isa<ConstantInt>(GEPIt.getOperand()) &&
|
||||
ArrayOffset == 0 && Offset == 0) {
|
||||
if (const ArrayType *AT = dyn_cast<ArrayType>(*GEPIt)) {
|
||||
uint64_t NumElements = AT->getNumElements();
|
||||
|
||||
// If this is an array index and the index is not constant, we cannot
|
||||
// promote... that is unless the array has exactly one or two elements
|
||||
// in it, in which case we CAN promote it, but we have to canonicalize
|
||||
// this out if this is the only problem.
|
||||
if ((NumElements != 1 && NumElements != 2) || !AllUsersAreLoads(GEPI))
|
||||
return MarkUnsafe(Info);
|
||||
Info.needsCleanup = true;
|
||||
ArrayOffset = TD->getTypeAllocSizeInBits(AT->getElementType());
|
||||
ArrayEltTy = AT->getElementType();
|
||||
++GEPIt;
|
||||
}
|
||||
}
|
||||
|
||||
// Walk through the GEP type indices, checking the types that this indexes
|
||||
// into.
|
||||
for (; GEPIt != E; ++GEPIt) {
|
||||
@ -535,19 +499,9 @@ void SROA::isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI,
|
||||
|
||||
// All the indices are safe. Now compute the offset due to this GEP and
|
||||
// check if the alloca has a component element at that offset.
|
||||
if (ArrayOffset == 0) {
|
||||
SmallVector<Value*, 8> Indices(GEPI->op_begin() + 1, GEPI->op_end());
|
||||
Offset += TD->getIndexedOffset(GEPI->getPointerOperandType(),
|
||||
&Indices[0], Indices.size());
|
||||
} else {
|
||||
// Both array elements have the same type, so it suffices to check one of
|
||||
// them. Copy the GEP indices starting from the array index, but replace
|
||||
// that variable index with a constant zero.
|
||||
SmallVector<Value*, 8> Indices(GEPI->op_begin() + 2, GEPI->op_end());
|
||||
Indices[0] = Constant::getNullValue(Type::getInt32Ty(GEPI->getContext()));
|
||||
const Type *ArrayEltPtr = PointerType::getUnqual(ArrayEltTy);
|
||||
Offset += TD->getIndexedOffset(ArrayEltPtr, &Indices[0], Indices.size());
|
||||
}
|
||||
SmallVector<Value*, 8> Indices(GEPI->op_begin() + 1, GEPI->op_end());
|
||||
Offset += TD->getIndexedOffset(GEPI->getPointerOperandType(),
|
||||
&Indices[0], Indices.size());
|
||||
if (!TypeHasComponent(AI->getAllocatedType(), Offset, 0))
|
||||
MarkUnsafe(Info);
|
||||
}
|
||||
@ -556,13 +510,11 @@ void SROA::isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI,
|
||||
/// alloca or has an offset and size that corresponds to a component element
|
||||
/// within it. The offset checked here may have been formed from a GEP with a
|
||||
/// pointer bitcasted to a different type.
|
||||
void SROA::isSafeMemAccess(AllocaInst *AI, uint64_t Offset,
|
||||
uint64_t ArrayOffset, uint64_t MemSize,
|
||||
void SROA::isSafeMemAccess(AllocaInst *AI, uint64_t Offset, uint64_t MemSize,
|
||||
const Type *MemOpType, bool isStore,
|
||||
AllocaInfo &Info) {
|
||||
// Check if this is a load/store of the entire alloca.
|
||||
if (Offset == 0 && ArrayOffset == 0 &&
|
||||
MemSize == TD->getTypeAllocSize(AI->getAllocatedType())) {
|
||||
if (Offset == 0 && MemSize == TD->getTypeAllocSize(AI->getAllocatedType())) {
|
||||
bool UsesAggregateType = (MemOpType == AI->getAllocatedType());
|
||||
// This is safe for MemIntrinsics (where MemOpType is 0), integer types
|
||||
// (which are essentially the same as the MemIntrinsics, especially with
|
||||
@ -580,8 +532,7 @@ void SROA::isSafeMemAccess(AllocaInst *AI, uint64_t Offset,
|
||||
}
|
||||
// Check if the offset/size correspond to a component within the alloca type.
|
||||
const Type *T = AI->getAllocatedType();
|
||||
if (TypeHasComponent(T, Offset, MemSize) &&
|
||||
(ArrayOffset == 0 || TypeHasComponent(T, Offset + ArrayOffset, MemSize)))
|
||||
if (TypeHasComponent(T, Offset, MemSize))
|
||||
return;
|
||||
|
||||
return MarkUnsafe(Info);
|
||||
@ -1219,7 +1170,7 @@ int SROA::isSafeAllocaToScalarRepl(AllocaInst *AI) {
|
||||
// the users are safe to transform.
|
||||
AllocaInfo Info;
|
||||
|
||||
isSafeForScalarRepl(AI, AI, 0, 0, Info);
|
||||
isSafeForScalarRepl(AI, AI, 0, Info);
|
||||
if (Info.isUnsafe) {
|
||||
DEBUG(errs() << "Cannot transform: " << *AI << '\n');
|
||||
return 0;
|
||||
@ -1238,83 +1189,21 @@ int SROA::isSafeAllocaToScalarRepl(AllocaInst *AI) {
|
||||
return Info.needsCleanup ? 1 : 3;
|
||||
}
|
||||
|
||||
/// CleanupGEP - GEP is used by an Alloca, which can be promoted after the GEP
|
||||
/// is canonicalized here.
|
||||
void SROA::CleanupGEP(GetElementPtrInst *GEPI) {
|
||||
gep_type_iterator I = gep_type_begin(GEPI);
|
||||
++I;
|
||||
|
||||
const ArrayType *AT = dyn_cast<ArrayType>(*I);
|
||||
if (!AT)
|
||||
return;
|
||||
|
||||
uint64_t NumElements = AT->getNumElements();
|
||||
|
||||
if (isa<ConstantInt>(I.getOperand()))
|
||||
return;
|
||||
|
||||
if (NumElements == 1) {
|
||||
GEPI->setOperand(2,
|
||||
Constant::getNullValue(Type::getInt32Ty(GEPI->getContext())));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(NumElements == 2 && "Unhandled case!");
|
||||
// All users of the GEP must be loads. At each use of the GEP, insert
|
||||
// two loads of the appropriate indexed GEP and select between them.
|
||||
Value *IsOne = new ICmpInst(GEPI, ICmpInst::ICMP_NE, I.getOperand(),
|
||||
Constant::getNullValue(I.getOperand()->getType()),
|
||||
"isone");
|
||||
// Insert the new GEP instructions, which are properly indexed.
|
||||
SmallVector<Value*, 8> Indices(GEPI->op_begin()+1, GEPI->op_end());
|
||||
Indices[1] = Constant::getNullValue(Type::getInt32Ty(GEPI->getContext()));
|
||||
Value *ZeroIdx = GetElementPtrInst::CreateInBounds(GEPI->getOperand(0),
|
||||
Indices.begin(),
|
||||
Indices.end(),
|
||||
GEPI->getName()+".0",GEPI);
|
||||
Indices[1] = ConstantInt::get(Type::getInt32Ty(GEPI->getContext()), 1);
|
||||
Value *OneIdx = GetElementPtrInst::CreateInBounds(GEPI->getOperand(0),
|
||||
Indices.begin(),
|
||||
Indices.end(),
|
||||
GEPI->getName()+".1", GEPI);
|
||||
// Replace all loads of the variable index GEP with loads from both
|
||||
// indexes and a select.
|
||||
while (!GEPI->use_empty()) {
|
||||
LoadInst *LI = cast<LoadInst>(GEPI->use_back());
|
||||
Value *Zero = new LoadInst(ZeroIdx, LI->getName()+".0", LI);
|
||||
Value *One = new LoadInst(OneIdx , LI->getName()+".1", LI);
|
||||
Value *R = SelectInst::Create(IsOne, One, Zero, LI->getName(), LI);
|
||||
LI->replaceAllUsesWith(R);
|
||||
LI->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
/// CleanupAllocaUsers - If SROA reported that it can promote the specified
|
||||
/// allocation, but only if cleaned up, perform the cleanups required.
|
||||
void SROA::CleanupAllocaUsers(Value *V) {
|
||||
// At this point, we know that the end result will be SROA'd and promoted, so
|
||||
// we can insert ugly code if required so long as sroa+mem2reg will clean it
|
||||
// up.
|
||||
for (Value::use_iterator UI = V->use_begin(), E = V->use_end();
|
||||
UI != E; ) {
|
||||
User *U = *UI++;
|
||||
if (isa<BitCastInst>(U)) {
|
||||
CleanupAllocaUsers(U);
|
||||
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(U)) {
|
||||
CleanupGEP(GEPI);
|
||||
CleanupAllocaUsers(GEPI);
|
||||
if (GEPI->use_empty()) GEPI->eraseFromParent();
|
||||
} else {
|
||||
Instruction *I = cast<Instruction>(U);
|
||||
SmallVector<DbgInfoIntrinsic *, 2> DbgInUses;
|
||||
if (!isa<StoreInst>(I) && OnlyUsedByDbgInfoIntrinsics(I, &DbgInUses)) {
|
||||
// Safe to remove debug info uses.
|
||||
while (!DbgInUses.empty()) {
|
||||
DbgInfoIntrinsic *DI = DbgInUses.back(); DbgInUses.pop_back();
|
||||
DI->eraseFromParent();
|
||||
}
|
||||
I->eraseFromParent();
|
||||
Instruction *I = cast<Instruction>(U);
|
||||
SmallVector<DbgInfoIntrinsic *, 2> DbgInUses;
|
||||
if (!isa<StoreInst>(I) && OnlyUsedByDbgInfoIntrinsics(I, &DbgInUses)) {
|
||||
// Safe to remove debug info uses.
|
||||
while (!DbgInUses.empty()) {
|
||||
DbgInfoIntrinsic *DI = DbgInUses.back(); DbgInUses.pop_back();
|
||||
DI->eraseFromParent();
|
||||
}
|
||||
I->eraseFromParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user