Better heuristics for handling arrays

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1296 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2001-11-14 11:02:49 +00:00
parent 84dce16fb1
commit d5b48ca422
4 changed files with 218 additions and 60 deletions

View File

@ -95,7 +95,17 @@ bool ExpressionConvertableToType(Value *V, const Type *Ty,
// We can convert the expr if the cast destination type is losslessly
// convertable to the requested type.
if (!losslessCastableTypes(Ty, I->getType())) return false;
break;
#if 1
// We also do not allow conversion of a cast that casts from a ptr to array
// of X to a *X. For example: cast [4 x %List *] * %val to %List * *
//
if (PointerType *SPT = dyn_cast<PointerType>(I->getOperand(0)->getType()))
if (PointerType *DPT = dyn_cast<PointerType>(I->getType()))
if (ArrayType *AT = dyn_cast<ArrayType>(SPT->getValueType()))
if (AT->getElementType() == DPT->getValueType())
return false;
#endif
return true;
case Instruction::Add:
case Instruction::Sub:
@ -395,6 +405,7 @@ bool RetValConvertableToType(Value *V, const Type *Ty,
//
static bool OperandConvertableToType(User *U, Value *V, const Type *Ty,
ValueTypeCache &CTMap) {
// TODO: IS THIS A BUG????
if (V->getType() == Ty) return true; // Already the right type?
// Expression type must be holdable in a register.
@ -409,7 +420,19 @@ static bool OperandConvertableToType(User *U, Value *V, const Type *Ty,
assert(I->getOperand(0) == V);
// We can convert the expr if the cast destination type is losslessly
// convertable to the requested type.
return losslessCastableTypes(Ty, I->getOperand(0)->getType());
if (!losslessCastableTypes(Ty, I->getOperand(0)->getType()))
return false;
#if 1
// We also do not allow conversion of a cast that casts from a ptr to array
// of X to a *X. For example: cast [4 x %List *] * %val to %List * *
//
if (PointerType *SPT = dyn_cast<PointerType>(I->getOperand(0)->getType()))
if (PointerType *DPT = dyn_cast<PointerType>(I->getType()))
if (ArrayType *AT = dyn_cast<ArrayType>(SPT->getValueType()))
if (AT->getElementType() == DPT->getValueType())
return false;
#endif
return true;
case Instruction::Add:
if (V == I->getOperand(0) && isa<CastInst>(I->getOperand(1))) {

View File

@ -12,6 +12,8 @@
#include "llvm/Analysis/FindUnsafePointerTypes.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Assembly/Writer.h"
// PruneTypes - Given a type Ty, make sure that neither it, or one of its
// subtypes, occur in TypesToModify.
//
@ -21,14 +23,20 @@ static void PruneTypes(const Type *Ty, set<const StructType*> &TypesToModify,
ProcessedTypes.insert(Ty);
// If the element is in TypesToModify, remove it now...
if (const StructType *ST = dyn_cast<StructType>(Ty))
if (const StructType *ST = dyn_cast<StructType>(Ty)) {
TypesToModify.erase(ST); // This doesn't fail if the element isn't present
cerr << "Unable to swap type: " << ST << endl;
}
// Remove all types that this type contains as well...
// Remove all types that this type contains as well... do not remove types
// that are referenced only through pointers, because we depend on the size of
// the pointer, not on what the structure points to.
//
for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end();
I != E; ++I)
PruneTypes(*I, TypesToModify, ProcessedTypes);
I != E; ++I) {
if (!isa<PointerType>(*I))
PruneTypes(*I, TypesToModify, ProcessedTypes);
}
}
@ -54,8 +62,8 @@ bool SwapStructContents::doPassInitialization(Module *M) {
const set<const Type *> &UsedTypes = FUT.getTypes();
// Combine the two sets, weeding out non structure types. Closures should
// would be nice.
// Combine the two sets, weeding out non structure types. Closures in C++
// sure would be nice.
set<const StructType*> TypesToModify;
for (set<const Type *>::const_iterator I = UsedTypes.begin(),
E = UsedTypes.end(); I != E; ++I)
@ -68,8 +76,10 @@ bool SwapStructContents::doPassInitialization(Module *M) {
//
set<const Type*> ProcessedTypes;
for (set<PointerType*>::const_iterator I = UnsafePTys.begin(),
E = UnsafePTys.end(); I != E; ++I)
E = UnsafePTys.end(); I != E; ++I) {
cerr << "Pruning type: " << *I << endl;
PruneTypes(*I, TypesToModify, ProcessedTypes);
}
// Build up a set of structure types that we are going to modify, and

View File

@ -38,6 +38,7 @@
#include "llvm/ConstPoolVals.h"
#include "llvm/Optimizations/ConstantHandling.h"
#include "llvm/Optimizations/DCE.h"
#include "llvm/Analysis/Expressions.h"
#include <algorithm>
#include "llvm/Assembly/Writer.h"
@ -57,6 +58,9 @@
#define PRINT_PEEPHOLE3(ID, I1, I2, I3) \
do { PRINT_PEEPHOLE(ID, 0, I1); PRINT_PEEPHOLE(ID, 1, I2); \
PRINT_PEEPHOLE(ID, 2, I3); } while (0)
#define PRINT_PEEPHOLE4(ID, I1, I2, I3, I4) \
do { PRINT_PEEPHOLE(ID, 0, I1); PRINT_PEEPHOLE(ID, 1, I2); \
PRINT_PEEPHOLE(ID, 2, I3); PRINT_PEEPHOLE(ID, 3, I4); } while (0)
// isReinterpretingCast - Return true if the cast instruction specified will
@ -269,6 +273,174 @@ static bool PeepholeMallocInst(BasicBlock *BB, BasicBlock::iterator &BI) {
}
// Peephole optimize the following instructions:
// %t1 = cast ulong <const int> to {<...>} *
// %t2 = add {<...>} * %SP, %t1 ;; Constant must be 2nd operand
//
// or
// %t1 = cast {<...>}* %SP to int*
// %t5 = cast ulong <const int> to int*
// %t2 = add int* %t1, %t5 ;; int is same size as field
//
// Into: %t3 = getelementptr {<...>} * %SP, <element indices>
// %t2 = cast <eltype> * %t3 to {<...>}*
//
static bool PeepholeOptimizeAddCast(BasicBlock *BB, BasicBlock::iterator &BI,
Value *AddOp1, CastInst *AddOp2) {
Value *OffsetVal = AddOp2->getOperand(0);
Value *SrcPtr; // Of type pointer to struct...
const StructType *StructTy;
if ((StructTy = getPointedToStruct(AddOp1->getType()))) {
SrcPtr = AddOp1; // Handle the first case...
} else if (CastInst *AddOp1c = dyn_cast<CastInst>(AddOp1)) {
SrcPtr = AddOp1c->getOperand(0); // Handle the second case...
StructTy = getPointedToStruct(SrcPtr->getType());
}
// Only proceed if we have detected all of our conditions successfully...
if (!StructTy || !SrcPtr || !OffsetVal->getType()->isIntegral())
return false;
// See if the cast is of an integer expression that is either a constant,
// or a value scaled by some amount with a possible offset.
//
analysis::ExprType Expr = analysis::ClassifyExpression(OffsetVal);
unsigned Offset = 0, Scale = 1;
// The expression must either be a constant, or a scaled index to be useful
if (!Expr.Offset && !Expr.Scale)
return false;
// Get the offset value if it exists...
if (Expr.Offset) {
if (ConstPoolSInt *CPSI = dyn_cast<ConstPoolSInt>(Expr.Offset))
Offset = (unsigned)CPSI->getValue();
else {
ConstPoolUInt *CPUI = cast<ConstPoolUInt>(Expr.Offset);
Offset = (unsigned)CPUI->getValue();
}
assert(Offset != 0 && "Expression analysis failure!");
}
// Get the scale value if it exists...
if (Expr.Scale) {
if (ConstPoolSInt *CPSI = dyn_cast<ConstPoolSInt>(Expr.Scale))
Scale = (unsigned)CPSI->getValue();
else {
ConstPoolUInt *CPUI = cast<ConstPoolUInt>(Expr.Scale);
Scale = (unsigned)CPUI->getValue();
}
assert(Scale != 1 && "Expression analysis failure!");
}
// Check to make sure the offset is not negative or really large, outside the
// scope of this structure...
//
if (Offset >= TD.getTypeSize(StructTy))
return false;
const StructLayout *SL = TD.getStructLayout(StructTy);
vector<ConstPoolVal*> Offsets;
unsigned ActualOffset = Offset;
const Type *ElTy = getStructOffsetType(StructTy, ActualOffset, Offsets);
if (getPointedToStruct(AddOp1->getType())) { // case 1
PRINT_PEEPHOLE2("add-to-gep1:in", AddOp2, *BI);
} else {
PRINT_PEEPHOLE3("add-to-gep2:in", AddOp1, AddOp2, *BI);
}
GetElementPtrInst *GEP = new GetElementPtrInst(SrcPtr, Offsets);
//AddOp2->getName());
BI = BB->getInstList().insert(BI, GEP)+1;
Instruction *AddrSrc = GEP;
if (const ArrayType *AT = dyn_cast<ArrayType>(ElTy)) {
assert((Scale == 1 || Offset == ActualOffset) &&
"Cannot handle scaled expression and unused offset in the same "
"instruction until after GEP array works!");
// Check to see if we have bottomed out INSIDE of an array reference..
//
if (Offset != ActualOffset) {
// Insert a cast of the "rest" of the offset to the appropriate
// pointer type.
CastInst *OffInst =
new CastInst(ConstPoolUInt::get(Type::ULongTy,
Offset-ActualOffset),
GEP->getType());
BI = BB->getInstList().insert(BI, OffInst)+1;
// Now insert an ADD to actually adjust the pointer...
Instruction *AddInst =
BinaryOperator::create(Instruction::Add, GEP, OffInst);
BI = BB->getInstList().insert(BI, AddInst)+1;
PRINT_PEEPHOLE2("add-to-gep:out1", OffInst, AddInst);
AddrSrc = AddInst;
} else if (Scale != 1) {
// If the scale factor occurs, then this means that there is an index into
// this element of the array. Check to make sure the scale factor is the
// same as the size of the datatype that we are dealing with.
//
assert(Scale == TD.getTypeSize(AT->getElementType()) &&
"Scaling by something other than the array element size!!");
// TODO: In the future, we will not want to cast the index and scale to
// pointer types first. We will want to create a GEP directly here.
// Now we must actually perform the scaling operation to get an
// appropriate value to add in... but the scale has to be done in the
// appropriate destination pointer type, so cast the index value now.
//
// Cast the base index pointer
CastInst *IdxValue = new CastInst(Expr.Var, GEP->getType());
BI = BB->getInstList().insert(BI, IdxValue)+1;
// Case the scale amount as well...
CastInst *ScaleAmt =
new CastInst(ConstPoolUInt::get(Type::ULongTy, Scale), GEP->getType());
BI = BB->getInstList().insert(BI, ScaleAmt)+1;
// Insert the multiply now. Make sure to make the constant the second arg
Instruction *ScaledVal =
BinaryOperator::create(Instruction::Mul, IdxValue, ScaleAmt);
BI = BB->getInstList().insert(BI, ScaledVal)+1;
// Now insert an ADD to actually adjust the pointer...
Instruction *AddInst =
BinaryOperator::create(Instruction::Add, GEP, ScaledVal);
BI = BB->getInstList().insert(BI, AddInst)+1;
PRINT_PEEPHOLE4("add-to-gep:out1", IdxValue, ScaleAmt, ScaledVal,
AddInst);
AddrSrc = AddInst;
}
// Insert a cast of the pointer to array of X to be a pointer to the
// element of the array.
//
// Insert a cast of the "rest" of the offset to the appropriate
// pointer type.
CastInst *ACI = new CastInst(AddrSrc, AT->getElementType());
BI = BB->getInstList().insert(BI, ACI)+1;
AddrSrc = ACI;
} else {
assert(Offset == ActualOffset && "GEP to middle of non array!");
assert(Scale == 1 && "Scale factor for expr that is not an array idx!");
}
Instruction *NCI = new CastInst(AddrSrc, AddOp1->getType());
ReplaceInstWithInst(BB->getInstList(), BI, NCI);
PRINT_PEEPHOLE2("add-to-gep:out", GEP, NCI);
return true;
}
// Peephole optimize the following instructions:
// %t1 = cast int (uint) * %reg111 to uint (...) *
// %t2 = call uint (...) * %cast111( uint %key )
@ -578,57 +750,10 @@ static bool PeepholeOptimize(BasicBlock *BB, BasicBlock::iterator &BI) {
} else if (I->getOpcode() == Instruction::Add &&
isa<CastInst>(I->getOperand(1))) {
// Peephole optimize the following instructions:
// %t1 = cast ulong <const int> to {<...>} *
// %t2 = add {<...>} * %SP, %t1 ;; Constant must be 2nd operand
//
// or
// %t1 = cast {<...>}* %SP to int*
// %t5 = cast ulong <const int> to int*
// %t2 = add int* %t1, %t5 ;; int is same size as field
//
// Into: %t3 = getelementptr {<...>} * %SP, <element indices>
// %t2 = cast <eltype> * %t3 to {<...>}*
//
Value *AddOp1 = I->getOperand(0);
CastInst *AddOp2 = cast<CastInst>(I->getOperand(1));
ConstPoolUInt *OffsetV = dyn_cast<ConstPoolUInt>(AddOp2->getOperand(0));
unsigned Offset = OffsetV ? OffsetV->getValue() : 0;
Value *SrcPtr; // Of type pointer to struct...
const StructType *StructTy;
if ((StructTy = getPointedToStruct(AddOp1->getType()))) {
SrcPtr = AddOp1; // Handle the first case...
} else if (CastInst *AddOp1c = dyn_cast<CastInst>(AddOp1)) {
SrcPtr = AddOp1c->getOperand(0); // Handle the second case...
StructTy = getPointedToStruct(SrcPtr->getType());
}
// Only proceed if we have detected all of our conditions successfully...
if (Offset && StructTy && SrcPtr && Offset < TD.getTypeSize(StructTy)) {
const StructLayout *SL = TD.getStructLayout(StructTy);
vector<ConstPoolVal*> Offsets;
unsigned ActualOffset = Offset;
const Type *ElTy = getStructOffsetType(StructTy, ActualOffset, Offsets);
if (getPointedToStruct(AddOp1->getType())) { // case 1
PRINT_PEEPHOLE2("add-to-gep1:in", AddOp2, I);
} else {
PRINT_PEEPHOLE3("add-to-gep2:in", AddOp1, AddOp2, I);
}
GetElementPtrInst *GEP = new GetElementPtrInst(SrcPtr, Offsets);
//AddOp2->getName());
BI = BB->getInstList().insert(BI, GEP)+1;
assert(Offset-ActualOffset == 0 &&
"GEP to middle of element not implemented yet!");
ReplaceInstWithInst(BB->getInstList(), BI,
I = new CastInst(GEP, I->getType()));
PRINT_PEEPHOLE2("add-to-gep:out", GEP, I);
if (PeepholeOptimizeAddCast(BB, BI, I->getOperand(0),
cast<CastInst>(I->getOperand(1))))
return true;
}
#endif
}

View File

@ -102,7 +102,7 @@ void ReplaceInstWithInst(BasicBlock::InstListType &BIL,
const Type *getStructOffsetType(const Type *Ty, unsigned &Offset,
vector<ConstPoolVal*> &Offsets,
bool StopEarly = true) {
if (!isa<StructType>(Ty) || (Offset == 0 && StopEarly)) {
if (!isa<StructType>(Ty) || (Offset == 0 && StopEarly && !Offsets.empty())) {
Offset = 0; // Return the offset that we were able to acheive
return Ty; // Return the leaf type
}