mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-09-29 15:17:14 +00:00
Re-revert 91459. It's breaking the x86_64 darwin bootstrap.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91607 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -74,10 +74,6 @@ namespace {
|
|||||||
private:
|
private:
|
||||||
TargetData *TD;
|
TargetData *TD;
|
||||||
|
|
||||||
/// DeadInsts - Keep track of instructions we have made dead, so that
|
|
||||||
/// we can remove them after we are done working.
|
|
||||||
SmallVector<WeakVH, 16> DeadInsts;
|
|
||||||
|
|
||||||
/// AllocaInfo - When analyzing uses of an alloca instruction, this captures
|
/// AllocaInfo - When analyzing uses of an alloca instruction, this captures
|
||||||
/// information about the uses. All these fields are initialized to false
|
/// information about the uses. All these fields are initialized to false
|
||||||
/// and set to true when something is learned.
|
/// and set to true when something is learned.
|
||||||
@@ -106,30 +102,25 @@ namespace {
|
|||||||
|
|
||||||
int isSafeAllocaToScalarRepl(AllocaInst *AI);
|
int isSafeAllocaToScalarRepl(AllocaInst *AI);
|
||||||
|
|
||||||
void isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
void isSafeUseOfAllocation(Instruction *User, AllocaInst *AI,
|
||||||
uint64_t ArrayOffset, AllocaInfo &Info);
|
AllocaInfo &Info);
|
||||||
void isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI, uint64_t &Offset,
|
void isSafeElementUse(Value *Ptr, bool isFirstElt, AllocaInst *AI,
|
||||||
uint64_t &ArrayOffset, AllocaInfo &Info);
|
AllocaInfo &Info);
|
||||||
void isSafeMemAccess(AllocaInst *AI, uint64_t Offset, uint64_t ArrayOffset,
|
void isSafeMemIntrinsicOnAllocation(MemIntrinsic *MI, AllocaInst *AI,
|
||||||
uint64_t MemSize, const Type *MemOpType, bool isStore,
|
unsigned OpNo, AllocaInfo &Info);
|
||||||
|
void isSafeUseOfBitCastedAllocation(BitCastInst *User, AllocaInst *AI,
|
||||||
AllocaInfo &Info);
|
AllocaInfo &Info);
|
||||||
bool TypeHasComponent(const Type *T, uint64_t Offset, uint64_t Size);
|
|
||||||
unsigned FindElementAndOffset(const Type *&T, uint64_t &Offset);
|
|
||||||
|
|
||||||
void DoScalarReplacement(AllocaInst *AI,
|
void DoScalarReplacement(AllocaInst *AI,
|
||||||
std::vector<AllocaInst*> &WorkList);
|
std::vector<AllocaInst*> &WorkList);
|
||||||
void DeleteDeadInstructions();
|
|
||||||
void CleanupGEP(GetElementPtrInst *GEP);
|
void CleanupGEP(GetElementPtrInst *GEP);
|
||||||
void CleanupAllocaUsers(Value *V);
|
void CleanupAllocaUsers(AllocaInst *AI);
|
||||||
AllocaInst *AddNewAlloca(Function &F, const Type *Ty, AllocaInst *Base);
|
AllocaInst *AddNewAlloca(Function &F, const Type *Ty, AllocaInst *Base);
|
||||||
|
|
||||||
void RewriteForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
void RewriteBitCastUserOfAlloca(Instruction *BCInst, AllocaInst *AI,
|
||||||
SmallVector<AllocaInst*, 32> &NewElts);
|
SmallVector<AllocaInst*, 32> &NewElts);
|
||||||
void RewriteBitCast(BitCastInst *BC, AllocaInst *AI, uint64_t Offset,
|
|
||||||
SmallVector<AllocaInst*, 32> &NewElts);
|
void RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *BCInst,
|
||||||
void RewriteGEP(GetElementPtrInst *GEPI, AllocaInst *AI, uint64_t Offset,
|
|
||||||
SmallVector<AllocaInst*, 32> &NewElts);
|
|
||||||
void RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *Inst,
|
|
||||||
AllocaInst *AI,
|
AllocaInst *AI,
|
||||||
SmallVector<AllocaInst*, 32> &NewElts);
|
SmallVector<AllocaInst*, 32> &NewElts);
|
||||||
void RewriteStoreUserOfWholeAlloca(StoreInst *SI, AllocaInst *AI,
|
void RewriteStoreUserOfWholeAlloca(StoreInst *SI, AllocaInst *AI,
|
||||||
@@ -369,35 +360,174 @@ void SROA::DoScalarReplacement(AllocaInst *AI,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have created the new alloca instructions, rewrite all the
|
// Now that we have created the alloca instructions that we want to use,
|
||||||
// uses of the old alloca.
|
// expand the getelementptr instructions to use them.
|
||||||
DeadInsts.push_back(AI);
|
while (!AI->use_empty()) {
|
||||||
RewriteForScalarRepl(AI, AI, 0, ElementAllocas);
|
Instruction *User = cast<Instruction>(AI->use_back());
|
||||||
|
if (BitCastInst *BCInst = dyn_cast<BitCastInst>(User)) {
|
||||||
|
RewriteBitCastUserOfAlloca(BCInst, AI, ElementAllocas);
|
||||||
|
BCInst->eraseFromParent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Now erase any instructions that were made dead while rewriting the alloca.
|
// Replace:
|
||||||
DeleteDeadInstructions();
|
// %res = load { i32, i32 }* %alloc
|
||||||
|
// with:
|
||||||
|
// %load.0 = load i32* %alloc.0
|
||||||
|
// %insert.0 insertvalue { i32, i32 } zeroinitializer, i32 %load.0, 0
|
||||||
|
// %load.1 = load i32* %alloc.1
|
||||||
|
// %insert = insertvalue { i32, i32 } %insert.0, i32 %load.1, 1
|
||||||
|
// (Also works for arrays instead of structs)
|
||||||
|
if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
|
||||||
|
Value *Insert = UndefValue::get(LI->getType());
|
||||||
|
for (unsigned i = 0, e = ElementAllocas.size(); i != e; ++i) {
|
||||||
|
Value *Load = new LoadInst(ElementAllocas[i], "load", LI);
|
||||||
|
Insert = InsertValueInst::Create(Insert, Load, i, "insert", LI);
|
||||||
|
}
|
||||||
|
LI->replaceAllUsesWith(Insert);
|
||||||
|
LI->eraseFromParent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace:
|
||||||
|
// store { i32, i32 } %val, { i32, i32 }* %alloc
|
||||||
|
// with:
|
||||||
|
// %val.0 = extractvalue { i32, i32 } %val, 0
|
||||||
|
// store i32 %val.0, i32* %alloc.0
|
||||||
|
// %val.1 = extractvalue { i32, i32 } %val, 1
|
||||||
|
// store i32 %val.1, i32* %alloc.1
|
||||||
|
// (Also works for arrays instead of structs)
|
||||||
|
if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
|
||||||
|
Value *Val = SI->getOperand(0);
|
||||||
|
for (unsigned i = 0, e = ElementAllocas.size(); i != e; ++i) {
|
||||||
|
Value *Extract = ExtractValueInst::Create(Val, i, Val->getName(), SI);
|
||||||
|
new StoreInst(Extract, ElementAllocas[i], SI);
|
||||||
|
}
|
||||||
|
SI->eraseFromParent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetElementPtrInst *GEPI = cast<GetElementPtrInst>(User);
|
||||||
|
// We now know that the GEP is of the form: GEP <ptr>, 0, <cst>
|
||||||
|
unsigned Idx =
|
||||||
|
(unsigned)cast<ConstantInt>(GEPI->getOperand(2))->getZExtValue();
|
||||||
|
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
SmallVector<Value*, 8> NewArgs;
|
||||||
|
NewArgs.push_back(Constant::getNullValue(
|
||||||
|
Type::getInt32Ty(AI->getContext())));
|
||||||
|
NewArgs.append(GEPI->op_begin()+3, GEPI->op_end());
|
||||||
|
RepValue = GetElementPtrInst::Create(AllocaToUse, NewArgs.begin(),
|
||||||
|
NewArgs.end(), "", GEPI);
|
||||||
|
RepValue->takeName(GEPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this GEP is to the start of the aggregate, check for memcpys.
|
||||||
|
if (Idx == 0 && GEPI->hasAllZeroIndices())
|
||||||
|
RewriteBitCastUserOfAlloca(GEPI, AI, ElementAllocas);
|
||||||
|
|
||||||
|
// Move all of the users over to the new GEP.
|
||||||
|
GEPI->replaceAllUsesWith(RepValue);
|
||||||
|
// Delete the old GEP
|
||||||
|
GEPI->eraseFromParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, delete the Alloca instruction
|
||||||
|
AI->eraseFromParent();
|
||||||
NumReplaced++;
|
NumReplaced++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DeleteDeadInstructions - Erase instructions on the DeadInstrs list,
|
/// isSafeElementUse - Check to see if this use is an allowed use for a
|
||||||
/// recursively including all their operands that become trivially dead.
|
/// getelementptr instruction of an array aggregate allocation. isFirstElt
|
||||||
void SROA::DeleteDeadInstructions() {
|
/// indicates whether Ptr is known to the start of the aggregate.
|
||||||
while (!DeadInsts.empty()) {
|
void SROA::isSafeElementUse(Value *Ptr, bool isFirstElt, AllocaInst *AI,
|
||||||
Instruction *I = dyn_cast_or_null<Instruction>(DeadInsts.pop_back_val());
|
AllocaInfo &Info) {
|
||||||
if (I == 0)
|
for (Value::use_iterator I = Ptr->use_begin(), E = Ptr->use_end();
|
||||||
|
I != E; ++I) {
|
||||||
|
Instruction *User = cast<Instruction>(*I);
|
||||||
|
switch (User->getOpcode()) {
|
||||||
|
case Instruction::Load: break;
|
||||||
|
case Instruction::Store:
|
||||||
|
// Store is ok if storing INTO the pointer, not storing the pointer
|
||||||
|
if (User->getOperand(0) == Ptr) return MarkUnsafe(Info);
|
||||||
|
break;
|
||||||
|
case Instruction::GetElementPtr: {
|
||||||
|
GetElementPtrInst *GEP = cast<GetElementPtrInst>(User);
|
||||||
|
bool AreAllZeroIndices = isFirstElt;
|
||||||
|
if (GEP->getNumOperands() > 1 &&
|
||||||
|
(!isa<ConstantInt>(GEP->getOperand(1)) ||
|
||||||
|
!cast<ConstantInt>(GEP->getOperand(1))->isZero()))
|
||||||
|
// Using pointer arithmetic to navigate the array.
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
|
||||||
|
// Verify that any array subscripts are in range.
|
||||||
|
for (gep_type_iterator GEPIt = gep_type_begin(GEP),
|
||||||
|
E = gep_type_end(GEP); GEPIt != E; ++GEPIt) {
|
||||||
|
// Ignore struct elements, no extra checking needed for these.
|
||||||
|
if (isa<StructType>(*GEPIt))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (User::op_iterator OI = I->op_begin(), E = I->op_end(); OI != E; ++OI)
|
// This GEP indexes an array. Verify that this is an in-range
|
||||||
if (Instruction *U = dyn_cast<Instruction>(*OI)) {
|
// constant integer. Specifically, consider A[0][i]. We cannot know that
|
||||||
// Zero out the operand and see if it becomes trivially dead.
|
// the user isn't doing invalid things like allowing i to index an
|
||||||
*OI = 0;
|
// out-of-range subscript that accesses A[1]. Because of this, we have
|
||||||
if (isInstructionTriviallyDead(U))
|
// to reject SROA of any accesses into structs where any of the
|
||||||
DeadInsts.push_back(U);
|
// components are variables.
|
||||||
|
ConstantInt *IdxVal = dyn_cast<ConstantInt>(GEPIt.getOperand());
|
||||||
|
if (!IdxVal) return MarkUnsafe(Info);
|
||||||
|
|
||||||
|
// Are all indices still zero?
|
||||||
|
AreAllZeroIndices &= IdxVal->isZero();
|
||||||
|
|
||||||
|
if (const ArrayType *AT = dyn_cast<ArrayType>(*GEPIt)) {
|
||||||
|
if (IdxVal->getZExtValue() >= AT->getNumElements())
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
} else if (const VectorType *VT = dyn_cast<VectorType>(*GEPIt)) {
|
||||||
|
if (IdxVal->getZExtValue() >= VT->getNumElements())
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I->eraseFromParent();
|
isSafeElementUse(GEP, AreAllZeroIndices, AI, Info);
|
||||||
|
if (Info.isUnsafe) return;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case Instruction::BitCast:
|
||||||
|
if (isFirstElt) {
|
||||||
|
isSafeUseOfBitCastedAllocation(cast<BitCastInst>(User), AI, Info);
|
||||||
|
if (Info.isUnsafe) return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DEBUG(errs() << " Transformation preventing inst: " << *User << '\n');
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
case Instruction::Call:
|
||||||
|
if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(User)) {
|
||||||
|
if (isFirstElt) {
|
||||||
|
isSafeMemIntrinsicOnAllocation(MI, AI, I.getOperandNo(), Info);
|
||||||
|
if (Info.isUnsafe) return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG(errs() << " Transformation preventing inst: " << *User << '\n');
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
default:
|
||||||
|
DEBUG(errs() << " Transformation preventing inst: " << *User << '\n');
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return; // All users look ok :)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AllUsersAreLoads - Return true if all users of this value are loads.
|
/// AllUsersAreLoads - Return true if all users of this value are loads.
|
||||||
@@ -409,116 +539,72 @@ static bool AllUsersAreLoads(Value *Ptr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isSafeForScalarRepl - Check if instruction I is a safe use with regard to
|
/// isSafeUseOfAllocation - Check if this user is an allowed use for an
|
||||||
/// performing scalar replacement of alloca AI. The results are flagged in
|
/// aggregate allocation.
|
||||||
/// the Info parameter. Offset and ArrayOffset indicate the position within
|
void SROA::isSafeUseOfAllocation(Instruction *User, AllocaInst *AI,
|
||||||
/// AI that is referenced by this instruction.
|
|
||||||
void SROA::isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
|
||||||
uint64_t ArrayOffset, 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);
|
|
||||||
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(User)) {
|
|
||||||
uint64_t GEPArrayOffset = ArrayOffset;
|
|
||||||
uint64_t GEPOffset = Offset;
|
|
||||||
isSafeGEP(GEPI, AI, GEPOffset, GEPArrayOffset, Info);
|
|
||||||
if (!Info.isUnsafe)
|
|
||||||
isSafeForScalarRepl(GEPI, AI, GEPOffset, GEPArrayOffset, 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,
|
|
||||||
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),
|
|
||||||
LIType, false, Info);
|
|
||||||
} else
|
|
||||||
MarkUnsafe(Info);
|
|
||||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
|
|
||||||
// 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),
|
|
||||||
SIType, true, Info);
|
|
||||||
} else
|
|
||||||
MarkUnsafe(Info);
|
|
||||||
} else if (isa<DbgInfoIntrinsic>(UI)) {
|
|
||||||
// If one user is DbgInfoIntrinsic then check if all users are
|
|
||||||
// DbgInfoIntrinsics.
|
|
||||||
if (OnlyUsedByDbgInfoIntrinsics(I)) {
|
|
||||||
Info.needsCleanup = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MarkUnsafe(Info);
|
|
||||||
} else {
|
|
||||||
DEBUG(errs() << " Transformation preventing inst: " << *User << '\n');
|
|
||||||
MarkUnsafe(Info);
|
|
||||||
}
|
|
||||||
if (Info.isUnsafe) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isSafeGEP - Check if a GEP instruction can be handled for scalar
|
|
||||||
/// 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.
|
|
||||||
void SROA::isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI,
|
|
||||||
uint64_t &Offset, uint64_t &ArrayOffset,
|
|
||||||
AllocaInfo &Info) {
|
AllocaInfo &Info) {
|
||||||
gep_type_iterator GEPIt = gep_type_begin(GEPI), E = gep_type_end(GEPI);
|
if (BitCastInst *C = dyn_cast<BitCastInst>(User))
|
||||||
if (GEPIt == E)
|
return isSafeUseOfBitCastedAllocation(C, AI, Info);
|
||||||
return;
|
|
||||||
|
|
||||||
// The first GEP index must be zero.
|
if (LoadInst *LI = dyn_cast<LoadInst>(User))
|
||||||
if (!isa<ConstantInt>(GEPIt.getOperand()) ||
|
if (!LI->isVolatile())
|
||||||
!cast<ConstantInt>(GEPIt.getOperand())->isZero())
|
return;// Loads (returning a first class aggregrate) are always rewritable
|
||||||
|
|
||||||
|
if (StoreInst *SI = dyn_cast<StoreInst>(User))
|
||||||
|
if (!SI->isVolatile() && SI->getOperand(0) != AI)
|
||||||
|
return;// Store is ok if storing INTO the pointer, not storing the pointer
|
||||||
|
|
||||||
|
GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(User);
|
||||||
|
if (GEPI == 0)
|
||||||
return MarkUnsafe(Info);
|
return MarkUnsafe(Info);
|
||||||
if (++GEPIt == E)
|
|
||||||
return;
|
gep_type_iterator I = gep_type_begin(GEPI), E = gep_type_end(GEPI);
|
||||||
|
|
||||||
|
// The GEP is not safe to transform if not of the form "GEP <ptr>, 0, <cst>".
|
||||||
|
if (I == E ||
|
||||||
|
I.getOperand() != Constant::getNullValue(I.getOperand()->getType())) {
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
++I;
|
||||||
|
if (I == E) return MarkUnsafe(Info); // ran out of GEP indices??
|
||||||
|
|
||||||
|
bool IsAllZeroIndices = true;
|
||||||
|
|
||||||
// If the first index is a non-constant index into an array, see if we can
|
// If the first index is a non-constant index into an array, see if we can
|
||||||
// handle it as a special case.
|
// handle it as a special case.
|
||||||
const Type *ArrayEltTy = 0;
|
if (const ArrayType *AT = dyn_cast<ArrayType>(*I)) {
|
||||||
if (ArrayOffset == 0 && Offset == 0) {
|
if (!isa<ConstantInt>(I.getOperand())) {
|
||||||
if (const ArrayType *AT = dyn_cast<ArrayType>(*GEPIt)) {
|
IsAllZeroIndices = 0;
|
||||||
if (!isa<ConstantInt>(GEPIt.getOperand())) {
|
|
||||||
uint64_t NumElements = AT->getNumElements();
|
uint64_t NumElements = AT->getNumElements();
|
||||||
|
|
||||||
// If this is an array index and the index is not constant, we cannot
|
// 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
|
// promote... that is unless the array has exactly one or two elements in
|
||||||
// in it, in which case we CAN promote it, but we have to canonicalize
|
// it, in which case we CAN promote it, but we have to canonicalize this
|
||||||
// this out if this is the only problem.
|
// out if this is the only problem.
|
||||||
if ((NumElements != 1 && NumElements != 2) || !AllUsersAreLoads(GEPI))
|
if ((NumElements == 1 || NumElements == 2) &&
|
||||||
return MarkUnsafe(Info);
|
AllUsersAreLoads(GEPI)) {
|
||||||
Info.needsCleanup = true;
|
Info.needsCleanup = true;
|
||||||
ArrayOffset = TD->getTypeAllocSizeInBits(AT->getElementType());
|
return; // Canonicalization required!
|
||||||
ArrayEltTy = AT->getElementType();
|
|
||||||
++GEPIt;
|
|
||||||
}
|
}
|
||||||
|
return MarkUnsafe(Info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk through the GEP type indices, checking the types that this indexes
|
// Walk through the GEP type indices, checking the types that this indexes
|
||||||
// into.
|
// into.
|
||||||
for (; GEPIt != E; ++GEPIt) {
|
for (; I != E; ++I) {
|
||||||
// Ignore struct elements, no extra checking needed for these.
|
// Ignore struct elements, no extra checking needed for these.
|
||||||
if (isa<StructType>(*GEPIt))
|
if (isa<StructType>(*I))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ConstantInt *IdxVal = dyn_cast<ConstantInt>(GEPIt.getOperand());
|
ConstantInt *IdxVal = dyn_cast<ConstantInt>(I.getOperand());
|
||||||
if (!IdxVal)
|
if (!IdxVal) return MarkUnsafe(Info);
|
||||||
return MarkUnsafe(Info);
|
|
||||||
|
|
||||||
if (const ArrayType *AT = dyn_cast<ArrayType>(*GEPIt)) {
|
// Are all indices still zero?
|
||||||
|
IsAllZeroIndices &= IdxVal->isZero();
|
||||||
|
|
||||||
|
if (const ArrayType *AT = dyn_cast<ArrayType>(*I)) {
|
||||||
// This GEP indexes an array. Verify that this is an in-range constant
|
// This GEP indexes an array. Verify that this is an in-range constant
|
||||||
// integer. Specifically, consider A[0][i]. We cannot know that the user
|
// integer. Specifically, consider A[0][i]. We cannot know that the user
|
||||||
// isn't doing invalid things like allowing i to index an out-of-range
|
// isn't doing invalid things like allowing i to index an out-of-range
|
||||||
@@ -526,255 +612,147 @@ void SROA::isSafeGEP(GetElementPtrInst *GEPI, AllocaInst *AI,
|
|||||||
// of any accesses into structs where any of the components are variables.
|
// of any accesses into structs where any of the components are variables.
|
||||||
if (IdxVal->getZExtValue() >= AT->getNumElements())
|
if (IdxVal->getZExtValue() >= AT->getNumElements())
|
||||||
return MarkUnsafe(Info);
|
return MarkUnsafe(Info);
|
||||||
} else {
|
} else if (const VectorType *VT = dyn_cast<VectorType>(*I)) {
|
||||||
const VectorType *VT = dyn_cast<VectorType>(*GEPIt);
|
|
||||||
assert(VT && "unexpected type in GEP type iterator");
|
|
||||||
if (IdxVal->getZExtValue() >= VT->getNumElements())
|
if (IdxVal->getZExtValue() >= VT->getNumElements())
|
||||||
return MarkUnsafe(Info);
|
return MarkUnsafe(Info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the indices are safe. Now compute the offset due to this GEP and
|
// If there are any non-simple uses of this getelementptr, make sure to reject
|
||||||
// check if the alloca has a component element at that offset.
|
// them.
|
||||||
if (ArrayOffset == 0) {
|
return isSafeElementUse(GEPI, IsAllZeroIndices, AI, Info);
|
||||||
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());
|
|
||||||
}
|
|
||||||
if (!TypeHasComponent(AI->getAllocatedType(), Offset, 0))
|
|
||||||
MarkUnsafe(Info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isSafeMemAccess - Check if a load/store/memcpy operates on the entire AI
|
/// isSafeMemIntrinsicOnAllocation - Check if the specified memory
|
||||||
/// alloca or has an offset and size that corresponds to a component element
|
/// intrinsic can be promoted by SROA. At this point, we know that the operand
|
||||||
/// within it. The offset checked here may have been formed from a GEP with a
|
/// of the memintrinsic is a pointer to the beginning of the allocation.
|
||||||
/// pointer bitcasted to a different type.
|
void SROA::isSafeMemIntrinsicOnAllocation(MemIntrinsic *MI, AllocaInst *AI,
|
||||||
void SROA::isSafeMemAccess(AllocaInst *AI, uint64_t Offset,
|
unsigned OpNo, AllocaInfo &Info) {
|
||||||
uint64_t ArrayOffset, uint64_t MemSize,
|
// If not constant length, give up.
|
||||||
const Type *MemOpType, bool isStore,
|
ConstantInt *Length = dyn_cast<ConstantInt>(MI->getLength());
|
||||||
AllocaInfo &Info) {
|
if (!Length) return MarkUnsafe(Info);
|
||||||
// Check if this is a load/store of the entire alloca.
|
|
||||||
if (Offset == 0 && ArrayOffset == 0 &&
|
// If not the whole aggregate, give up.
|
||||||
MemSize == TD->getTypeAllocSize(AI->getAllocatedType())) {
|
if (Length->getZExtValue() !=
|
||||||
bool UsesAggregateType = (MemOpType == AI->getAllocatedType());
|
TD->getTypeAllocSize(AI->getType()->getElementType()))
|
||||||
// This is safe for MemIntrinsics (where MemOpType is 0), integer types
|
return MarkUnsafe(Info);
|
||||||
// (which are essentially the same as the MemIntrinsics, especially with
|
|
||||||
// regard to copying padding between elements), or references using the
|
// We only know about memcpy/memset/memmove.
|
||||||
// aggregate type of the alloca.
|
if (!isa<MemIntrinsic>(MI))
|
||||||
if (!MemOpType || isa<IntegerType>(MemOpType) || UsesAggregateType) {
|
return MarkUnsafe(Info);
|
||||||
if (!UsesAggregateType) {
|
|
||||||
if (isStore)
|
// Otherwise, we can transform it. Determine whether this is a memcpy/set
|
||||||
|
// into or out of the aggregate.
|
||||||
|
if (OpNo == 1)
|
||||||
Info.isMemCpyDst = true;
|
Info.isMemCpyDst = true;
|
||||||
else
|
else {
|
||||||
|
assert(OpNo == 2);
|
||||||
Info.isMemCpySrc = true;
|
Info.isMemCpySrc = true;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 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)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
/// isSafeUseOfBitCastedAllocation - Check if all users of this bitcast
|
||||||
|
/// from an alloca are safe for SROA of that alloca.
|
||||||
|
void SROA::isSafeUseOfBitCastedAllocation(BitCastInst *BC, AllocaInst *AI,
|
||||||
|
AllocaInfo &Info) {
|
||||||
|
for (Value::use_iterator UI = BC->use_begin(), E = BC->use_end();
|
||||||
|
UI != E; ++UI) {
|
||||||
|
if (BitCastInst *BCU = dyn_cast<BitCastInst>(UI)) {
|
||||||
|
isSafeUseOfBitCastedAllocation(BCU, AI, Info);
|
||||||
|
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(UI)) {
|
||||||
|
isSafeMemIntrinsicOnAllocation(MI, AI, UI.getOperandNo(), Info);
|
||||||
|
} else if (StoreInst *SI = dyn_cast<StoreInst>(UI)) {
|
||||||
|
if (SI->isVolatile())
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
|
||||||
|
// If storing the entire alloca in one chunk through a bitcasted pointer
|
||||||
|
// to integer, we can transform it. This happens (for example) when you
|
||||||
|
// cast a {i32,i32}* to i64* and store through it. This is similar to the
|
||||||
|
// memcpy case and occurs in various "byval" cases and emulated memcpys.
|
||||||
|
if (isa<IntegerType>(SI->getOperand(0)->getType()) &&
|
||||||
|
TD->getTypeAllocSize(SI->getOperand(0)->getType()) ==
|
||||||
|
TD->getTypeAllocSize(AI->getType()->getElementType())) {
|
||||||
|
Info.isMemCpyDst = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
} else if (LoadInst *LI = dyn_cast<LoadInst>(UI)) {
|
||||||
|
if (LI->isVolatile())
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
|
||||||
|
// If loading the entire alloca in one chunk through a bitcasted pointer
|
||||||
|
// to integer, we can transform it. This happens (for example) when you
|
||||||
|
// cast a {i32,i32}* to i64* and load through it. This is similar to the
|
||||||
|
// memcpy case and occurs in various "byval" cases and emulated memcpys.
|
||||||
|
if (isa<IntegerType>(LI->getType()) &&
|
||||||
|
TD->getTypeAllocSize(LI->getType()) ==
|
||||||
|
TD->getTypeAllocSize(AI->getType()->getElementType())) {
|
||||||
|
Info.isMemCpySrc = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return MarkUnsafe(Info);
|
||||||
|
} else if (isa<DbgInfoIntrinsic>(UI)) {
|
||||||
|
// If one user is DbgInfoIntrinsic then check if all users are
|
||||||
|
// DbgInfoIntrinsics.
|
||||||
|
if (OnlyUsedByDbgInfoIntrinsics(BC)) {
|
||||||
|
Info.needsCleanup = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
MarkUnsafe(Info);
|
||||||
|
}
|
||||||
|
else {
|
||||||
return MarkUnsafe(Info);
|
return MarkUnsafe(Info);
|
||||||
}
|
}
|
||||||
|
if (Info.isUnsafe) return;
|
||||||
/// TypeHasComponent - Return true if T has a component type with the
|
|
||||||
/// specified offset and size. If Size is zero, do not check the size.
|
|
||||||
bool SROA::TypeHasComponent(const Type *T, uint64_t Offset, uint64_t Size) {
|
|
||||||
const Type *EltTy;
|
|
||||||
uint64_t EltSize;
|
|
||||||
if (const StructType *ST = dyn_cast<StructType>(T)) {
|
|
||||||
const StructLayout *Layout = TD->getStructLayout(ST);
|
|
||||||
unsigned EltIdx = Layout->getElementContainingOffset(Offset);
|
|
||||||
EltTy = ST->getContainedType(EltIdx);
|
|
||||||
EltSize = TD->getTypeAllocSize(EltTy);
|
|
||||||
Offset -= Layout->getElementOffset(EltIdx);
|
|
||||||
} else if (const ArrayType *AT = dyn_cast<ArrayType>(T)) {
|
|
||||||
EltTy = AT->getElementType();
|
|
||||||
EltSize = TD->getTypeAllocSize(EltTy);
|
|
||||||
Offset %= EltSize;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (Offset == 0 && (Size == 0 || EltSize == Size))
|
|
||||||
return true;
|
|
||||||
// Check if the component spans multiple elements.
|
|
||||||
if (Offset + Size > EltSize)
|
|
||||||
return false;
|
|
||||||
return TypeHasComponent(EltTy, Offset, Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RewriteForScalarRepl - Alloca AI is being split into NewElts, so rewrite
|
/// RewriteBitCastUserOfAlloca - BCInst (transitively) bitcasts AI, or indexes
|
||||||
/// the instruction I, which references it, to use the separate elements.
|
/// to its first element. Transform users of the cast to use the new values
|
||||||
/// Offset indicates the position within AI that is referenced by this
|
/// instead.
|
||||||
/// instruction.
|
void SROA::RewriteBitCastUserOfAlloca(Instruction *BCInst, AllocaInst *AI,
|
||||||
void SROA::RewriteForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset,
|
|
||||||
SmallVector<AllocaInst*, 32> &NewElts) {
|
SmallVector<AllocaInst*, 32> &NewElts) {
|
||||||
for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI!=E; ++UI) {
|
Value::use_iterator UI = BCInst->use_begin(), UE = BCInst->use_end();
|
||||||
Instruction *User = cast<Instruction>(*UI);
|
while (UI != UE) {
|
||||||
|
Instruction *User = cast<Instruction>(*UI++);
|
||||||
|
if (BitCastInst *BCU = dyn_cast<BitCastInst>(User)) {
|
||||||
|
RewriteBitCastUserOfAlloca(BCU, AI, NewElts);
|
||||||
|
if (BCU->use_empty()) BCU->eraseFromParent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (BitCastInst *BC = dyn_cast<BitCastInst>(User)) {
|
if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(User)) {
|
||||||
RewriteBitCast(BC, AI, Offset, NewElts);
|
// This must be memcpy/memmove/memset of the entire aggregate.
|
||||||
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(User)) {
|
// Split into one per element.
|
||||||
RewriteGEP(GEPI, AI, Offset, NewElts);
|
RewriteMemIntrinUserOfAlloca(MI, BCInst, AI, NewElts);
|
||||||
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(User)) {
|
continue;
|
||||||
ConstantInt *Length = dyn_cast<ConstantInt>(MI->getLength());
|
|
||||||
uint64_t MemSize = Length->getZExtValue();
|
|
||||||
if (Offset == 0 &&
|
|
||||||
MemSize == TD->getTypeAllocSize(AI->getAllocatedType()))
|
|
||||||
RewriteMemIntrinUserOfAlloca(MI, I, AI, NewElts);
|
|
||||||
} else if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
|
|
||||||
const Type *LIType = LI->getType();
|
|
||||||
if (LIType == AI->getAllocatedType()) {
|
|
||||||
// Replace:
|
|
||||||
// %res = load { i32, i32 }* %alloc
|
|
||||||
// with:
|
|
||||||
// %load.0 = load i32* %alloc.0
|
|
||||||
// %insert.0 insertvalue { i32, i32 } zeroinitializer, i32 %load.0, 0
|
|
||||||
// %load.1 = load i32* %alloc.1
|
|
||||||
// %insert = insertvalue { i32, i32 } %insert.0, i32 %load.1, 1
|
|
||||||
// (Also works for arrays instead of structs)
|
|
||||||
Value *Insert = UndefValue::get(LIType);
|
|
||||||
for (unsigned i = 0, e = NewElts.size(); i != e; ++i) {
|
|
||||||
Value *Load = new LoadInst(NewElts[i], "load", LI);
|
|
||||||
Insert = InsertValueInst::Create(Insert, Load, i, "insert", LI);
|
|
||||||
}
|
}
|
||||||
LI->replaceAllUsesWith(Insert);
|
|
||||||
DeadInsts.push_back(LI);
|
if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
|
||||||
} else if (isa<IntegerType>(LIType) &&
|
|
||||||
TD->getTypeAllocSize(LIType) ==
|
|
||||||
TD->getTypeAllocSize(AI->getAllocatedType())) {
|
|
||||||
// If this is a load of the entire alloca to an integer, rewrite it.
|
|
||||||
RewriteLoadUserOfWholeAlloca(LI, AI, NewElts);
|
|
||||||
}
|
|
||||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
|
|
||||||
Value *Val = SI->getOperand(0);
|
|
||||||
const Type *SIType = Val->getType();
|
|
||||||
if (SIType == AI->getAllocatedType()) {
|
|
||||||
// Replace:
|
|
||||||
// store { i32, i32 } %val, { i32, i32 }* %alloc
|
|
||||||
// with:
|
|
||||||
// %val.0 = extractvalue { i32, i32 } %val, 0
|
|
||||||
// store i32 %val.0, i32* %alloc.0
|
|
||||||
// %val.1 = extractvalue { i32, i32 } %val, 1
|
|
||||||
// store i32 %val.1, i32* %alloc.1
|
|
||||||
// (Also works for arrays instead of structs)
|
|
||||||
for (unsigned i = 0, e = NewElts.size(); i != e; ++i) {
|
|
||||||
Value *Extract = ExtractValueInst::Create(Val, i, Val->getName(), SI);
|
|
||||||
new StoreInst(Extract, NewElts[i], SI);
|
|
||||||
}
|
|
||||||
DeadInsts.push_back(SI);
|
|
||||||
} else if (isa<IntegerType>(SIType) &&
|
|
||||||
TD->getTypeAllocSize(SIType) ==
|
|
||||||
TD->getTypeAllocSize(AI->getAllocatedType())) {
|
|
||||||
// If this is a store of the entire alloca from an integer, rewrite it.
|
// If this is a store of the entire alloca from an integer, rewrite it.
|
||||||
RewriteStoreUserOfWholeAlloca(SI, AI, NewElts);
|
RewriteStoreUserOfWholeAlloca(SI, AI, NewElts);
|
||||||
}
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RewriteBitCast - Update a bitcast reference to the alloca being replaced
|
if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
|
||||||
/// and recursively continue updating all of its uses.
|
// If this is a load of the entire alloca to an integer, rewrite it.
|
||||||
void SROA::RewriteBitCast(BitCastInst *BC, AllocaInst *AI, uint64_t Offset,
|
RewriteLoadUserOfWholeAlloca(LI, AI, NewElts);
|
||||||
SmallVector<AllocaInst*, 32> &NewElts) {
|
continue;
|
||||||
RewriteForScalarRepl(BC, AI, Offset, NewElts);
|
|
||||||
if (BC->getOperand(0) != AI)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The bitcast references the original alloca. Replace its uses with
|
|
||||||
// references to the first new element alloca.
|
|
||||||
Instruction *Val = NewElts[0];
|
|
||||||
if (Val->getType() != BC->getDestTy()) {
|
|
||||||
Val = new BitCastInst(Val, BC->getDestTy(), "", BC);
|
|
||||||
Val->takeName(BC);
|
|
||||||
}
|
|
||||||
BC->replaceAllUsesWith(Val);
|
|
||||||
DeadInsts.push_back(BC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FindElementAndOffset - Return the index of the element containing Offset
|
// Otherwise it must be some other user of a gep of the first pointer. Just
|
||||||
/// within the specified type, which must be either a struct or an array.
|
// leave these alone.
|
||||||
/// Sets T to the type of the element and Offset to the offset within that
|
continue;
|
||||||
/// element.
|
|
||||||
unsigned SROA::FindElementAndOffset(const Type *&T, uint64_t &Offset) {
|
|
||||||
unsigned Idx = 0;
|
|
||||||
if (const StructType *ST = dyn_cast<StructType>(T)) {
|
|
||||||
const StructLayout *Layout = TD->getStructLayout(ST);
|
|
||||||
Idx = Layout->getElementContainingOffset(Offset);
|
|
||||||
T = ST->getContainedType(Idx);
|
|
||||||
Offset -= Layout->getElementOffset(Idx);
|
|
||||||
} else {
|
|
||||||
const ArrayType *AT = dyn_cast<ArrayType>(T);
|
|
||||||
assert(AT && "unexpected type for scalar replacement");
|
|
||||||
T = AT->getElementType();
|
|
||||||
uint64_t EltSize = TD->getTypeAllocSize(T);
|
|
||||||
Idx = (unsigned)(Offset / EltSize);
|
|
||||||
Offset -= Idx * EltSize;
|
|
||||||
}
|
}
|
||||||
return Idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// RewriteGEP - Check if this GEP instruction moves the pointer across
|
|
||||||
/// elements of the alloca that are being split apart, and if so, rewrite
|
|
||||||
/// the GEP to be relative to the new element.
|
|
||||||
void SROA::RewriteGEP(GetElementPtrInst *GEPI, AllocaInst *AI, uint64_t Offset,
|
|
||||||
SmallVector<AllocaInst*, 32> &NewElts) {
|
|
||||||
uint64_t OldOffset = Offset;
|
|
||||||
SmallVector<Value*, 8> Indices(GEPI->op_begin() + 1, GEPI->op_end());
|
|
||||||
Offset += TD->getIndexedOffset(GEPI->getPointerOperandType(),
|
|
||||||
&Indices[0], Indices.size());
|
|
||||||
|
|
||||||
RewriteForScalarRepl(GEPI, AI, Offset, NewElts);
|
|
||||||
|
|
||||||
const Type *T = AI->getAllocatedType();
|
|
||||||
unsigned OldIdx = FindElementAndOffset(T, OldOffset);
|
|
||||||
if (GEPI->getOperand(0) == AI)
|
|
||||||
OldIdx = ~0U; // Force the GEP to be rewritten.
|
|
||||||
|
|
||||||
T = AI->getAllocatedType();
|
|
||||||
uint64_t EltOffset = Offset;
|
|
||||||
unsigned Idx = FindElementAndOffset(T, EltOffset);
|
|
||||||
|
|
||||||
// If this GEP does not move the pointer across elements of the alloca
|
|
||||||
// being split, then it does not needs to be rewritten.
|
|
||||||
if (Idx == OldIdx)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const Type *i32Ty = Type::getInt32Ty(AI->getContext());
|
|
||||||
SmallVector<Value*, 8> NewArgs;
|
|
||||||
NewArgs.push_back(Constant::getNullValue(i32Ty));
|
|
||||||
while (EltOffset != 0) {
|
|
||||||
unsigned EltIdx = FindElementAndOffset(T, EltOffset);
|
|
||||||
NewArgs.push_back(ConstantInt::get(i32Ty, EltIdx));
|
|
||||||
}
|
|
||||||
Instruction *Val = NewElts[Idx];
|
|
||||||
if (NewArgs.size() > 1) {
|
|
||||||
Val = GetElementPtrInst::CreateInBounds(Val, NewArgs.begin(),
|
|
||||||
NewArgs.end(), "", GEPI);
|
|
||||||
Val->takeName(GEPI);
|
|
||||||
}
|
|
||||||
if (Val->getType() != GEPI->getType())
|
|
||||||
Val = new BitCastInst(Val, GEPI->getType(), Val->getNameStr(), GEPI);
|
|
||||||
GEPI->replaceAllUsesWith(Val);
|
|
||||||
DeadInsts.push_back(GEPI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RewriteMemIntrinUserOfAlloca - MI is a memcpy/memset/memmove from or to AI.
|
/// RewriteMemIntrinUserOfAlloca - MI is a memcpy/memset/memmove from or to AI.
|
||||||
/// Rewrite it to copy or set the elements of the scalarized memory.
|
/// Rewrite it to copy or set the elements of the scalarized memory.
|
||||||
void SROA::RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *Inst,
|
void SROA::RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *BCInst,
|
||||||
AllocaInst *AI,
|
AllocaInst *AI,
|
||||||
SmallVector<AllocaInst*, 32> &NewElts) {
|
SmallVector<AllocaInst*, 32> &NewElts) {
|
||||||
|
|
||||||
// If this is a memcpy/memmove, construct the other pointer as the
|
// If this is a memcpy/memmove, construct the other pointer as the
|
||||||
// appropriate type. The "Other" pointer is the pointer that goes to memory
|
// appropriate type. The "Other" pointer is the pointer that goes to memory
|
||||||
// that doesn't have anything to do with the alloca that we are promoting. For
|
// that doesn't have anything to do with the alloca that we are promoting. For
|
||||||
@@ -783,41 +761,28 @@ void SROA::RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *Inst,
|
|||||||
LLVMContext &Context = MI->getContext();
|
LLVMContext &Context = MI->getContext();
|
||||||
unsigned MemAlignment = MI->getAlignment();
|
unsigned MemAlignment = MI->getAlignment();
|
||||||
if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI)) { // memmove/memcopy
|
if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI)) { // memmove/memcopy
|
||||||
if (Inst == MTI->getRawDest())
|
if (BCInst == MTI->getRawDest())
|
||||||
OtherPtr = MTI->getRawSource();
|
OtherPtr = MTI->getRawSource();
|
||||||
else {
|
else {
|
||||||
assert(Inst == MTI->getRawSource());
|
assert(BCInst == MTI->getRawSource());
|
||||||
OtherPtr = MTI->getRawDest();
|
OtherPtr = MTI->getRawDest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of the other intrinsic argument, so it can be removed if it
|
||||||
|
// is dead when the intrinsic is replaced.
|
||||||
|
Value *PossiblyDead = OtherPtr;
|
||||||
|
|
||||||
// If there is an other pointer, we want to convert it to the same pointer
|
// If there is an other pointer, we want to convert it to the same pointer
|
||||||
// type as AI has, so we can GEP through it safely.
|
// type as AI has, so we can GEP through it safely.
|
||||||
if (OtherPtr) {
|
if (OtherPtr) {
|
||||||
|
// It is likely that OtherPtr is a bitcast, if so, remove it.
|
||||||
// Remove bitcasts and all-zero GEPs from OtherPtr. This is an
|
if (BitCastInst *BC = dyn_cast<BitCastInst>(OtherPtr))
|
||||||
// optimization, but it's also required to detect the corner case where
|
|
||||||
// both pointer operands are referencing the same memory, and where
|
|
||||||
// OtherPtr may be a bitcast or GEP that currently being rewritten. (This
|
|
||||||
// function is only called for mem intrinsics that access the whole
|
|
||||||
// aggregate, so non-zero GEPs are not an issue here.)
|
|
||||||
while (1) {
|
|
||||||
if (BitCastInst *BC = dyn_cast<BitCastInst>(OtherPtr)) {
|
|
||||||
OtherPtr = BC->getOperand(0);
|
OtherPtr = BC->getOperand(0);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(OtherPtr)) {
|
|
||||||
// All zero GEPs are effectively bitcasts.
|
// All zero GEPs are effectively bitcasts.
|
||||||
if (GEP->hasAllZeroIndices()) {
|
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(OtherPtr))
|
||||||
|
if (GEP->hasAllZeroIndices())
|
||||||
OtherPtr = GEP->getOperand(0);
|
OtherPtr = GEP->getOperand(0);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// If OtherPtr has already been rewritten, this intrinsic will be dead.
|
|
||||||
if (OtherPtr == NewElts[0])
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ConstantExpr *BCE = dyn_cast<ConstantExpr>(OtherPtr))
|
if (ConstantExpr *BCE = dyn_cast<ConstantExpr>(OtherPtr))
|
||||||
if (BCE->getOpcode() == Instruction::BitCast)
|
if (BCE->getOpcode() == Instruction::BitCast)
|
||||||
@@ -833,7 +798,7 @@ void SROA::RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *Inst,
|
|||||||
// Process each element of the aggregate.
|
// Process each element of the aggregate.
|
||||||
Value *TheFn = MI->getOperand(0);
|
Value *TheFn = MI->getOperand(0);
|
||||||
const Type *BytePtrTy = MI->getRawDest()->getType();
|
const Type *BytePtrTy = MI->getRawDest()->getType();
|
||||||
bool SROADest = MI->getRawDest() == Inst;
|
bool SROADest = MI->getRawDest() == BCInst;
|
||||||
|
|
||||||
Constant *Zero = Constant::getNullValue(Type::getInt32Ty(MI->getContext()));
|
Constant *Zero = Constant::getNullValue(Type::getInt32Ty(MI->getContext()));
|
||||||
|
|
||||||
@@ -842,13 +807,10 @@ void SROA::RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *Inst,
|
|||||||
Value *OtherElt = 0;
|
Value *OtherElt = 0;
|
||||||
unsigned OtherEltAlign = MemAlignment;
|
unsigned OtherEltAlign = MemAlignment;
|
||||||
|
|
||||||
if (OtherPtr == AI) {
|
if (OtherPtr) {
|
||||||
OtherElt = NewElts[i];
|
|
||||||
OtherEltAlign = 0;
|
|
||||||
} else if (OtherPtr) {
|
|
||||||
Value *Idx[2] = { Zero,
|
Value *Idx[2] = { Zero,
|
||||||
ConstantInt::get(Type::getInt32Ty(MI->getContext()), i) };
|
ConstantInt::get(Type::getInt32Ty(MI->getContext()), i) };
|
||||||
OtherElt = GetElementPtrInst::CreateInBounds(OtherPtr, Idx, Idx + 2,
|
OtherElt = GetElementPtrInst::Create(OtherPtr, Idx, Idx + 2,
|
||||||
OtherPtr->getNameStr()+"."+Twine(i),
|
OtherPtr->getNameStr()+"."+Twine(i),
|
||||||
MI);
|
MI);
|
||||||
uint64_t EltOffset;
|
uint64_t EltOffset;
|
||||||
@@ -962,7 +924,9 @@ void SROA::RewriteMemIntrinUserOfAlloca(MemIntrinsic *MI, Instruction *Inst,
|
|||||||
CallInst::Create(TheFn, Ops, Ops + 4, "", MI);
|
CallInst::Create(TheFn, Ops, Ops + 4, "", MI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DeadInsts.push_back(MI);
|
MI->eraseFromParent();
|
||||||
|
if (PossiblyDead)
|
||||||
|
RecursivelyDeleteTriviallyDeadInstructions(PossiblyDead);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RewriteStoreUserOfWholeAlloca - We found a store of an integer that
|
/// RewriteStoreUserOfWholeAlloca - We found a store of an integer that
|
||||||
@@ -973,9 +937,15 @@ void SROA::RewriteStoreUserOfWholeAlloca(StoreInst *SI, AllocaInst *AI,
|
|||||||
// Extract each element out of the integer according to its structure offset
|
// Extract each element out of the integer according to its structure offset
|
||||||
// and store the element value to the individual alloca.
|
// and store the element value to the individual alloca.
|
||||||
Value *SrcVal = SI->getOperand(0);
|
Value *SrcVal = SI->getOperand(0);
|
||||||
const Type *AllocaEltTy = AI->getAllocatedType();
|
const Type *AllocaEltTy = AI->getType()->getElementType();
|
||||||
uint64_t AllocaSizeBits = TD->getTypeAllocSizeInBits(AllocaEltTy);
|
uint64_t AllocaSizeBits = TD->getTypeAllocSizeInBits(AllocaEltTy);
|
||||||
|
|
||||||
|
// If this isn't a store of an integer to the whole alloca, it may be a store
|
||||||
|
// to the first element. Just ignore the store in this case and normal SROA
|
||||||
|
// will handle it.
|
||||||
|
if (!isa<IntegerType>(SrcVal->getType()) ||
|
||||||
|
TD->getTypeAllocSizeInBits(SrcVal->getType()) != AllocaSizeBits)
|
||||||
|
return;
|
||||||
// Handle tail padding by extending the operand
|
// Handle tail padding by extending the operand
|
||||||
if (TD->getTypeSizeInBits(SrcVal->getType()) != AllocaSizeBits)
|
if (TD->getTypeSizeInBits(SrcVal->getType()) != AllocaSizeBits)
|
||||||
SrcVal = new ZExtInst(SrcVal,
|
SrcVal = new ZExtInst(SrcVal,
|
||||||
@@ -1080,7 +1050,7 @@ void SROA::RewriteStoreUserOfWholeAlloca(StoreInst *SI, AllocaInst *AI,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeadInsts.push_back(SI);
|
SI->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RewriteLoadUserOfWholeAlloca - We found a load of the entire allocation to
|
/// RewriteLoadUserOfWholeAlloca - We found a load of the entire allocation to
|
||||||
@@ -1089,9 +1059,16 @@ void SROA::RewriteLoadUserOfWholeAlloca(LoadInst *LI, AllocaInst *AI,
|
|||||||
SmallVector<AllocaInst*, 32> &NewElts) {
|
SmallVector<AllocaInst*, 32> &NewElts) {
|
||||||
// Extract each element out of the NewElts according to its structure offset
|
// Extract each element out of the NewElts according to its structure offset
|
||||||
// and form the result value.
|
// and form the result value.
|
||||||
const Type *AllocaEltTy = AI->getAllocatedType();
|
const Type *AllocaEltTy = AI->getType()->getElementType();
|
||||||
uint64_t AllocaSizeBits = TD->getTypeAllocSizeInBits(AllocaEltTy);
|
uint64_t AllocaSizeBits = TD->getTypeAllocSizeInBits(AllocaEltTy);
|
||||||
|
|
||||||
|
// If this isn't a load of the whole alloca to an integer, it may be a load
|
||||||
|
// of the first element. Just ignore the load in this case and normal SROA
|
||||||
|
// will handle it.
|
||||||
|
if (!isa<IntegerType>(LI->getType()) ||
|
||||||
|
TD->getTypeAllocSizeInBits(LI->getType()) != AllocaSizeBits)
|
||||||
|
return;
|
||||||
|
|
||||||
DEBUG(errs() << "PROMOTING LOAD OF WHOLE ALLOCA: " << *AI << '\n' << *LI
|
DEBUG(errs() << "PROMOTING LOAD OF WHOLE ALLOCA: " << *AI << '\n' << *LI
|
||||||
<< '\n');
|
<< '\n');
|
||||||
|
|
||||||
@@ -1162,9 +1139,10 @@ void SROA::RewriteLoadUserOfWholeAlloca(LoadInst *LI, AllocaInst *AI,
|
|||||||
ResultVal = new TruncInst(ResultVal, LI->getType(), "", LI);
|
ResultVal = new TruncInst(ResultVal, LI->getType(), "", LI);
|
||||||
|
|
||||||
LI->replaceAllUsesWith(ResultVal);
|
LI->replaceAllUsesWith(ResultVal);
|
||||||
DeadInsts.push_back(LI);
|
LI->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// HasPadding - Return true if the specified type has any structure or
|
/// HasPadding - Return true if the specified type has any structure or
|
||||||
/// alignment padding, false otherwise.
|
/// alignment padding, false otherwise.
|
||||||
static bool HasPadding(const Type *Ty, const TargetData &TD) {
|
static bool HasPadding(const Type *Ty, const TargetData &TD) {
|
||||||
@@ -1214,11 +1192,15 @@ int SROA::isSafeAllocaToScalarRepl(AllocaInst *AI) {
|
|||||||
// the users are safe to transform.
|
// the users are safe to transform.
|
||||||
AllocaInfo Info;
|
AllocaInfo Info;
|
||||||
|
|
||||||
isSafeForScalarRepl(AI, AI, 0, 0, Info);
|
for (Value::use_iterator I = AI->use_begin(), E = AI->use_end();
|
||||||
|
I != E; ++I) {
|
||||||
|
isSafeUseOfAllocation(cast<Instruction>(*I), AI, Info);
|
||||||
if (Info.isUnsafe) {
|
if (Info.isUnsafe) {
|
||||||
DEBUG(errs() << "Cannot transform: " << *AI << '\n');
|
DEBUG(errs() << "Cannot transform: " << *AI << "\n due to user: "
|
||||||
|
<< **I << '\n');
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Okay, we know all the users are promotable. If the aggregate is a memcpy
|
// Okay, we know all the users are promotable. If the aggregate is a memcpy
|
||||||
// source and destination, we have to be careful. In particular, the memcpy
|
// source and destination, we have to be careful. In particular, the memcpy
|
||||||
@@ -1226,7 +1208,7 @@ int SROA::isSafeAllocaToScalarRepl(AllocaInst *AI) {
|
|||||||
// types, but may actually be used. In these cases, we refuse to promote the
|
// types, but may actually be used. In these cases, we refuse to promote the
|
||||||
// struct.
|
// struct.
|
||||||
if (Info.isMemCpySrc && Info.isMemCpyDst &&
|
if (Info.isMemCpySrc && Info.isMemCpyDst &&
|
||||||
HasPadding(AI->getAllocatedType(), *TD))
|
HasPadding(AI->getType()->getElementType(), *TD))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// If we require cleanup, return 1, otherwise return 3.
|
// If we require cleanup, return 1, otherwise return 3.
|
||||||
@@ -1263,12 +1245,12 @@ void SROA::CleanupGEP(GetElementPtrInst *GEPI) {
|
|||||||
// Insert the new GEP instructions, which are properly indexed.
|
// Insert the new GEP instructions, which are properly indexed.
|
||||||
SmallVector<Value*, 8> Indices(GEPI->op_begin()+1, GEPI->op_end());
|
SmallVector<Value*, 8> Indices(GEPI->op_begin()+1, GEPI->op_end());
|
||||||
Indices[1] = Constant::getNullValue(Type::getInt32Ty(GEPI->getContext()));
|
Indices[1] = Constant::getNullValue(Type::getInt32Ty(GEPI->getContext()));
|
||||||
Value *ZeroIdx = GetElementPtrInst::CreateInBounds(GEPI->getOperand(0),
|
Value *ZeroIdx = GetElementPtrInst::Create(GEPI->getOperand(0),
|
||||||
Indices.begin(),
|
Indices.begin(),
|
||||||
Indices.end(),
|
Indices.end(),
|
||||||
GEPI->getName()+".0", GEPI);
|
GEPI->getName()+".0", GEPI);
|
||||||
Indices[1] = ConstantInt::get(Type::getInt32Ty(GEPI->getContext()), 1);
|
Indices[1] = ConstantInt::get(Type::getInt32Ty(GEPI->getContext()), 1);
|
||||||
Value *OneIdx = GetElementPtrInst::CreateInBounds(GEPI->getOperand(0),
|
Value *OneIdx = GetElementPtrInst::Create(GEPI->getOperand(0),
|
||||||
Indices.begin(),
|
Indices.begin(),
|
||||||
Indices.end(),
|
Indices.end(),
|
||||||
GEPI->getName()+".1", GEPI);
|
GEPI->getName()+".1", GEPI);
|
||||||
@@ -1282,24 +1264,22 @@ void SROA::CleanupGEP(GetElementPtrInst *GEPI) {
|
|||||||
LI->replaceAllUsesWith(R);
|
LI->replaceAllUsesWith(R);
|
||||||
LI->eraseFromParent();
|
LI->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
GEPI->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// CleanupAllocaUsers - If SROA reported that it can promote the specified
|
/// CleanupAllocaUsers - If SROA reported that it can promote the specified
|
||||||
/// allocation, but only if cleaned up, perform the cleanups required.
|
/// allocation, but only if cleaned up, perform the cleanups required.
|
||||||
void SROA::CleanupAllocaUsers(Value *V) {
|
void SROA::CleanupAllocaUsers(AllocaInst *AI) {
|
||||||
// At this point, we know that the end result will be SROA'd and promoted, so
|
// 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
|
// we can insert ugly code if required so long as sroa+mem2reg will clean it
|
||||||
// up.
|
// up.
|
||||||
for (Value::use_iterator UI = V->use_begin(), E = V->use_end();
|
for (Value::use_iterator UI = AI->use_begin(), E = AI->use_end();
|
||||||
UI != E; ) {
|
UI != E; ) {
|
||||||
User *U = *UI++;
|
User *U = *UI++;
|
||||||
if (isa<BitCastInst>(U)) {
|
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(U))
|
||||||
CleanupAllocaUsers(U);
|
|
||||||
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(U)) {
|
|
||||||
CleanupGEP(GEPI);
|
CleanupGEP(GEPI);
|
||||||
CleanupAllocaUsers(GEPI);
|
else {
|
||||||
if (GEPI->use_empty()) GEPI->eraseFromParent();
|
|
||||||
} else {
|
|
||||||
Instruction *I = cast<Instruction>(U);
|
Instruction *I = cast<Instruction>(U);
|
||||||
SmallVector<DbgInfoIntrinsic *, 2> DbgInUses;
|
SmallVector<DbgInfoIntrinsic *, 2> DbgInUses;
|
||||||
if (!isa<StoreInst>(I) && OnlyUsedByDbgInfoIntrinsics(I, &DbgInUses)) {
|
if (!isa<StoreInst>(I) && OnlyUsedByDbgInfoIntrinsics(I, &DbgInUses)) {
|
||||||
@@ -1415,7 +1395,7 @@ bool SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial, const Type *&VecTy,
|
|||||||
|
|
||||||
// Compute the offset that this GEP adds to the pointer.
|
// Compute the offset that this GEP adds to the pointer.
|
||||||
SmallVector<Value*, 8> Indices(GEP->op_begin()+1, GEP->op_end());
|
SmallVector<Value*, 8> Indices(GEP->op_begin()+1, GEP->op_end());
|
||||||
uint64_t GEPOffset = TD->getIndexedOffset(GEP->getPointerOperandType(),
|
uint64_t GEPOffset = TD->getIndexedOffset(GEP->getOperand(0)->getType(),
|
||||||
&Indices[0], Indices.size());
|
&Indices[0], Indices.size());
|
||||||
// See if all uses can be converted.
|
// See if all uses can be converted.
|
||||||
if (!CanConvertToScalar(GEP, IsNotTrivial, VecTy, SawVec,Offset+GEPOffset,
|
if (!CanConvertToScalar(GEP, IsNotTrivial, VecTy, SawVec,Offset+GEPOffset,
|
||||||
@@ -1477,7 +1457,7 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, uint64_t Offset) {
|
|||||||
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(User)) {
|
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(User)) {
|
||||||
// Compute the offset that this GEP adds to the pointer.
|
// Compute the offset that this GEP adds to the pointer.
|
||||||
SmallVector<Value*, 8> Indices(GEP->op_begin()+1, GEP->op_end());
|
SmallVector<Value*, 8> Indices(GEP->op_begin()+1, GEP->op_end());
|
||||||
uint64_t GEPOffset = TD->getIndexedOffset(GEP->getPointerOperandType(),
|
uint64_t GEPOffset = TD->getIndexedOffset(GEP->getOperand(0)->getType(),
|
||||||
&Indices[0], Indices.size());
|
&Indices[0], Indices.size());
|
||||||
ConvertUsesToScalar(GEP, NewAI, Offset+GEPOffset*8);
|
ConvertUsesToScalar(GEP, NewAI, Offset+GEPOffset*8);
|
||||||
GEP->eraseFromParent();
|
GEP->eraseFromParent();
|
||||||
|
@@ -1,89 +0,0 @@
|
|||||||
; RUN: opt < %s -scalarrepl -S | FileCheck %s
|
|
||||||
; Radar 7441282
|
|
||||||
|
|
||||||
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32-n32"
|
|
||||||
target triple = "thumbv7-apple-darwin10"
|
|
||||||
|
|
||||||
%struct.__neon_int16x8x2_t = type { <8 x i16>, <8 x i16> }
|
|
||||||
%struct.int16x8_t = type { <8 x i16> }
|
|
||||||
%struct.int16x8x2_t = type { [2 x %struct.int16x8_t] }
|
|
||||||
%union..0anon = type { %struct.int16x8x2_t }
|
|
||||||
|
|
||||||
define arm_apcscc void @test(<8 x i16> %tmp.0, %struct.int16x8x2_t* %dst) nounwind {
|
|
||||||
; CHECK: @test
|
|
||||||
; CHECK-NOT: alloca
|
|
||||||
; CHECK: "alloca point"
|
|
||||||
entry:
|
|
||||||
%tmp_addr = alloca %struct.int16x8_t ; <%struct.int16x8_t*> [#uses=3]
|
|
||||||
%dst_addr = alloca %struct.int16x8x2_t* ; <%struct.int16x8x2_t**> [#uses=2]
|
|
||||||
%__rv = alloca %union..0anon ; <%union..0anon*> [#uses=2]
|
|
||||||
%__bx = alloca %struct.int16x8_t ; <%struct.int16x8_t*> [#uses=2]
|
|
||||||
%__ax = alloca %struct.int16x8_t ; <%struct.int16x8_t*> [#uses=2]
|
|
||||||
%tmp2 = alloca %struct.int16x8x2_t ; <%struct.int16x8x2_t*> [#uses=2]
|
|
||||||
%0 = alloca %struct.int16x8x2_t ; <%struct.int16x8x2_t*> [#uses=2]
|
|
||||||
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
|
|
||||||
%1 = getelementptr inbounds %struct.int16x8_t* %tmp_addr, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
store <8 x i16> %tmp.0, <8 x i16>* %1
|
|
||||||
store %struct.int16x8x2_t* %dst, %struct.int16x8x2_t** %dst_addr
|
|
||||||
%2 = getelementptr inbounds %struct.int16x8_t* %__ax, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
%3 = getelementptr inbounds %struct.int16x8_t* %tmp_addr, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
%4 = load <8 x i16>* %3, align 16 ; <<8 x i16>> [#uses=1]
|
|
||||||
store <8 x i16> %4, <8 x i16>* %2, align 16
|
|
||||||
%5 = getelementptr inbounds %struct.int16x8_t* %__bx, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
%6 = getelementptr inbounds %struct.int16x8_t* %tmp_addr, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
%7 = load <8 x i16>* %6, align 16 ; <<8 x i16>> [#uses=1]
|
|
||||||
store <8 x i16> %7, <8 x i16>* %5, align 16
|
|
||||||
%8 = getelementptr inbounds %struct.int16x8_t* %__ax, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
%9 = load <8 x i16>* %8, align 16 ; <<8 x i16>> [#uses=2]
|
|
||||||
%10 = getelementptr inbounds %struct.int16x8_t* %__bx, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
%11 = load <8 x i16>* %10, align 16 ; <<8 x i16>> [#uses=2]
|
|
||||||
%12 = getelementptr inbounds %union..0anon* %__rv, i32 0, i32 0 ; <%struct.int16x8x2_t*> [#uses=1]
|
|
||||||
%13 = bitcast %struct.int16x8x2_t* %12 to %struct.__neon_int16x8x2_t* ; <%struct.__neon_int16x8x2_t*> [#uses=2]
|
|
||||||
%14 = shufflevector <8 x i16> %9, <8 x i16> %11, <8 x i32> <i32 0, i32 8, i32 2, i32 10, i32 4, i32 12, i32 6, i32 14> ; <<8 x i16>> [#uses=1]
|
|
||||||
%15 = getelementptr inbounds %struct.__neon_int16x8x2_t* %13, i32 0, i32 0 ; <<8 x i16>*> [#uses=1]
|
|
||||||
store <8 x i16> %14, <8 x i16>* %15
|
|
||||||
%16 = shufflevector <8 x i16> %9, <8 x i16> %11, <8 x i32> <i32 1, i32 9, i32 3, i32 11, i32 5, i32 13, i32 7, i32 15> ; <<8 x i16>> [#uses=1]
|
|
||||||
%17 = getelementptr inbounds %struct.__neon_int16x8x2_t* %13, i32 0, i32 1 ; <<8 x i16>*> [#uses=1]
|
|
||||||
store <8 x i16> %16, <8 x i16>* %17
|
|
||||||
%18 = getelementptr inbounds %union..0anon* %__rv, i32 0, i32 0 ; <%struct.int16x8x2_t*> [#uses=1]
|
|
||||||
%19 = bitcast %struct.int16x8x2_t* %0 to i8* ; <i8*> [#uses=1]
|
|
||||||
%20 = bitcast %struct.int16x8x2_t* %18 to i8* ; <i8*> [#uses=1]
|
|
||||||
call void @llvm.memcpy.i32(i8* %19, i8* %20, i32 32, i32 16)
|
|
||||||
%tmp21 = bitcast %struct.int16x8x2_t* %tmp2 to i8* ; <i8*> [#uses=1]
|
|
||||||
%21 = bitcast %struct.int16x8x2_t* %0 to i8* ; <i8*> [#uses=1]
|
|
||||||
call void @llvm.memcpy.i32(i8* %tmp21, i8* %21, i32 32, i32 16)
|
|
||||||
%22 = load %struct.int16x8x2_t** %dst_addr, align 4 ; <%struct.int16x8x2_t*> [#uses=1]
|
|
||||||
%23 = bitcast %struct.int16x8x2_t* %22 to i8* ; <i8*> [#uses=1]
|
|
||||||
%tmp22 = bitcast %struct.int16x8x2_t* %tmp2 to i8* ; <i8*> [#uses=1]
|
|
||||||
call void @llvm.memcpy.i32(i8* %23, i8* %tmp22, i32 32, i32 16)
|
|
||||||
br label %return
|
|
||||||
|
|
||||||
; CHECK: store <8 x i16>
|
|
||||||
; CHECK: store <8 x i16>
|
|
||||||
|
|
||||||
return: ; preds = %entry
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; Radar 7466574
|
|
||||||
%struct._NSRange = type { i64 }
|
|
||||||
|
|
||||||
define arm_apcscc void @test_memcpy_self() nounwind {
|
|
||||||
; CHECK: @test_memcpy_self
|
|
||||||
; CHECK-NOT: alloca
|
|
||||||
; CHECK: br i1
|
|
||||||
entry:
|
|
||||||
%range = alloca %struct._NSRange ; <%struct._NSRange*> [#uses=2]
|
|
||||||
br i1 undef, label %cond.true, label %cond.false
|
|
||||||
|
|
||||||
cond.true: ; preds = %entry
|
|
||||||
%tmp3 = bitcast %struct._NSRange* %range to i8* ; <i8*> [#uses=1]
|
|
||||||
%tmp4 = bitcast %struct._NSRange* %range to i8* ; <i8*> [#uses=1]
|
|
||||||
call void @llvm.memcpy.i32(i8* %tmp3, i8* %tmp4, i32 8, i32 8)
|
|
||||||
ret void
|
|
||||||
|
|
||||||
cond.false: ; preds = %entry
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @llvm.memcpy.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind
|
|
Reference in New Issue
Block a user