add an inefficient way of folding structure and constant array indexes together

into a single LEA instruction.  This should improve the code generated for
things like X->A.B.C[12].D.

The bigger benefit is still coming though.  Note that this uses an LEA instruction
instead of an add, giving the register allocator more freedom.  We should probably
never generate ADDri32's.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11817 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2004-02-25 03:45:50 +00:00
parent 5a83096d6a
commit 985fe3df6f
2 changed files with 180 additions and 44 deletions

View File

@ -2308,6 +2308,76 @@ void ISel::visitGetElementPtrInst(GetElementPtrInst &I) {
I.op_begin()+1, I.op_end(), outputReg);
}
/// getGEPIndex - Inspect the getelementptr operands specified with GEPOps and
/// GEPTypes (the derived types being stepped through at each level). On return
/// from this function, if some indexes of the instruction are representable as
/// an X86 lea instruction, the machine operands are put into the Ops
/// instruction and the consumed indexes are poped from the GEPOps/GEPTypes
/// lists. Otherwise, GEPOps.size() is returned. If this returns a an
/// addressing mode that only partially consumes the input, the BaseReg input of
/// the addressing mode must be left free.
///
/// Note that there is one fewer entry in GEPTypes than there is in GEPOps.
///
static void getGEPIndex(std::vector<Value*> &GEPOps,
std::vector<const Type*> &GEPTypes,
MachineInstr *Ops, const TargetData &TD){
// Clear out the state we are working with...
Ops->getOperand(0).setReg(0); // No base register
Ops->getOperand(1).setImmedValue(1); // Unit scale
Ops->getOperand(2).setReg(0); // No index register
Ops->getOperand(3).setImmedValue(0); // No displacement
// While there are GEP indexes that can be folded into the current address,
// keep processing them.
while (!GEPTypes.empty()) {
if (const StructType *StTy = dyn_cast<StructType>(GEPTypes.back())) {
// It's a struct access. CUI is the index into the structure,
// which names the field. This index must have unsigned type.
const ConstantUInt *CUI = cast<ConstantUInt>(GEPOps.back());
// Use the TargetData structure to pick out what the layout of the
// structure is in memory. Since the structure index must be constant, we
// can get its value and use it to find the right byte offset from the
// StructLayout class's list of structure member offsets.
unsigned idxValue = CUI->getValue();
unsigned FieldOff = TD.getStructLayout(StTy)->MemberOffsets[idxValue];
if (FieldOff) {
if (Ops->getOperand(2).getReg())
return; // Already has an index, can't add offset.
Ops->getOperand(3).setImmedValue(FieldOff+
Ops->getOperand(3).getImmedValue());
}
GEPOps.pop_back(); // Consume a GEP operand
GEPTypes.pop_back();
} else {
// It's an array or pointer access: [ArraySize x ElementType].
const SequentialType *SqTy = cast<SequentialType>(GEPTypes.back());
Value *idx = GEPOps.back();
// idx is the index into the array. Unlike with structure
// indices, we may not know its actual value at code-generation
// time.
assert(idx->getType() == Type::LongTy && "Bad GEP array index!");
// If idx is a constant, fold it into the offset.
if (ConstantSInt *CSI = dyn_cast<ConstantSInt>(idx)) {
unsigned elementSize = TD.getTypeSize(SqTy->getElementType());
unsigned Offset = elementSize*CSI->getValue();
Ops->getOperand(3).setImmedValue(Offset+
Ops->getOperand(3).getImmedValue());
} else {
// If we can't handle it, return.
return;
}
GEPOps.pop_back(); // Consume a GEP operand
GEPTypes.pop_back();
}
}
}
void ISel::emitGEPOperation(MachineBasicBlock *MBB,
MachineBasicBlock::iterator IP,
Value *Src, User::op_iterator IdxBegin,
@ -2326,11 +2396,28 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
GEPTypes.assign(gep_type_begin(Src->getType(), IdxBegin, IdxEnd),
gep_type_end(Src->getType(), IdxBegin, IdxEnd));
// DummyMI - A dummy instruction to pass into getGEPIndex. The opcode doesn't
// matter, we just need 4 MachineOperands.
MachineInstr *DummyMI =
BuildMI(X86::PHI, 4).addReg(0).addZImm(1).addReg(0).addSImm(0);
// Keep emitting instructions until we consume the entire GEP instruction.
while (!GEPOps.empty()) {
unsigned OldSize = GEPOps.size();
getGEPIndex(GEPOps, GEPTypes, DummyMI, TD);
if (GEPTypes.empty()) {
if (GEPOps.size() != OldSize) {
// getGEPIndex consumed some of the input. Build an LEA instruction here.
assert(DummyMI->getOperand(0).getReg() == 0 &&
DummyMI->getOperand(1).getImmedValue() == 1 &&
DummyMI->getOperand(2).getReg() == 0 &&
"Unhandled GEP fold!");
if (unsigned Offset = DummyMI->getOperand(3).getImmedValue()) {
unsigned Reg = makeAnotherReg(Type::UIntTy);
addRegOffset(BMI(MBB, IP, X86::LEAr32, 5, TargetReg), Reg, Offset);
TargetReg = Reg;
}
} else if (GEPTypes.empty()) {
// The getGEPIndex operation didn't want to build an LEA. Check to see if
// all operands are consumed but the base pointer. If so, just load it
// into the register.
@ -2341,27 +2428,6 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
BMI(MBB, IP, X86::MOVrr32, 1, TargetReg).addReg(BaseReg);
}
break; // we are now done
} else if (const StructType *StTy = dyn_cast<StructType>(GEPTypes.back())) {
// It's a struct access. CUI is the index into the structure,
// which names the field. This index must have unsigned type.
const ConstantUInt *CUI = cast<ConstantUInt>(GEPOps.back());
GEPOps.pop_back(); // Consume a GEP operand
GEPTypes.pop_back();
// Use the TargetData structure to pick out what the layout of the
// structure is in memory. Since the structure index must be constant, we
// can get its value and use it to find the right byte offset from the
// StructLayout class's list of structure member offsets.
unsigned idxValue = CUI->getValue();
unsigned FieldOff = TD.getStructLayout(StTy)->MemberOffsets[idxValue];
if (FieldOff) {
unsigned Reg = makeAnotherReg(Type::UIntTy);
// Emit an ADD to add FieldOff to the basePtr.
BMI(MBB, IP, X86::ADDri32, 2, TargetReg).addReg(Reg).addZImm(FieldOff);
--IP; // Insert the next instruction before this one.
TargetReg = Reg; // Codegen the rest of the GEP into this
}
} else {
// It's an array or pointer access: [ArraySize x ElementType].
const SequentialType *SqTy = cast<SequentialType>(GEPTypes.back());
@ -2430,6 +2496,8 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
}
}
}
delete DummyMI;
}

View File

@ -2308,6 +2308,76 @@ void ISel::visitGetElementPtrInst(GetElementPtrInst &I) {
I.op_begin()+1, I.op_end(), outputReg);
}
/// getGEPIndex - Inspect the getelementptr operands specified with GEPOps and
/// GEPTypes (the derived types being stepped through at each level). On return
/// from this function, if some indexes of the instruction are representable as
/// an X86 lea instruction, the machine operands are put into the Ops
/// instruction and the consumed indexes are poped from the GEPOps/GEPTypes
/// lists. Otherwise, GEPOps.size() is returned. If this returns a an
/// addressing mode that only partially consumes the input, the BaseReg input of
/// the addressing mode must be left free.
///
/// Note that there is one fewer entry in GEPTypes than there is in GEPOps.
///
static void getGEPIndex(std::vector<Value*> &GEPOps,
std::vector<const Type*> &GEPTypes,
MachineInstr *Ops, const TargetData &TD){
// Clear out the state we are working with...
Ops->getOperand(0).setReg(0); // No base register
Ops->getOperand(1).setImmedValue(1); // Unit scale
Ops->getOperand(2).setReg(0); // No index register
Ops->getOperand(3).setImmedValue(0); // No displacement
// While there are GEP indexes that can be folded into the current address,
// keep processing them.
while (!GEPTypes.empty()) {
if (const StructType *StTy = dyn_cast<StructType>(GEPTypes.back())) {
// It's a struct access. CUI is the index into the structure,
// which names the field. This index must have unsigned type.
const ConstantUInt *CUI = cast<ConstantUInt>(GEPOps.back());
// Use the TargetData structure to pick out what the layout of the
// structure is in memory. Since the structure index must be constant, we
// can get its value and use it to find the right byte offset from the
// StructLayout class's list of structure member offsets.
unsigned idxValue = CUI->getValue();
unsigned FieldOff = TD.getStructLayout(StTy)->MemberOffsets[idxValue];
if (FieldOff) {
if (Ops->getOperand(2).getReg())
return; // Already has an index, can't add offset.
Ops->getOperand(3).setImmedValue(FieldOff+
Ops->getOperand(3).getImmedValue());
}
GEPOps.pop_back(); // Consume a GEP operand
GEPTypes.pop_back();
} else {
// It's an array or pointer access: [ArraySize x ElementType].
const SequentialType *SqTy = cast<SequentialType>(GEPTypes.back());
Value *idx = GEPOps.back();
// idx is the index into the array. Unlike with structure
// indices, we may not know its actual value at code-generation
// time.
assert(idx->getType() == Type::LongTy && "Bad GEP array index!");
// If idx is a constant, fold it into the offset.
if (ConstantSInt *CSI = dyn_cast<ConstantSInt>(idx)) {
unsigned elementSize = TD.getTypeSize(SqTy->getElementType());
unsigned Offset = elementSize*CSI->getValue();
Ops->getOperand(3).setImmedValue(Offset+
Ops->getOperand(3).getImmedValue());
} else {
// If we can't handle it, return.
return;
}
GEPOps.pop_back(); // Consume a GEP operand
GEPTypes.pop_back();
}
}
}
void ISel::emitGEPOperation(MachineBasicBlock *MBB,
MachineBasicBlock::iterator IP,
Value *Src, User::op_iterator IdxBegin,
@ -2326,11 +2396,28 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
GEPTypes.assign(gep_type_begin(Src->getType(), IdxBegin, IdxEnd),
gep_type_end(Src->getType(), IdxBegin, IdxEnd));
// DummyMI - A dummy instruction to pass into getGEPIndex. The opcode doesn't
// matter, we just need 4 MachineOperands.
MachineInstr *DummyMI =
BuildMI(X86::PHI, 4).addReg(0).addZImm(1).addReg(0).addSImm(0);
// Keep emitting instructions until we consume the entire GEP instruction.
while (!GEPOps.empty()) {
unsigned OldSize = GEPOps.size();
getGEPIndex(GEPOps, GEPTypes, DummyMI, TD);
if (GEPTypes.empty()) {
if (GEPOps.size() != OldSize) {
// getGEPIndex consumed some of the input. Build an LEA instruction here.
assert(DummyMI->getOperand(0).getReg() == 0 &&
DummyMI->getOperand(1).getImmedValue() == 1 &&
DummyMI->getOperand(2).getReg() == 0 &&
"Unhandled GEP fold!");
if (unsigned Offset = DummyMI->getOperand(3).getImmedValue()) {
unsigned Reg = makeAnotherReg(Type::UIntTy);
addRegOffset(BMI(MBB, IP, X86::LEAr32, 5, TargetReg), Reg, Offset);
TargetReg = Reg;
}
} else if (GEPTypes.empty()) {
// The getGEPIndex operation didn't want to build an LEA. Check to see if
// all operands are consumed but the base pointer. If so, just load it
// into the register.
@ -2341,27 +2428,6 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
BMI(MBB, IP, X86::MOVrr32, 1, TargetReg).addReg(BaseReg);
}
break; // we are now done
} else if (const StructType *StTy = dyn_cast<StructType>(GEPTypes.back())) {
// It's a struct access. CUI is the index into the structure,
// which names the field. This index must have unsigned type.
const ConstantUInt *CUI = cast<ConstantUInt>(GEPOps.back());
GEPOps.pop_back(); // Consume a GEP operand
GEPTypes.pop_back();
// Use the TargetData structure to pick out what the layout of the
// structure is in memory. Since the structure index must be constant, we
// can get its value and use it to find the right byte offset from the
// StructLayout class's list of structure member offsets.
unsigned idxValue = CUI->getValue();
unsigned FieldOff = TD.getStructLayout(StTy)->MemberOffsets[idxValue];
if (FieldOff) {
unsigned Reg = makeAnotherReg(Type::UIntTy);
// Emit an ADD to add FieldOff to the basePtr.
BMI(MBB, IP, X86::ADDri32, 2, TargetReg).addReg(Reg).addZImm(FieldOff);
--IP; // Insert the next instruction before this one.
TargetReg = Reg; // Codegen the rest of the GEP into this
}
} else {
// It's an array or pointer access: [ArraySize x ElementType].
const SequentialType *SqTy = cast<SequentialType>(GEPTypes.back());
@ -2430,6 +2496,8 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
}
}
}
delete DummyMI;
}