mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-19 19:29:31 +00:00
Fix the last of the major PPC GEP folding deficiencies. This will allow
the ISel to use indexed and non-zero immediate offsets for GEPs that have more than one use. This is common for instruction sequences such as a load followed by a modify and store to the same address. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16493 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ab5948f242
commit
645495d2e6
@ -32,8 +32,9 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Statistic<> NumSetCC("ppc-codegen", "Number of SetCC straight-lined");
|
Statistic<>
|
||||||
|
MultiUseGEP("ppc-codegen", "Number of GEPs folded with more than one use");
|
||||||
|
|
||||||
/// TypeClass - Used by the PowerPC backend to group LLVM types by their basic
|
/// TypeClass - Used by the PowerPC backend to group LLVM types by their basic
|
||||||
/// PPC Representation.
|
/// PPC Representation.
|
||||||
///
|
///
|
||||||
@ -79,13 +80,35 @@ namespace {
|
|||||||
MachineBasicBlock *BB; // The current MBB we are compiling
|
MachineBasicBlock *BB; // The current MBB we are compiling
|
||||||
int VarArgsFrameIndex; // FrameIndex for start of varargs area
|
int VarArgsFrameIndex; // FrameIndex for start of varargs area
|
||||||
|
|
||||||
std::map<Value*, unsigned> RegMap; // Mapping between Values and SSA Regs
|
/// CollapsedGepOp - This struct is for recording the intermediate results
|
||||||
|
/// used to calculate the base, index, and offset of a GEP instruction.
|
||||||
|
struct CollapsedGepOp {
|
||||||
|
ConstantSInt *offset; // the current offset into the struct/array
|
||||||
|
Value *index; // the index of the array element
|
||||||
|
ConstantUInt *size; // the size of each array element
|
||||||
|
CollapsedGepOp(ConstantSInt *o, Value *i, ConstantUInt *s) :
|
||||||
|
offset(o), index(i), size(s) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// FoldedGEP - This struct is for recording the necessary information to
|
||||||
|
/// emit the GEP in a load or store instruction, used by emitGEPOperation.
|
||||||
|
struct FoldedGEP {
|
||||||
|
unsigned base;
|
||||||
|
unsigned index;
|
||||||
|
ConstantSInt *offset;
|
||||||
|
FoldedGEP() : base(0), index(0), offset(0) {}
|
||||||
|
FoldedGEP(unsigned b, unsigned i, ConstantSInt *o) :
|
||||||
|
base(b), index(i), offset(o) {}
|
||||||
|
};
|
||||||
|
|
||||||
// External functions used in the Module
|
// External functions used in the Module
|
||||||
Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn,
|
Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn,
|
||||||
*__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn,
|
*__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn,
|
||||||
*__fixunsdfdiFn, *__floatdisfFn, *__floatdidfFn, *mallocFn, *freeFn;
|
*__fixunsdfdiFn, *__floatdisfFn, *__floatdidfFn, *mallocFn, *freeFn;
|
||||||
|
|
||||||
|
// Mapping between Values and SSA Regs
|
||||||
|
std::map<Value*, unsigned> RegMap;
|
||||||
|
|
||||||
// MBBMap - Mapping between LLVM BB -> Machine BB
|
// MBBMap - Mapping between LLVM BB -> Machine BB
|
||||||
std::map<const BasicBlock*, MachineBasicBlock*> MBBMap;
|
std::map<const BasicBlock*, MachineBasicBlock*> MBBMap;
|
||||||
|
|
||||||
@ -93,6 +116,9 @@ namespace {
|
|||||||
// FrameIndex for the alloca.
|
// FrameIndex for the alloca.
|
||||||
std::map<AllocaInst*, unsigned> AllocaMap;
|
std::map<AllocaInst*, unsigned> AllocaMap;
|
||||||
|
|
||||||
|
// GEPMap - Mapping between basic blocks and GEP definitions
|
||||||
|
std::map<GetElementPtrInst*, FoldedGEP> GEPMap;
|
||||||
|
|
||||||
// A Reg to hold the base address used for global loads and stores, and a
|
// A Reg to hold the base address used for global loads and stores, and a
|
||||||
// flag to set whether or not we need to emit it for this function.
|
// flag to set whether or not we need to emit it for this function.
|
||||||
unsigned GlobalBaseReg;
|
unsigned GlobalBaseReg;
|
||||||
@ -170,6 +196,7 @@ namespace {
|
|||||||
// Select the PHI nodes
|
// Select the PHI nodes
|
||||||
SelectPHINodes();
|
SelectPHINodes();
|
||||||
|
|
||||||
|
GEPMap.clear();
|
||||||
RegMap.clear();
|
RegMap.clear();
|
||||||
MBBMap.clear();
|
MBBMap.clear();
|
||||||
AllocaMap.clear();
|
AllocaMap.clear();
|
||||||
@ -222,15 +249,6 @@ namespace {
|
|||||||
ValueRecord(unsigned R, const Type *T) : Val(0), Reg(R), Ty(T) {}
|
ValueRecord(unsigned R, const Type *T) : Val(0), Reg(R), Ty(T) {}
|
||||||
ValueRecord(Value *V) : Val(V), Reg(0), Ty(V->getType()) {}
|
ValueRecord(Value *V) : Val(V), Reg(0), Ty(V->getType()) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This struct is for recording the necessary operations to emit the GEP
|
|
||||||
struct CollapsedGepOp {
|
|
||||||
bool isMul;
|
|
||||||
Value *index;
|
|
||||||
ConstantSInt *size;
|
|
||||||
CollapsedGepOp(bool mul, Value *i, ConstantSInt *s) :
|
|
||||||
isMul(mul), index(i), size(s) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
void doCall(const ValueRecord &Ret, MachineInstr *CallMI,
|
void doCall(const ValueRecord &Ret, MachineInstr *CallMI,
|
||||||
const std::vector<ValueRecord> &Args, bool isVarArg);
|
const std::vector<ValueRecord> &Args, bool isVarArg);
|
||||||
@ -292,10 +310,7 @@ namespace {
|
|||||||
/// constant expression GEP support.
|
/// constant expression GEP support.
|
||||||
///
|
///
|
||||||
void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP,
|
void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP,
|
||||||
Value *Src, User::op_iterator IdxBegin,
|
GetElementPtrInst *GEPI, bool foldGEP);
|
||||||
User::op_iterator IdxEnd, unsigned TargetReg,
|
|
||||||
bool CollapseRemainder, ConstantSInt **Remainder,
|
|
||||||
unsigned *PendingAddReg);
|
|
||||||
|
|
||||||
/// emitCastOperation - Common code shared between visitCastInst and
|
/// emitCastOperation - Common code shared between visitCastInst and
|
||||||
/// constant expression cast support.
|
/// constant expression cast support.
|
||||||
@ -377,6 +392,13 @@ namespace {
|
|||||||
void emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI,
|
void emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI,
|
||||||
unsigned LHS, unsigned RHS);
|
unsigned LHS, unsigned RHS);
|
||||||
|
|
||||||
|
/// emitAdd - A convenience function to emit the necessary code to add a
|
||||||
|
/// constant signed value to a register.
|
||||||
|
///
|
||||||
|
void emitAdd(MachineBasicBlock *MBB,
|
||||||
|
MachineBasicBlock::iterator IP,
|
||||||
|
unsigned Op0Reg, ConstantSInt *Op1, unsigned DestReg);
|
||||||
|
|
||||||
/// makeAnotherReg - This method returns the next register number we haven't
|
/// makeAnotherReg - This method returns the next register number we haven't
|
||||||
/// yet used.
|
/// yet used.
|
||||||
///
|
///
|
||||||
@ -905,26 +927,38 @@ static SetCondInst *canFoldSetCCIntoBranchOrSelect(Value *V) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// canFoldGEPIntoLoadOrStore - Return the GEP instruction if we can fold it into
|
// canFoldGEPIntoLoadOrStore - Return the GEP instruction if we can fold it into
|
||||||
// the load or store instruction that is the only user of the GEP.
|
// the load or store instruction that is the only user of the GEP.
|
||||||
//
|
//
|
||||||
static GetElementPtrInst *canFoldGEPIntoLoadOrStore(Value *V) {
|
static GetElementPtrInst *canFoldGEPIntoLoadOrStore(Value *V) {
|
||||||
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V))
|
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) {
|
||||||
if (GEPI->hasOneUse()) {
|
bool AllUsesAreMem = true;
|
||||||
Instruction *User = cast<Instruction>(GEPI->use_back());
|
for (Value::use_iterator I = GEPI->use_begin(), E = GEPI->use_end();
|
||||||
|
I != E; ++I) {
|
||||||
|
Instruction *User = cast<Instruction>(*I);
|
||||||
|
|
||||||
|
// If the GEP is the target of a store, but not the source, then we are ok
|
||||||
|
// to fold it.
|
||||||
if (isa<StoreInst>(User) &&
|
if (isa<StoreInst>(User) &&
|
||||||
GEPI->getParent() == User->getParent() &&
|
GEPI->getParent() == User->getParent() &&
|
||||||
User->getOperand(0) != GEPI &&
|
User->getOperand(0) != GEPI &&
|
||||||
User->getOperand(1) == GEPI) {
|
User->getOperand(1) == GEPI)
|
||||||
return GEPI;
|
continue;
|
||||||
}
|
|
||||||
|
// If the GEP is the source of a load, then we're always ok to fold it
|
||||||
if (isa<LoadInst>(User) &&
|
if (isa<LoadInst>(User) &&
|
||||||
GEPI->getParent() == User->getParent() &&
|
GEPI->getParent() == User->getParent() &&
|
||||||
User->getOperand(0) == GEPI) {
|
User->getOperand(0) == GEPI)
|
||||||
return GEPI;
|
continue;
|
||||||
}
|
|
||||||
|
// if we got to this point, than the instruction was not a load or store
|
||||||
|
// that we are capable of folding the GEP into.
|
||||||
|
AllUsesAreMem = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (AllUsesAreMem)
|
||||||
|
return GEPI;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,7 +1159,6 @@ void PPC32ISel::visitSetCondInst(SetCondInst &I) {
|
|||||||
ConstantInt *CI = dyn_cast<ConstantInt>(Op1);
|
ConstantInt *CI = dyn_cast<ConstantInt>(Op1);
|
||||||
|
|
||||||
if (CI && CI->getRawValue() == 0) {
|
if (CI && CI->getRawValue() == 0) {
|
||||||
++NumSetCC;
|
|
||||||
unsigned Op0Reg = ExtendOrClear(BB, MI, Op0);
|
unsigned Op0Reg = ExtendOrClear(BB, MI, Op0);
|
||||||
|
|
||||||
// comparisons against constant zero and negative one often have shorter
|
// comparisons against constant zero and negative one often have shorter
|
||||||
@ -1249,8 +1282,6 @@ void PPC32ISel::visitSelectInst(SelectInst &SI) {
|
|||||||
|
|
||||||
/// emitSelect - Common code shared between visitSelectInst and the constant
|
/// emitSelect - Common code shared between visitSelectInst and the constant
|
||||||
/// expression support.
|
/// expression support.
|
||||||
/// FIXME: this is most likely broken in one or more ways. Namely, PowerPC has
|
|
||||||
/// no select instruction. FSEL only works for comparisons against zero.
|
|
||||||
void PPC32ISel::emitSelectOperation(MachineBasicBlock *MBB,
|
void PPC32ISel::emitSelectOperation(MachineBasicBlock *MBB,
|
||||||
MachineBasicBlock::iterator IP,
|
MachineBasicBlock::iterator IP,
|
||||||
Value *Cond, Value *TrueVal,
|
Value *Cond, Value *TrueVal,
|
||||||
@ -2565,47 +2596,33 @@ void PPC32ISel::visitLoadInst(LoadInst &I) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this load is the only use of the GEP instruction that is its address,
|
// If the offset fits in 16 bits, we can emit a reg+imm load, otherwise, we
|
||||||
// then we can fold the GEP directly into the load instruction.
|
// use the index from the FoldedGEP struct and use reg+reg addressing.
|
||||||
// emitGEPOperation with a second to last arg of 'true' will place the
|
|
||||||
// base register for the GEP into baseReg, and the constant offset from that
|
|
||||||
// into offset. If the offset fits in 16 bits, we can emit a reg+imm store
|
|
||||||
// otherwise, we copy the offset into another reg, and use reg+reg addressing.
|
|
||||||
if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) {
|
if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) {
|
||||||
unsigned baseReg = getReg(GEPI);
|
|
||||||
unsigned pendingAdd;
|
|
||||||
ConstantSInt *offset;
|
|
||||||
|
|
||||||
emitGEPOperation(BB, BB->end(), GEPI->getOperand(0), GEPI->op_begin()+1,
|
|
||||||
GEPI->op_end(), baseReg, true, &offset, &pendingAdd);
|
|
||||||
|
|
||||||
if (pendingAdd == 0 && Class != cLong &&
|
// Generate the code for the GEP and get the components of the folded GEP
|
||||||
canUseAsImmediateForOpcode(offset, 0)) {
|
emitGEPOperation(BB, BB->end(), GEPI, true);
|
||||||
if (LoadNeedsSignExtend(I)) {
|
unsigned baseReg = GEPMap[GEPI].base;
|
||||||
unsigned TmpReg = makeAnotherReg(I.getType());
|
unsigned indexReg = GEPMap[GEPI].index;
|
||||||
|
ConstantSInt *offset = GEPMap[GEPI].offset;
|
||||||
|
|
||||||
|
if (Class != cLong) {
|
||||||
|
unsigned TmpReg = makeAnotherReg(I.getType());
|
||||||
|
if (indexReg == 0)
|
||||||
BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(offset->getValue())
|
BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(offset->getValue())
|
||||||
.addReg(baseReg);
|
.addReg(baseReg);
|
||||||
|
else
|
||||||
|
BuildMI(BB, IdxOpcode, 2, TmpReg).addReg(indexReg).addReg(baseReg);
|
||||||
|
if (LoadNeedsSignExtend(I))
|
||||||
BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg);
|
BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg);
|
||||||
} else {
|
else
|
||||||
BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(offset->getValue())
|
BuildMI(BB, PPC::OR, 2, DestReg).addReg(TmpReg).addReg(TmpReg);
|
||||||
.addReg(baseReg);
|
} else {
|
||||||
}
|
indexReg = (indexReg != 0) ? indexReg : getReg(offset);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned indexReg = (pendingAdd != 0) ? pendingAdd : getReg(offset);
|
|
||||||
|
|
||||||
if (Class == cLong) {
|
|
||||||
unsigned indexPlus4 = makeAnotherReg(Type::IntTy);
|
unsigned indexPlus4 = makeAnotherReg(Type::IntTy);
|
||||||
BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4);
|
BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4);
|
||||||
BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg);
|
BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg);
|
||||||
BuildMI(BB, IdxOpcode, 2, DestReg+1).addReg(indexPlus4).addReg(baseReg);
|
BuildMI(BB, IdxOpcode, 2, DestReg+1).addReg(indexPlus4).addReg(baseReg);
|
||||||
} else if (LoadNeedsSignExtend(I)) {
|
|
||||||
unsigned TmpReg = makeAnotherReg(I.getType());
|
|
||||||
BuildMI(BB, IdxOpcode, 2, TmpReg).addReg(indexReg).addReg(baseReg);
|
|
||||||
BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg);
|
|
||||||
} else {
|
|
||||||
BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2647,38 +2664,30 @@ void PPC32ISel::visitStoreInst(StoreInst &I) {
|
|||||||
unsigned IdxOpcode = IdxOpcodes[Class];
|
unsigned IdxOpcode = IdxOpcodes[Class];
|
||||||
unsigned ValReg = getReg(I.getOperand(0));
|
unsigned ValReg = getReg(I.getOperand(0));
|
||||||
|
|
||||||
// If this store is the only use of the GEP instruction that is its address,
|
// If the offset fits in 16 bits, we can emit a reg+imm store, otherwise, we
|
||||||
// then we can fold the GEP directly into the store instruction.
|
// use the index from the FoldedGEP struct and use reg+reg addressing.
|
||||||
// emitGEPOperation with a second to last arg of 'true' will place the
|
|
||||||
// base register for the GEP into baseReg, and the constant offset from that
|
|
||||||
// into offset. If the offset fits in 16 bits, we can emit a reg+imm store
|
|
||||||
// otherwise, we copy the offset into another reg, and use reg+reg addressing.
|
|
||||||
if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) {
|
if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) {
|
||||||
unsigned baseReg = getReg(GEPI);
|
// Generate the code for the GEP and get the components of the folded GEP
|
||||||
unsigned pendingAdd;
|
emitGEPOperation(BB, BB->end(), GEPI, true);
|
||||||
ConstantSInt *offset;
|
unsigned baseReg = GEPMap[GEPI].base;
|
||||||
|
unsigned indexReg = GEPMap[GEPI].index;
|
||||||
|
ConstantSInt *offset = GEPMap[GEPI].offset;
|
||||||
|
|
||||||
emitGEPOperation(BB, BB->end(), GEPI->getOperand(0), GEPI->op_begin()+1,
|
if (Class != cLong) {
|
||||||
GEPI->op_end(), baseReg, true, &offset, &pendingAdd);
|
if (indexReg == 0)
|
||||||
|
BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(offset->getValue())
|
||||||
if (0 == pendingAdd && Class != cLong &&
|
.addReg(baseReg);
|
||||||
canUseAsImmediateForOpcode(offset, 0)) {
|
else
|
||||||
BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(offset->getValue())
|
BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg)
|
||||||
.addReg(baseReg);
|
.addReg(baseReg);
|
||||||
return;
|
} else {
|
||||||
}
|
indexReg = (indexReg != 0) ? indexReg : getReg(offset);
|
||||||
|
|
||||||
unsigned indexReg = (pendingAdd != 0) ? pendingAdd : getReg(offset);
|
|
||||||
|
|
||||||
if (Class == cLong) {
|
|
||||||
unsigned indexPlus4 = makeAnotherReg(Type::IntTy);
|
unsigned indexPlus4 = makeAnotherReg(Type::IntTy);
|
||||||
BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4);
|
BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4);
|
||||||
BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg).addReg(baseReg);
|
BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg).addReg(baseReg);
|
||||||
BuildMI(BB, IdxOpcode, 3).addReg(ValReg+1).addReg(indexPlus4)
|
BuildMI(BB, IdxOpcode, 3).addReg(ValReg+1).addReg(indexPlus4)
|
||||||
.addReg(baseReg);
|
.addReg(baseReg);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg).addReg(baseReg);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3286,9 +3295,22 @@ void PPC32ISel::visitGetElementPtrInst(GetElementPtrInst &I) {
|
|||||||
if (canFoldGEPIntoLoadOrStore(&I))
|
if (canFoldGEPIntoLoadOrStore(&I))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned outputReg = getReg(I);
|
emitGEPOperation(BB, BB->end(), &I, false);
|
||||||
emitGEPOperation(BB, BB->end(), I.getOperand(0), I.op_begin()+1, I.op_end(),
|
}
|
||||||
outputReg, false, 0, 0);
|
|
||||||
|
/// emitAdd - A convenience function to emit the necessary code to add a
|
||||||
|
/// constant signed value to a register.
|
||||||
|
///
|
||||||
|
void PPC32ISel::emitAdd(MachineBasicBlock *MBB,
|
||||||
|
MachineBasicBlock::iterator IP,
|
||||||
|
unsigned Op0Reg, ConstantSInt *Op1, unsigned DestReg) {
|
||||||
|
if (canUseAsImmediateForOpcode(Op1, 0)) {
|
||||||
|
BuildMI(*MBB, IP, PPC::ADDI, 2, DestReg).addReg(Op0Reg)
|
||||||
|
.addSImm(Op1->getValue());
|
||||||
|
} else {
|
||||||
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
||||||
|
BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Op0Reg).addReg(Op1Reg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emitGEPOperation - Common code shared between visitGetElementPtrInst and
|
/// emitGEPOperation - Common code shared between visitGetElementPtrInst and
|
||||||
@ -3296,13 +3318,19 @@ void PPC32ISel::visitGetElementPtrInst(GetElementPtrInst &I) {
|
|||||||
///
|
///
|
||||||
void PPC32ISel::emitGEPOperation(MachineBasicBlock *MBB,
|
void PPC32ISel::emitGEPOperation(MachineBasicBlock *MBB,
|
||||||
MachineBasicBlock::iterator IP,
|
MachineBasicBlock::iterator IP,
|
||||||
Value *Src, User::op_iterator IdxBegin,
|
GetElementPtrInst *GEPI, bool GEPIsFolded) {
|
||||||
User::op_iterator IdxEnd, unsigned TargetReg,
|
// If we've already emitted this particular GEP, just return to avoid
|
||||||
bool GEPIsFolded, ConstantSInt **RemainderPtr,
|
// multiple definitions of the base register.
|
||||||
unsigned *PendingAddReg) {
|
if (GEPIsFolded && (GEPMap[GEPI].base != 0)) {
|
||||||
|
MultiUseGEP++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *Src = GEPI->getOperand(0);
|
||||||
|
User::op_iterator IdxBegin = GEPI->op_begin()+1;
|
||||||
|
User::op_iterator IdxEnd = GEPI->op_end();
|
||||||
const TargetData &TD = TM.getTargetData();
|
const TargetData &TD = TM.getTargetData();
|
||||||
const Type *Ty = Src->getType();
|
const Type *Ty = Src->getType();
|
||||||
unsigned basePtrReg = getReg(Src, MBB, IP);
|
|
||||||
int64_t constValue = 0;
|
int64_t constValue = 0;
|
||||||
|
|
||||||
// Record the operations to emit the GEP in a vector so that we can emit them
|
// Record the operations to emit the GEP in a vector so that we can emit them
|
||||||
@ -3322,17 +3350,14 @@ void PPC32ISel::emitGEPOperation(MachineBasicBlock *MBB,
|
|||||||
// right byte offset from the StructLayout class's list of
|
// right byte offset from the StructLayout class's list of
|
||||||
// structure member offsets.
|
// structure member offsets.
|
||||||
unsigned fieldIndex = cast<ConstantUInt>(idx)->getValue();
|
unsigned fieldIndex = cast<ConstantUInt>(idx)->getValue();
|
||||||
unsigned memberOffset =
|
|
||||||
TD.getStructLayout(StTy)->MemberOffsets[fieldIndex];
|
|
||||||
|
|
||||||
// StructType member offsets are always constant values. Add it to the
|
// StructType member offsets are always constant values. Add it to the
|
||||||
// running total.
|
// running total.
|
||||||
constValue += memberOffset;
|
constValue += TD.getStructLayout(StTy)->MemberOffsets[fieldIndex];
|
||||||
|
|
||||||
// The next type is the member of the structure selected by the
|
// The next type is the member of the structure selected by the index.
|
||||||
// index.
|
|
||||||
Ty = StTy->getElementType (fieldIndex);
|
Ty = StTy->getElementType (fieldIndex);
|
||||||
} else if (const SequentialType *SqTy = dyn_cast<SequentialType> (Ty)) {
|
} else if (const SequentialType *SqTy = dyn_cast<SequentialType>(Ty)) {
|
||||||
// Many GEP instructions use a [cast (int/uint) to LongTy] as their
|
// Many GEP instructions use a [cast (int/uint) to LongTy] as their
|
||||||
// operand. Handle this case directly now...
|
// operand. Handle this case directly now...
|
||||||
if (CastInst *CI = dyn_cast<CastInst>(idx))
|
if (CastInst *CI = dyn_cast<CastInst>(idx))
|
||||||
@ -3355,111 +3380,71 @@ void PPC32ISel::emitGEPOperation(MachineBasicBlock *MBB,
|
|||||||
else
|
else
|
||||||
assert(0 && "Invalid ConstantInt GEP index type!");
|
assert(0 && "Invalid ConstantInt GEP index type!");
|
||||||
} else {
|
} else {
|
||||||
// Push current gep state to this point as an add
|
// Push current gep state to this point as an add and multiply
|
||||||
ops.push_back(CollapsedGepOp(false, 0,
|
ops.push_back(CollapsedGepOp(
|
||||||
ConstantSInt::get(Type::IntTy,constValue)));
|
ConstantSInt::get(Type::IntTy, constValue),
|
||||||
|
idx, ConstantUInt::get(Type::UIntTy, elementSize)));
|
||||||
// Push multiply gep op and reset constant value
|
|
||||||
ops.push_back(CollapsedGepOp(true, idx,
|
|
||||||
ConstantSInt::get(Type::IntTy, elementSize)));
|
|
||||||
|
|
||||||
constValue = 0;
|
constValue = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Emit instructions for all the collapsed ops
|
// Emit instructions for all the collapsed ops
|
||||||
bool pendingAdd = false;
|
unsigned indexReg = 0;
|
||||||
unsigned pendingAddReg = 0;
|
|
||||||
|
|
||||||
for(std::vector<CollapsedGepOp>::iterator cgo_i = ops.begin(),
|
for(std::vector<CollapsedGepOp>::iterator cgo_i = ops.begin(),
|
||||||
cgo_e = ops.end(); cgo_i != cgo_e; ++cgo_i) {
|
cgo_e = ops.end(); cgo_i != cgo_e; ++cgo_i) {
|
||||||
CollapsedGepOp& cgo = *cgo_i;
|
CollapsedGepOp& cgo = *cgo_i;
|
||||||
unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy);
|
|
||||||
|
|
||||||
// If we didn't emit an add last time through the loop, we need to now so
|
|
||||||
// that the base reg is updated appropriately.
|
|
||||||
if (pendingAdd) {
|
|
||||||
assert(pendingAddReg != 0 && "Uninitialized register in pending add!");
|
|
||||||
BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg)
|
|
||||||
.addReg(pendingAddReg);
|
|
||||||
basePtrReg = nextBasePtrReg;
|
|
||||||
nextBasePtrReg = makeAnotherReg(Type::IntTy);
|
|
||||||
pendingAddReg = 0;
|
|
||||||
pendingAdd = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cgo.isMul) {
|
unsigned TmpReg1 = makeAnotherReg(Type::IntTy);
|
||||||
// We know the elementSize is a constant, so we can emit a constant mul
|
unsigned TmpReg2 = makeAnotherReg(Type::IntTy);
|
||||||
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
doMultiplyConst(MBB, IP, TmpReg1, cgo.index, cgo.size);
|
||||||
doMultiplyConst(MBB, IP, nextBasePtrReg, cgo.index, cgo.size);
|
emitAdd(MBB, IP, TmpReg1, cgo.offset, TmpReg2);
|
||||||
pendingAddReg = basePtrReg;
|
|
||||||
pendingAdd = true;
|
if (indexReg == 0)
|
||||||
} else {
|
indexReg = TmpReg2;
|
||||||
// Try and generate an immediate addition if possible
|
else {
|
||||||
if (cgo.size->isNullValue()) {
|
unsigned TmpReg3 = makeAnotherReg(Type::IntTy);
|
||||||
BuildMI(*MBB, IP, PPC::OR, 2, nextBasePtrReg).addReg(basePtrReg)
|
BuildMI(*MBB, IP, PPC::ADD, 2, TmpReg3).addReg(indexReg).addReg(TmpReg2);
|
||||||
.addReg(basePtrReg);
|
indexReg = TmpReg3;
|
||||||
} else if (canUseAsImmediateForOpcode(cgo.size, 0)) {
|
|
||||||
BuildMI(*MBB, IP, PPC::ADDI, 2, nextBasePtrReg).addReg(basePtrReg)
|
|
||||||
.addSImm(cgo.size->getValue());
|
|
||||||
} else {
|
|
||||||
unsigned Op1r = getReg(cgo.size, MBB, IP);
|
|
||||||
BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg)
|
|
||||||
.addReg(Op1r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
basePtrReg = nextBasePtrReg;
|
|
||||||
}
|
}
|
||||||
// Add the current base register plus any accumulated constant value
|
|
||||||
|
// We now have a base register, an index register, and possibly a constant
|
||||||
|
// remainder. If the GEP is going to be folded, we try to generate the
|
||||||
|
// optimal addressing mode.
|
||||||
|
unsigned TargetReg = getReg(GEPI, MBB, IP);
|
||||||
|
unsigned basePtrReg = getReg(Src, MBB, IP);
|
||||||
ConstantSInt *remainder = ConstantSInt::get(Type::IntTy, constValue);
|
ConstantSInt *remainder = ConstantSInt::get(Type::IntTy, constValue);
|
||||||
|
|
||||||
// If we are emitting this during a fold, copy the current base register to
|
// If we are emitting this during a fold, copy the current base register to
|
||||||
// the target, and save the current constant offset so the folding load or
|
// the target, and save the current constant offset so the folding load or
|
||||||
// store can try and use it as an immediate.
|
// store can try and use it as an immediate.
|
||||||
if (GEPIsFolded) {
|
if (GEPIsFolded) {
|
||||||
// If this is a folded GEP and the last element was an index, then we need
|
if (indexReg == 0) {
|
||||||
// to do some extra work to turn a shift/add/stw into a shift/stwx
|
if (!canUseAsImmediateForOpcode(remainder, 0)) {
|
||||||
if (pendingAdd && 0 == remainder->getValue()) {
|
indexReg = getReg(remainder, MBB, IP);
|
||||||
assert(pendingAddReg != 0 && "Uninitialized register in pending add!");
|
remainder = 0;
|
||||||
*PendingAddReg = pendingAddReg;
|
|
||||||
} else {
|
|
||||||
*PendingAddReg = 0;
|
|
||||||
if (pendingAdd) {
|
|
||||||
unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy);
|
|
||||||
assert(pendingAddReg != 0 && "Uninitialized register in pending add!");
|
|
||||||
BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg)
|
|
||||||
.addReg(pendingAddReg);
|
|
||||||
basePtrReg = nextBasePtrReg;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
||||||
|
emitAdd(MBB, IP, indexReg, remainder, TmpReg);
|
||||||
|
indexReg = TmpReg;
|
||||||
|
remainder = 0;
|
||||||
}
|
}
|
||||||
BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg)
|
BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg)
|
||||||
.addReg(basePtrReg);
|
.addReg(basePtrReg);
|
||||||
*RemainderPtr = remainder;
|
GEPMap[GEPI] = FoldedGEP(TargetReg, indexReg, remainder);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we still have a pending add at this point, emit it now
|
// We're not folding, so collapse the base, index, and any remainder into the
|
||||||
if (pendingAdd) {
|
// destination register.
|
||||||
|
if (indexReg != 0) {
|
||||||
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
||||||
BuildMI(*MBB, IP, PPC::ADD, 2, TmpReg).addReg(pendingAddReg)
|
BuildMI(*MBB, IP, PPC::ADD, 2, TmpReg).addReg(indexReg).addReg(basePtrReg);
|
||||||
.addReg(basePtrReg);
|
|
||||||
basePtrReg = TmpReg;
|
basePtrReg = TmpReg;
|
||||||
}
|
}
|
||||||
|
emitAdd(MBB, IP, basePtrReg, remainder, TargetReg);
|
||||||
// After we have processed all the indices, the result is left in
|
|
||||||
// basePtrReg. Move it to the register where we were expected to
|
|
||||||
// put the answer.
|
|
||||||
if (remainder->isNullValue()) {
|
|
||||||
BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg)
|
|
||||||
.addReg(basePtrReg);
|
|
||||||
} else if (canUseAsImmediateForOpcode(remainder, 0)) {
|
|
||||||
BuildMI(*MBB, IP, PPC::ADDI, 2, TargetReg).addReg(basePtrReg)
|
|
||||||
.addSImm(remainder->getValue());
|
|
||||||
} else {
|
|
||||||
unsigned Op1r = getReg(remainder, MBB, IP);
|
|
||||||
BuildMI(*MBB, IP, PPC::ADD, 2, TargetReg).addReg(basePtrReg).addReg(Op1r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// visitAllocaInst - If this is a fixed size alloca, allocate space from the
|
/// visitAllocaInst - If this is a fixed size alloca, allocate space from the
|
||||||
|
Loading…
Reference in New Issue
Block a user