forked from OSchip/llvm-project
* Use the new Abstract Frame Manager to handle incoming arguments and
fixed size allocas * Revamp call emission to work with new frame manager llvm-svn: 5178
This commit is contained in:
parent
d47aac9d4b
commit
51553e0700
|
@ -20,6 +20,7 @@
|
|||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/SSARegMap.h"
|
||||
#include "llvm/CodeGen/FunctionFrameInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/InstVisitor.h"
|
||||
#include "llvm/Target/MRegisterInfo.h"
|
||||
|
@ -73,29 +74,12 @@ namespace {
|
|||
bool runOnFunction(Function &Fn) {
|
||||
F = &MachineFunction::construct(&Fn, TM);
|
||||
|
||||
// Create all of the machine basic blocks for the function...
|
||||
for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
|
||||
F->getBasicBlockList().push_back(MBBMap[I] = new MachineBasicBlock(I));
|
||||
|
||||
// Emit instructions to load the arguments... The function's arguments
|
||||
// look like this:
|
||||
//
|
||||
// [EBP] -- copy of old EBP
|
||||
// [EBP + 4] -- return address
|
||||
// [EBP + 8] -- first argument (leftmost lexically)
|
||||
//
|
||||
// So we want to start with counter = 2.
|
||||
//
|
||||
BB = &F->front();
|
||||
unsigned ArgOffset = 8;
|
||||
for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E;
|
||||
++I, ArgOffset += 4) {
|
||||
unsigned Reg = getReg(*I);
|
||||
|
||||
// Load it out of the stack frame at EBP + 4*argPos.
|
||||
|
||||
// FIXME: This should load the argument of the appropriate size!!
|
||||
addRegOffset(BuildMI(BB, X86::MOVmr32, 4, Reg), X86::EBP, ArgOffset);
|
||||
}
|
||||
LoadArgumentsToVirtualRegs(Fn);
|
||||
|
||||
// Instruction select everything except PHI nodes
|
||||
visit(Fn);
|
||||
|
@ -123,6 +107,10 @@ namespace {
|
|||
BB = MBBMap[&LLVM_BB];
|
||||
}
|
||||
|
||||
/// LoadArgumentsToVirtualRegs - Load all of the arguments to this function
|
||||
/// from the stack into virtual registers.
|
||||
///
|
||||
void LoadArgumentsToVirtualRegs(Function &F);
|
||||
|
||||
/// SelectPHINodes - Insert machine code to generate phis. This is tricky
|
||||
/// because we have to generate our sources into the source basic blocks,
|
||||
|
@ -170,10 +158,13 @@ namespace {
|
|||
void visitLoadInst(LoadInst &I);
|
||||
void visitStoreInst(StoreInst &I);
|
||||
void visitGetElementPtrInst(GetElementPtrInst &I);
|
||||
void visitMallocInst(MallocInst &I);
|
||||
void visitFreeInst(FreeInst &I);
|
||||
void visitAllocaInst(AllocaInst &I);
|
||||
|
||||
// We assume that by this point, malloc instructions have been
|
||||
// lowered to calls, and dlsym will magically find malloc for us.
|
||||
void visitMallocInst(MallocInst &I) { visitInstruction (I); }
|
||||
void visitFreeInst(FreeInst &I) { visitInstruction(I); }
|
||||
|
||||
// Other operators
|
||||
void visitShiftInst(ShiftInst &I);
|
||||
void visitPHINode(PHINode &I) {} // PHI nodes handled by second pass
|
||||
|
@ -341,6 +332,59 @@ void ISel::copyConstantToRegister(MachineBasicBlock *MBB,
|
|||
}
|
||||
}
|
||||
|
||||
/// LoadArgumentsToVirtualRegs - Load all of the arguments to this function from
|
||||
/// the stack into virtual registers.
|
||||
///
|
||||
void ISel::LoadArgumentsToVirtualRegs(Function &Fn) {
|
||||
// Emit instructions to load the arguments... On entry to a function on the
|
||||
// X86, the stack frame looks like this:
|
||||
//
|
||||
// [ESP] -- return address
|
||||
// [ESP + 4] -- first argument (leftmost lexically) if four bytes in size
|
||||
// [ESP + 8] -- second argument, if four bytes in size
|
||||
// ...
|
||||
//
|
||||
unsigned ArgOffset = 0;
|
||||
FunctionFrameInfo *FFI = F->getFrameInfo();
|
||||
|
||||
for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) {
|
||||
unsigned Reg = getReg(*I);
|
||||
|
||||
ArgOffset += 4; // Each argument takes at least 4 bytes on the stack...
|
||||
int FI; // Frame object index
|
||||
|
||||
switch (getClassB(I->getType())) {
|
||||
case cByte:
|
||||
FI = FFI->CreateFixedObject(1, ArgOffset);
|
||||
addFrameReference(BuildMI(BB, X86::MOVmr8, 4, Reg), FI);
|
||||
break;
|
||||
case cShort:
|
||||
FI = FFI->CreateFixedObject(2, ArgOffset);
|
||||
addFrameReference(BuildMI(BB, X86::MOVmr16, 4, Reg), FI);
|
||||
break;
|
||||
case cInt:
|
||||
FI = FFI->CreateFixedObject(4, ArgOffset);
|
||||
addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg), FI);
|
||||
break;
|
||||
case cFP:
|
||||
unsigned Opcode;
|
||||
if (I->getType() == Type::FloatTy) {
|
||||
Opcode = X86::FLDr32;
|
||||
FI = FFI->CreateFixedObject(4, ArgOffset);
|
||||
} else {
|
||||
Opcode = X86::FLDr64;
|
||||
ArgOffset += 4; // doubles require 4 additional bytes
|
||||
FI = FFI->CreateFixedObject(8, ArgOffset);
|
||||
}
|
||||
addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unhandled argument type!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// SelectPHINodes - Insert machine code to generate phis. This is tricky
|
||||
/// because we have to generate our sources into the source basic blocks, not
|
||||
/// the current one.
|
||||
|
@ -366,7 +410,8 @@ void ISel::SelectPHINodes() {
|
|||
// available in a virtual register, insert the computation code into
|
||||
// PredMBB
|
||||
//
|
||||
|
||||
// FIXME: This should insert the code into the BOTTOM of the block, not
|
||||
// the top of the block. This just makes for huge live ranges...
|
||||
MachineBasicBlock::iterator PI = PredMBB->begin();
|
||||
while ((*PI)->getOpcode() == X86::PHI) ++PI;
|
||||
|
||||
|
@ -532,7 +577,7 @@ void ISel::visitBranchInst(BranchInst &BI) {
|
|||
|
||||
// Compare condition with zero, followed by jump-if-equal to ifFalse, and
|
||||
// jump-if-nonequal to ifTrue
|
||||
unsigned int condReg = getReg(BI.getCondition());
|
||||
unsigned condReg = getReg(BI.getCondition());
|
||||
BuildMI(BB, X86::CMPri8, 2).addReg(condReg).addZImm(0);
|
||||
BuildMI(BB, X86::JNE, 1).addPCDisp(BI.getSuccessor(0));
|
||||
BuildMI(BB, X86::JE, 1).addPCDisp(BI.getSuccessor(1));
|
||||
|
@ -543,33 +588,65 @@ void ISel::visitBranchInst(BranchInst &BI) {
|
|||
|
||||
/// visitCallInst - Push args on stack and do a procedure call instruction.
|
||||
void ISel::visitCallInst(CallInst &CI) {
|
||||
// keep a counter of how many bytes we pushed on the stack
|
||||
unsigned bytesPushed = 0;
|
||||
// Count how many bytes are to be pushed on the stack...
|
||||
unsigned NumBytes = 0;
|
||||
|
||||
// Push the arguments on the stack in reverse order, as specified by
|
||||
// the ABI.
|
||||
for (unsigned i = CI.getNumOperands()-1; i >= 1; --i) {
|
||||
Value *v = CI.getOperand(i);
|
||||
switch (getClass(v->getType())) {
|
||||
case cByte:
|
||||
case cShort:
|
||||
// Promote V to 32 bits wide, and move the result into EAX,
|
||||
// then push EAX.
|
||||
promote32 (X86::EAX, v);
|
||||
BuildMI(BB, X86::PUSHr32, 1).addReg(X86::EAX);
|
||||
bytesPushed += 4;
|
||||
if (CI.getNumOperands() > 1) {
|
||||
for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i)
|
||||
switch (getClass(CI.getOperand(i)->getType())) {
|
||||
case cByte: case cShort: case cInt:
|
||||
NumBytes += 4;
|
||||
break;
|
||||
case cInt: {
|
||||
unsigned Reg = getReg(v);
|
||||
BuildMI(BB, X86::PUSHr32, 1).addReg(Reg);
|
||||
bytesPushed += 4;
|
||||
case cLong:
|
||||
NumBytes += 8;
|
||||
break;
|
||||
case cFP:
|
||||
NumBytes += CI.getOperand(i)->getType() == Type::FloatTy ? 4 : 8;
|
||||
break;
|
||||
default: assert(0 && "Unknown class!");
|
||||
}
|
||||
|
||||
// Adjust the stack pointer for the new arguments...
|
||||
BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addZImm(NumBytes);
|
||||
|
||||
// Arguments go on the stack in reverse order, as specified by the ABI.
|
||||
unsigned ArgOffset = 0;
|
||||
for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) {
|
||||
Value *Arg = CI.getOperand(i);
|
||||
switch (getClass(Arg->getType())) {
|
||||
case cByte:
|
||||
case cShort: {
|
||||
// Promote arg to 32 bits wide into a temporary register...
|
||||
unsigned R = makeAnotherReg(Type::UIntTy);
|
||||
promote32(R, Arg);
|
||||
addRegOffset(BuildMI(BB, X86::MOVrm32, 5),
|
||||
X86::ESP, ArgOffset).addReg(R);
|
||||
break;
|
||||
}
|
||||
case cInt:
|
||||
addRegOffset(BuildMI(BB, X86::MOVrm32, 5),
|
||||
X86::ESP, ArgOffset).addReg(getReg(Arg));
|
||||
break;
|
||||
|
||||
case cFP:
|
||||
if (Arg->getType() == Type::FloatTy) {
|
||||
addRegOffset(BuildMI(BB, X86::FSTr32, 5),
|
||||
X86::ESP, ArgOffset).addReg(getReg(Arg));
|
||||
} else {
|
||||
assert(Arg->getType() == Type::DoubleTy && "Unknown FP type!");
|
||||
ArgOffset += 4;
|
||||
addRegOffset(BuildMI(BB, X86::FSTr32, 5),
|
||||
X86::ESP, ArgOffset).addReg(getReg(Arg));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// FIXME: long/ulong/float/double args not handled.
|
||||
visitInstruction(CI);
|
||||
break;
|
||||
}
|
||||
ArgOffset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (Function *F = CI.getCalledFunction()) {
|
||||
|
@ -580,9 +657,7 @@ void ISel::visitCallInst(CallInst &CI) {
|
|||
BuildMI(BB, X86::CALLr32, 1).addReg(Reg);
|
||||
}
|
||||
|
||||
// Adjust the stack by `bytesPushed' amount if non-zero
|
||||
if (bytesPushed > 0)
|
||||
BuildMI(BB, X86::ADDri32,2, X86::ESP).addReg(X86::ESP).addZImm(bytesPushed);
|
||||
BuildMI(BB, X86::ADJCALLSTACKUP, 1).addZImm(NumBytes);
|
||||
|
||||
// If there is a return value, scavenge the result from the location the call
|
||||
// leaves it in...
|
||||
|
@ -956,9 +1031,9 @@ ISel::visitCastInst (CastInst &CI)
|
|||
{
|
||||
const Type *targetType = CI.getType ();
|
||||
Value *operand = CI.getOperand (0);
|
||||
unsigned int operandReg = getReg (operand);
|
||||
unsigned operandReg = getReg (operand);
|
||||
const Type *sourceType = operand->getType ();
|
||||
unsigned int destReg = getReg (CI);
|
||||
unsigned destReg = getReg (CI);
|
||||
//
|
||||
// Currently we handle:
|
||||
//
|
||||
|
@ -1158,47 +1233,58 @@ void ISel::emitGEPOperation(MachineBasicBlock *MBB,
|
|||
}
|
||||
|
||||
|
||||
/// visitMallocInst - I know that personally, whenever I want to remember
|
||||
/// something, I have to clear off some space in my brain.
|
||||
void
|
||||
ISel::visitMallocInst (MallocInst &I)
|
||||
{
|
||||
// We assume that by this point, malloc instructions have been
|
||||
// lowered to calls, and dlsym will magically find malloc for us.
|
||||
// So we do not want to see malloc instructions here.
|
||||
visitInstruction (I);
|
||||
}
|
||||
|
||||
|
||||
/// visitFreeInst - same story as MallocInst
|
||||
void
|
||||
ISel::visitFreeInst (FreeInst &I)
|
||||
{
|
||||
// We assume that by this point, free instructions have been
|
||||
// lowered to calls, and dlsym will magically find free for us.
|
||||
// So we do not want to see free instructions here.
|
||||
visitInstruction (I);
|
||||
}
|
||||
|
||||
|
||||
/// visitAllocaInst - I want some stack space. Come on, man, I said I
|
||||
/// want some freakin' stack space.
|
||||
void
|
||||
ISel::visitAllocaInst (AllocaInst &I)
|
||||
{
|
||||
/// visitAllocaInst - If this is a fixed size alloca, allocate space from the
|
||||
/// frame manager, otherwise do it the hard way.
|
||||
///
|
||||
void ISel::visitAllocaInst(AllocaInst &I) {
|
||||
// Find the data size of the alloca inst's getAllocatedType.
|
||||
const Type *allocatedType = I.getAllocatedType ();
|
||||
const TargetData &TD = TM.DataLayout;
|
||||
unsigned allocatedTypeSize = TD.getTypeSize (allocatedType);
|
||||
// Keep stack 32-bit aligned.
|
||||
unsigned int allocatedTypeWords = allocatedTypeSize / 4;
|
||||
if (allocatedTypeSize % 4 != 0) { allocatedTypeWords++; }
|
||||
const Type *Ty = I.getAllocatedType();
|
||||
unsigned TySize = TM.getTargetData().getTypeSize(Ty);
|
||||
|
||||
// If this is a fixed size alloca in the entry block for the function,
|
||||
// statically stack allocate the space.
|
||||
//
|
||||
if (ConstantUInt *CUI = dyn_cast<ConstantUInt>(I.getArraySize())) {
|
||||
if (I.getParent() == I.getParent()->getParent()->begin()) {
|
||||
TySize *= CUI->getValue(); // Get total allocated size...
|
||||
unsigned Alignment = TM.getTargetData().getTypeAlignment(Ty);
|
||||
|
||||
// Create a new stack object using the frame manager...
|
||||
int FrameIdx = F->getFrameInfo()->CreateStackObject(TySize, Alignment);
|
||||
addFrameReference(BuildMI(BB, X86::LEAr32, 5, getReg(I)), FrameIdx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a register to hold the temporary result of multiplying the type size
|
||||
// constant by the variable amount.
|
||||
unsigned TotalSizeReg = makeAnotherReg(Type::UIntTy);
|
||||
unsigned SrcReg1 = getReg(I.getArraySize());
|
||||
unsigned SizeReg = makeAnotherReg(Type::UIntTy);
|
||||
BuildMI(BB, X86::MOVir32, 1, SizeReg).addZImm(TySize);
|
||||
|
||||
// TotalSizeReg = mul <numelements>, <TypeSize>
|
||||
MachineBasicBlock::iterator MBBI = BB->end();
|
||||
doMultiply(BB, MBBI, TotalSizeReg, Type::UIntTy, SrcReg1, SizeReg);
|
||||
|
||||
// AddedSize = add <TotalSizeReg>, 15
|
||||
unsigned AddedSizeReg = makeAnotherReg(Type::UIntTy);
|
||||
BuildMI(BB, X86::ADDri32, 2, AddedSizeReg).addReg(TotalSizeReg).addZImm(15);
|
||||
|
||||
// AlignedSize = and <AddedSize>, ~15
|
||||
unsigned AlignedSize = makeAnotherReg(Type::UIntTy);
|
||||
BuildMI(BB, X86::ANDri32, 2, AlignedSize).addReg(AddedSizeReg).addZImm(~15);
|
||||
|
||||
// Subtract size from stack pointer, thereby allocating some space.
|
||||
BuildMI(BB, X86::SUBri32, 2,
|
||||
X86::ESP).addReg(X86::ESP).addZImm(allocatedTypeWords * 4);
|
||||
BuildMI(BB, X86::SUBri32, 2, X86::ESP).addReg(X86::ESP).addZImm(AlignedSize);
|
||||
|
||||
// Put a pointer to the space into the result register, by copying
|
||||
// the stack pointer.
|
||||
BuildMI(BB, X86::MOVrr32, 1, getReg(I)).addReg(X86::ESP);
|
||||
|
||||
// Inform the Frame Information that we have just allocated a variable sized
|
||||
// object.
|
||||
F->getFrameInfo()->CreateVariableSizedObject();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue