diff options
author | Chris Lattner <sabre@nondot.org> | 2006-12-10 23:56:50 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2006-12-10 23:56:50 +0000 |
commit | ae6a30509463a82182d090d2b42623e02c118596 (patch) | |
tree | f04b8630a05db4a235df0dfb9467c769bb14265d | |
parent | 1846783d93d4a0e05796e3ee180fc74f5ac4683c (diff) |
* Eliminate calls to CastInst::createInferredCast.
* Add support for promoting unions with fp values in them. This produces
our new int<->fp bitcast instructions, implementing
Transforms/ScalarRepl/union-fp-int.ll
As an example, this allows us to compile this:
union intfloat { int i; float f; };
float invsqrt(const float arg_x) {
union intfloat x = { .f = arg_x };
const float xhalf = arg_x * 0.5f;
x.i = 0x5f3759df - (x.i >> 1);
return x.f * (1.5f - xhalf * x.f * x.f);
}
into:
_invsqrt:
movss 4(%esp), %xmm0
movd %xmm0, %eax
sarl %eax
movl $1597463007, %ecx
subl %eax, %ecx
movd %ecx, %xmm1
mulss LCPI1_0, %xmm0
mulss %xmm1, %xmm0
movss LCPI1_1, %xmm2
mulss %xmm1, %xmm0
subss %xmm0, %xmm2
movl 8(%esp), %eax
mulss %xmm2, %xmm1
movss %xmm1, (%eax)
ret
instead of:
_invsqrt:
subl $4, %esp
movss 8(%esp), %xmm0
movss %xmm0, (%esp)
movl (%esp), %eax
movl $1597463007, %ecx
sarl %eax
subl %eax, %ecx
movl %ecx, (%esp)
mulss LCPI1_0, %xmm0
movss (%esp), %xmm1
mulss %xmm1, %xmm0
mulss %xmm1, %xmm0
movss LCPI1_1, %xmm2
subss %xmm0, %xmm2
mulss %xmm2, %xmm1
movl 12(%esp), %eax
movss %xmm1, (%eax)
addl $4, %esp
ret
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@32418 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Transforms/Scalar/ScalarReplAggregates.cpp | 133 |
1 files changed, 93 insertions, 40 deletions
diff --git a/lib/Transforms/Scalar/ScalarReplAggregates.cpp b/lib/Transforms/Scalar/ScalarReplAggregates.cpp index 959b192077..07e4a75b72 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregates.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -419,11 +419,14 @@ void SROA::CanonicalizeAllocaUsers(AllocationInst *AI) { /// types are incompatible, return true, otherwise update Accum and return /// false. /// -/// There are two cases we handle here: +/// There are three 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. +/// 3) A union of scalar types, such as int/float or int/pointer. Here we +/// merge together into integers, allowing the xform to work with #1 as +/// well. static bool MergeInType(const Type *In, const Type *&Accum, const TargetData &TD) { // If this is our first type, just use it. @@ -436,22 +439,38 @@ static bool MergeInType(const Type *In, const Type *&Accum, Accum = In; } else if (isa<PointerType>(In) && isa<PointerType>(Accum)) { // Pointer unions just stay as one of the pointers. - } 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 if (isa<PointerType>(In) && Accum->isIntegral()) { - // Pointer/Integer unions merge together as integers. - return MergeInType(TD.getIntPtrType(), Accum, TD); - } else if (isa<PointerType>(Accum) && In->isIntegral()) { - // Pointer/Integer unions merge together as integers. - Accum = TD.getIntPtrType(); - return MergeInType(In, Accum, TD); + } else if (isa<PackedType>(In) || isa<PackedType>(Accum)) { + 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 { + // FIXME: Handle packed->packed. + return true; + } } else { - return true; + // Pointer/FP/Integer unions merge together as integers. + switch (Accum->getTypeID()) { + case Type::PointerTyID: Accum = TD.getIntPtrType(); break; + case Type::FloatTyID: Accum = Type::UIntTy; break; + case Type::DoubleTyID: Accum = Type::ULongTy; break; + default: + assert(Accum->isIntegral() && "Unknown FP type!"); + break; + } + + switch (In->getTypeID()) { + case Type::PointerTyID: In = TD.getIntPtrType(); break; + case Type::FloatTyID: In = Type::UIntTy; break; + case Type::DoubleTyID: In = Type::ULongTy; break; + default: + assert(In->isIntegral() && "Unknown FP type!"); + break; + } + return MergeInType(In, Accum, TD); } return false; } @@ -612,20 +631,35 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) { unsigned Elt = Offset/(TD.getTypeSize(PTy->getElementType())*8); NV = new ExtractElementInst(NV, ConstantInt::get(Type::UIntTy, Elt), "tmp", LI); + } else if (isa<PointerType>(NV->getType())) { + assert(isa<PointerType>(LI->getType())); + // Must be ptr->ptr cast. Anything else would result in NV being + // an integer. + NV = new BitCastInst(NV, LI->getType(), LI->getName(), LI); } else { - if (Offset) { - assert(NV->getType()->isInteger() && "Unknown promotion!"); - if (Offset < TD.getTypeSize(NV->getType())*8) { - NV = new ShiftInst(Instruction::LShr, NV, - ConstantInt::get(Type::UByteTy, Offset), - LI->getName(), LI); - } + assert(NV->getType()->isInteger() && "Unknown promotion!"); + if (Offset && Offset < TD.getTypeSize(NV->getType())*8) { + NV = new ShiftInst(Instruction::LShr, NV, + ConstantInt::get(Type::UByteTy, Offset), + LI->getName(), LI); + } + + // If the result is an integer, this is a trunc or bitcast. + if (LI->getType()->isIntegral()) { + NV = CastInst::createTruncOrBitCast(NV, LI->getType(), + LI->getName(), LI); + } else if (LI->getType()->isFloatingPoint()) { + // If needed, truncate the integer to the appropriate size. + if (NV->getType()->getPrimitiveSize() > + LI->getType()->getPrimitiveSize()) + NV = new TruncInst(NV, LI->getType(), LI->getName(), LI); + + // Then do a bitcast. + NV = new BitCastInst(NV, LI->getType(), LI->getName(), LI); } else { - assert((NV->getType()->isInteger() || - isa<PointerType>(NV->getType())) && "Unknown promotion!"); + // Otherwise must be a pointer. + NV = new IntToPtrInst(NV, LI->getType(), LI->getName(), LI); } - NV = CastInst::createInferredCast(NV, LI->getType(), LI->getName(), - LI); } } LI->replaceAllUsesWith(NV); @@ -647,24 +681,43 @@ void SROA::ConvertUsesToScalar(Value *Ptr, AllocaInst *NewAI, unsigned Offset) { ConstantInt::get(Type::UIntTy, Elt), "tmp", SI); } else { - // Always zero extend the value. - if (SV->getType()->isSigned()) - SV = CastInst::createInferredCast(SV, - SV->getType()->getUnsignedVersion(), SV->getName(), SI); - SV = CastInst::createInferredCast(SV, Old->getType(), SV->getName(), - SI); - if (Offset && Offset < TD.getTypeSize(SV->getType())*8) + // If SV is a float, convert it to the appropriate integer type. + // If it is a pointer, do the same, and also handle ptr->ptr casts + // here. + switch (SV->getType()->getTypeID()) { + default: + assert(!SV->getType()->isFloatingPoint() && "Unknown FP type!"); + break; + case Type::FloatTyID: + SV = new BitCastInst(SV, Type::UIntTy, SV->getName(), SI); + break; + case Type::DoubleTyID: + SV = new BitCastInst(SV, Type::ULongTy, SV->getName(), SI); + break; + case Type::PointerTyID: + if (isa<PointerType>(AllocaType)) + SV = new BitCastInst(SV, AllocaType, SV->getName(), SI); + else + SV = new PtrToIntInst(SV, TD.getIntPtrType(), SV->getName(), SI); + break; + } + + unsigned SrcSize = TD.getTypeSize(SV->getType())*8; + + // Always zero extend the value if needed. + if (SV->getType() != AllocaType) + SV = CastInst::createZExtOrBitCast(SV, AllocaType, + SV->getName(), SI); + if (Offset && Offset < AllocaType->getPrimitiveSizeInBits()) SV = new ShiftInst(Instruction::Shl, SV, ConstantInt::get(Type::UByteTy, Offset), SV->getName()+".adj", SI); // Mask out the bits we are about to insert from the old value. unsigned TotalBits = TD.getTypeSize(SV->getType())*8; - unsigned InsertBits = TD.getTypeSize(SI->getOperand(0)->getType())*8; - if (TotalBits != InsertBits) { - assert(TotalBits > InsertBits); - uint64_t Mask = ~(((1ULL << InsertBits)-1) << Offset); - if (TotalBits != 64) - Mask = Mask & ((1ULL << TotalBits)-1); + if (TotalBits != SrcSize) { + assert(TotalBits > SrcSize); + uint64_t Mask = ~(((1ULL << SrcSize)-1) << Offset); + Mask = Mask & SV->getType()->getIntegralTypeMask(); Old = BinaryOperator::createAnd(Old, ConstantInt::get(Old->getType(), Mask), Old->getName()+".mask", SI); |