mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-09 20:13:35 +00:00
Teach scalarrepl to promote unions of vectors and floats, producing
insert/extractelement operations. This implements Transforms/ScalarRepl/vector_promote.ll git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@27710 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
d8f5bd3988
commit
de6df88529
@ -415,16 +415,30 @@ void SROA::CanonicalizeAllocaUsers(AllocationInst *AI) {
|
|||||||
/// MergeInType - Add the 'In' type to the accumulated type so far. If the
|
/// MergeInType - Add the 'In' type to the accumulated type so far. If the
|
||||||
/// types are incompatible, return true, otherwise update Accum and return
|
/// types are incompatible, return true, otherwise update Accum and return
|
||||||
/// false.
|
/// false.
|
||||||
|
///
|
||||||
|
/// There are two cases we handle here:
|
||||||
|
/// 1) An effectively integer union, where the pieces are stored into as
|
||||||
|
/// smaller integers (common with byte swap and other idioms).
|
||||||
|
/// 2) A union of a vector and its elements. Here we turn element accesses
|
||||||
|
/// into insert/extract element operations.
|
||||||
static bool MergeInType(const Type *In, const Type *&Accum) {
|
static bool MergeInType(const Type *In, const Type *&Accum) {
|
||||||
if (!In->isIntegral()) return true;
|
|
||||||
|
|
||||||
// If this is our first type, just use it.
|
// If this is our first type, just use it.
|
||||||
if (Accum == Type::VoidTy) {
|
const PackedType *PTy;
|
||||||
|
if (Accum == Type::VoidTy || In == Accum) {
|
||||||
Accum = In;
|
Accum = In;
|
||||||
} else {
|
} else if (In->isIntegral() && Accum->isIntegral()) { // integer union.
|
||||||
// Otherwise pick whichever type is larger.
|
// Otherwise pick whichever type is larger.
|
||||||
if (In->getTypeID() > Accum->getTypeID())
|
if (In->getTypeID() > Accum->getTypeID())
|
||||||
Accum = In;
|
Accum = In;
|
||||||
|
} else if ((PTy = dyn_cast<PackedType>(Accum)) &&
|
||||||
|
PTy->getElementType() == In) {
|
||||||
|
// Accum is a vector, and we are accessing an element: ok.
|
||||||
|
} else if ((PTy = dyn_cast<PackedType>(In)) &&
|
||||||
|
PTy->getElementType() == Accum) {
|
||||||
|
// In is a vector, and accum is an element: ok, remember In.
|
||||||
|
Accum = In;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -462,7 +476,7 @@ const Type *SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial) {
|
|||||||
// Storing the pointer, not the into the value?
|
// Storing the pointer, not the into the value?
|
||||||
if (SI->getOperand(0) == V) return 0;
|
if (SI->getOperand(0) == V) return 0;
|
||||||
|
|
||||||
// NOTE: We could handle storing of FP imms here!
|
// NOTE: We could handle storing of FP imms into integers here!
|
||||||
|
|
||||||
if (MergeInType(SI->getOperand(0)->getType(), UsedType))
|
if (MergeInType(SI->getOperand(0)->getType(), UsedType))
|
||||||
return 0;
|
return 0;
|
||||||
@ -482,7 +496,7 @@ const Type *SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial) {
|
|||||||
IsNotTrivial = true;
|
IsNotTrivial = true;
|
||||||
const Type *SubElt = CanConvertToScalar(GEP, IsNotTrivial);
|
const Type *SubElt = CanConvertToScalar(GEP, IsNotTrivial);
|
||||||
if (SubElt == 0) return 0;
|
if (SubElt == 0) return 0;
|
||||||
if (SubElt != Type::VoidTy) {
|
if (SubElt != Type::VoidTy && SubElt->isInteger()) {
|
||||||
const Type *NewTy =
|
const Type *NewTy =
|
||||||
getUIntAtLeastAsBitAs(SubElt->getPrimitiveSizeInBits()+BitOffset);
|
getUIntAtLeastAsBitAs(SubElt->getPrimitiveSizeInBits()+BitOffset);
|
||||||
if (NewTy == 0 || MergeInType(NewTy, UsedType)) return 0;
|
if (NewTy == 0 || MergeInType(NewTy, UsedType)) return 0;
|
||||||
@ -499,8 +513,23 @@ const Type *SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial) {
|
|||||||
|
|
||||||
if (const ArrayType *ATy = dyn_cast<ArrayType>(AggTy)) {
|
if (const ArrayType *ATy = dyn_cast<ArrayType>(AggTy)) {
|
||||||
if (Idx >= ATy->getNumElements()) return 0; // Out of range.
|
if (Idx >= ATy->getNumElements()) return 0; // Out of range.
|
||||||
} else if (const PackedType *PTy = dyn_cast<PackedType>(AggTy)) {
|
} else if (const PackedType *PackedTy = dyn_cast<PackedType>(AggTy)) {
|
||||||
if (Idx >= PTy->getNumElements()) return 0; // Out of range.
|
// Getting an element of the packed vector.
|
||||||
|
if (Idx >= PackedTy->getNumElements()) return 0; // Out of range.
|
||||||
|
|
||||||
|
// Merge in the packed type.
|
||||||
|
if (MergeInType(PackedTy, UsedType)) return 0;
|
||||||
|
|
||||||
|
const Type *SubTy = CanConvertToScalar(GEP, IsNotTrivial);
|
||||||
|
if (SubTy == 0) return 0;
|
||||||
|
|
||||||
|
if (SubTy != Type::VoidTy && MergeInType(SubTy, UsedType))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// We'll need to change this to an insert/extract element operation.
|
||||||
|
IsNotTrivial = true;
|
||||||
|
continue; // Everything looks ok
|
||||||
|
|
||||||
} else if (isa<StructType>(AggTy)) {
|
} else if (isa<StructType>(AggTy)) {
|
||||||
// Structs are always ok.
|
// Structs are always ok.
|
||||||
} else {
|
} else {
|
||||||
@ -537,31 +566,47 @@ void SROA::ConvertToScalar(AllocationInst *AI, const Type *ActualTy) {
|
|||||||
"Not in the entry block!");
|
"Not in the entry block!");
|
||||||
EntryBlock->getInstList().remove(AI); // Take the alloca out of the program.
|
EntryBlock->getInstList().remove(AI); // Take the alloca out of the program.
|
||||||
|
|
||||||
|
if (ActualTy->isInteger())
|
||||||
|
ActualTy = ActualTy->getUnsignedVersion();
|
||||||
|
|
||||||
// Create and insert the alloca.
|
// Create and insert the alloca.
|
||||||
AllocaInst *NewAI = new AllocaInst(ActualTy->getUnsignedVersion(), 0,
|
AllocaInst *NewAI = new AllocaInst(ActualTy, 0, AI->getName(),
|
||||||
AI->getName(), EntryBlock->begin());
|
EntryBlock->begin());
|
||||||
ConvertUsesToScalar(AI, NewAI, 0);
|
ConvertUsesToScalar(AI, NewAI, 0);
|
||||||
delete AI;
|
delete AI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// ConvertUsesToScalar - Convert all of the users of Ptr to use the new alloca
|
/// ConvertUsesToScalar - Convert all of the users of Ptr to use the new alloca
|
||||||
/// directly. Offset is an offset from the original alloca, in bits that need
|
/// directly. This happens when we are converting an "integer union" to a
|
||||||
/// to be shifted to the right. By the end of this, there should be no uses of
|
/// single integer scalar, or when we are converting a "vector union" to a
|
||||||
/// Ptr.
|
/// vector with insert/extractelement instructions.
|
||||||
|
///
|
||||||
|
/// Offset is an offset from the original alloca, in bits that need to be
|
||||||
|
/// shifted to the right. By the end of this, there should be no uses of Ptr.
|
||||||
void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) {
|
void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) {
|
||||||
|
bool isVectorInsert = isa<PackedType>(NewAI->getType()->getElementType());
|
||||||
while (!Ptr->use_empty()) {
|
while (!Ptr->use_empty()) {
|
||||||
Instruction *User = cast<Instruction>(Ptr->use_back());
|
Instruction *User = cast<Instruction>(Ptr->use_back());
|
||||||
|
|
||||||
if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
|
if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
|
||||||
// The load is a bit extract from NewAI shifted right by Offset bits.
|
// The load is a bit extract from NewAI shifted right by Offset bits.
|
||||||
Value *NV = new LoadInst(NewAI, LI->getName(), LI);
|
Value *NV = new LoadInst(NewAI, LI->getName(), LI);
|
||||||
if (Offset && Offset < NV->getType()->getPrimitiveSizeInBits())
|
if (NV->getType() != LI->getType()) {
|
||||||
NV = new ShiftInst(Instruction::Shr, NV,
|
if (const PackedType *PTy = dyn_cast<PackedType>(NV->getType())) {
|
||||||
ConstantUInt::get(Type::UByteTy, Offset),
|
// Must be an element access.
|
||||||
LI->getName(), LI);
|
unsigned Elt = Offset/PTy->getElementType()->getPrimitiveSizeInBits();
|
||||||
if (NV->getType() != LI->getType())
|
NV = new ExtractElementInst(NV, ConstantUInt::get(Type::UIntTy, Elt),
|
||||||
NV = new CastInst(NV, LI->getType(), LI->getName(), LI);
|
"tmp", LI);
|
||||||
|
} else {
|
||||||
|
assert(NV->getType()->isInteger() && "Unknown promotion!");
|
||||||
|
if (Offset && Offset < NV->getType()->getPrimitiveSizeInBits())
|
||||||
|
NV = new ShiftInst(Instruction::Shr, NV,
|
||||||
|
ConstantUInt::get(Type::UByteTy, Offset),
|
||||||
|
LI->getName(), LI);
|
||||||
|
NV = new CastInst(NV, LI->getType(), LI->getName(), LI);
|
||||||
|
}
|
||||||
|
}
|
||||||
LI->replaceAllUsesWith(NV);
|
LI->replaceAllUsesWith(NV);
|
||||||
LI->eraseFromParent();
|
LI->eraseFromParent();
|
||||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
|
} else if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
|
||||||
@ -570,31 +615,41 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) {
|
|||||||
// Convert the stored type to the actual type, shift it left to insert
|
// Convert the stored type to the actual type, shift it left to insert
|
||||||
// then 'or' into place.
|
// then 'or' into place.
|
||||||
Value *SV = SI->getOperand(0);
|
Value *SV = SI->getOperand(0);
|
||||||
if (SV->getType() != NewAI->getType()->getElementType() || Offset != 0) {
|
const Type *AllocaType = NewAI->getType()->getElementType();
|
||||||
|
if (SV->getType() != AllocaType) {
|
||||||
Value *Old = new LoadInst(NewAI, NewAI->getName()+".in", SI);
|
Value *Old = new LoadInst(NewAI, NewAI->getName()+".in", SI);
|
||||||
// If SV is signed, convert it to unsigned, so that the next cast zero
|
|
||||||
// extends the value.
|
if (const PackedType *PTy = dyn_cast<PackedType>(AllocaType)) {
|
||||||
if (SV->getType()->isSigned())
|
// Must be an element insertion.
|
||||||
SV = new CastInst(SV, SV->getType()->getUnsignedVersion(),
|
unsigned Elt = Offset/PTy->getElementType()->getPrimitiveSizeInBits();
|
||||||
SV->getName(), SI);
|
SV = new InsertElementInst(Old, SV,
|
||||||
SV = new CastInst(SV, Old->getType(), SV->getName(), SI);
|
ConstantUInt::get(Type::UIntTy, Elt),
|
||||||
if (Offset && Offset < SV->getType()->getPrimitiveSizeInBits())
|
"tmp", SI);
|
||||||
SV = new ShiftInst(Instruction::Shl, SV,
|
} else {
|
||||||
ConstantUInt::get(Type::UByteTy, Offset),
|
// If SV is signed, convert it to unsigned, so that the next cast zero
|
||||||
SV->getName()+".adj", SI);
|
// extends the value.
|
||||||
// Mask out the bits we are about to insert from the old value.
|
if (SV->getType()->isSigned())
|
||||||
unsigned TotalBits = SV->getType()->getPrimitiveSizeInBits();
|
SV = new CastInst(SV, SV->getType()->getUnsignedVersion(),
|
||||||
unsigned InsertBits =
|
SV->getName(), SI);
|
||||||
SI->getOperand(0)->getType()->getPrimitiveSizeInBits();
|
SV = new CastInst(SV, Old->getType(), SV->getName(), SI);
|
||||||
if (TotalBits != InsertBits) {
|
if (Offset && Offset < SV->getType()->getPrimitiveSizeInBits())
|
||||||
assert(TotalBits > InsertBits);
|
SV = new ShiftInst(Instruction::Shl, SV,
|
||||||
uint64_t Mask = ~(((1ULL << InsertBits)-1) << Offset);
|
ConstantUInt::get(Type::UByteTy, Offset),
|
||||||
if (TotalBits != 64)
|
SV->getName()+".adj", SI);
|
||||||
Mask = Mask & ((1ULL << TotalBits)-1);
|
// Mask out the bits we are about to insert from the old value.
|
||||||
Old = BinaryOperator::createAnd(Old,
|
unsigned TotalBits = SV->getType()->getPrimitiveSizeInBits();
|
||||||
|
unsigned InsertBits =
|
||||||
|
SI->getOperand(0)->getType()->getPrimitiveSizeInBits();
|
||||||
|
if (TotalBits != InsertBits) {
|
||||||
|
assert(TotalBits > InsertBits);
|
||||||
|
uint64_t Mask = ~(((1ULL << InsertBits)-1) << Offset);
|
||||||
|
if (TotalBits != 64)
|
||||||
|
Mask = Mask & ((1ULL << TotalBits)-1);
|
||||||
|
Old = BinaryOperator::createAnd(Old,
|
||||||
ConstantUInt::get(Old->getType(), Mask),
|
ConstantUInt::get(Old->getType(), Mask),
|
||||||
Old->getName()+".mask", SI);
|
Old->getName()+".mask", SI);
|
||||||
SV = BinaryOperator::createOr(Old, SV, SV->getName()+".ins", SI);
|
SV = BinaryOperator::createOr(Old, SV, SV->getName()+".ins", SI);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new StoreInst(SV, NewAI, SI);
|
new StoreInst(SV, NewAI, SI);
|
||||||
@ -603,7 +658,7 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) {
|
|||||||
} else if (CastInst *CI = dyn_cast<CastInst>(User)) {
|
} else if (CastInst *CI = dyn_cast<CastInst>(User)) {
|
||||||
unsigned NewOff = Offset;
|
unsigned NewOff = Offset;
|
||||||
const TargetData &TD = getAnalysis<TargetData>();
|
const TargetData &TD = getAnalysis<TargetData>();
|
||||||
if (TD.isBigEndian()) {
|
if (TD.isBigEndian() && !isVectorInsert) {
|
||||||
// Adjust the pointer. For example, storing 16-bits into a 32-bit
|
// Adjust the pointer. For example, storing 16-bits into a 32-bit
|
||||||
// alloca with just a cast makes it modify the top 16-bits.
|
// alloca with just a cast makes it modify the top 16-bits.
|
||||||
const Type *SrcTy = cast<PointerType>(Ptr->getType())->getElementType();
|
const Type *SrcTy = cast<PointerType>(Ptr->getType())->getElementType();
|
||||||
@ -625,7 +680,7 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) {
|
|||||||
unsigned Idx = cast<ConstantInt>(GEP->getOperand(1))->getRawValue();
|
unsigned Idx = cast<ConstantInt>(GEP->getOperand(1))->getRawValue();
|
||||||
unsigned BitOffset = Idx*AggSizeInBits;
|
unsigned BitOffset = Idx*AggSizeInBits;
|
||||||
|
|
||||||
if (TD.isLittleEndian())
|
if (TD.isLittleEndian() || isVectorInsert)
|
||||||
NewOffset += BitOffset;
|
NewOffset += BitOffset;
|
||||||
else
|
else
|
||||||
NewOffset -= BitOffset;
|
NewOffset -= BitOffset;
|
||||||
@ -637,14 +692,14 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) {
|
|||||||
if (const SequentialType *SeqTy = dyn_cast<SequentialType>(AggTy)) {
|
if (const SequentialType *SeqTy = dyn_cast<SequentialType>(AggTy)) {
|
||||||
unsigned ElSizeBits = TD.getTypeSize(SeqTy->getElementType())*8;
|
unsigned ElSizeBits = TD.getTypeSize(SeqTy->getElementType())*8;
|
||||||
|
|
||||||
if (TD.isLittleEndian())
|
if (TD.isLittleEndian() || isVectorInsert)
|
||||||
NewOffset += ElSizeBits*Idx;
|
NewOffset += ElSizeBits*Idx;
|
||||||
else
|
else
|
||||||
NewOffset += AggSizeInBits-ElSizeBits*(Idx+1);
|
NewOffset += AggSizeInBits-ElSizeBits*(Idx+1);
|
||||||
} else if (const StructType *STy = dyn_cast<StructType>(AggTy)) {
|
} else if (const StructType *STy = dyn_cast<StructType>(AggTy)) {
|
||||||
unsigned EltBitOffset = TD.getStructLayout(STy)->MemberOffsets[Idx]*8;
|
unsigned EltBitOffset = TD.getStructLayout(STy)->MemberOffsets[Idx]*8;
|
||||||
|
|
||||||
if (TD.isLittleEndian())
|
if (TD.isLittleEndian() || isVectorInsert)
|
||||||
NewOffset += EltBitOffset;
|
NewOffset += EltBitOffset;
|
||||||
else {
|
else {
|
||||||
const PointerType *ElPtrTy = cast<PointerType>(GEP->getType());
|
const PointerType *ElPtrTy = cast<PointerType>(GEP->getType());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user