#include "llvm/Target/Sparc.h" #include "SparcInternals.h" #include "llvm/Method.h" #include "llvm/iTerminators.h" #include "llvm/CodeGen/InstrScheduling.h" #include "llvm/CodeGen/InstrSelection.h" #include "llvm/Analysis/LiveVar/MethodLiveVarInfo.h" #include "llvm/CodeGen/PhyRegAlloc.h" //--------------------------------------------------------------------------- // UltraSparcRegInfo //--------------------------------------------------------------------------- /* Rules for coloring values with sepcial registers: ================================================= The following are the cases we color values with special regs: 1) Incoming Method Arguements 2) Outgoing Call Arguments 3) Return Value of a call 4) Return Value of a return statement Both 1 and 3 are defs. Therefore, they can be set directly. For case 1, incoming args are colored to %i0-%i5 and %f0 - %fx. For case 3, the return value of the call must be colored to %o0 or %f0. For case 2 we can use %o0-%o6 and %f0- %fx and for case 4 we can use %i0 or %f0. However, we cannot pre-color them directly to those regs if there are call interferences or they can be already colred by case 1. (Note that a return value is call is already colored and it is registered as a call interference as well if it is live after the call). Otherwise, they can be precolored. In cases where we cannot precolor, we just have to insert a copy instruction to copy the LR to the required register. */ //--------------------------------------------------------------------------- // This method will color incoming args to a method. If there are more // args than that can fit in regs, code will be inserted to pop them from // stack //--------------------------------------------------------------------------- void UltraSparcRegInfo::colorArgs(const Method *const Meth, LiveRangeInfo& LRI) const { // get the argument list const Method::ArgumentListType& ArgList = Meth->getArgumentList(); // get an iterator to arg list Method::ArgumentListType::const_iterator ArgIt = ArgList.begin(); unsigned intArgNo=0; // to keep track of which float regs are allocated for argument passing bool FloatArgUsedArr[NumOfFloatArgRegs]; // init float arg used array for(unsigned i=0; i < NumOfFloatArgRegs; ++i) FloatArgUsedArr[i] = false; // for each argument for( ; ArgIt != ArgList.end() ; ++ArgIt) { // get the LR of arg LiveRange *const LR = LRI.getLiveRangeForValue((const Value *) *ArgIt); unsigned RegClassID = (LR->getRegClass())->getID(); // if the arg is in int class - allocate a reg for an int arg if( RegClassID == IntRegClassID ) { if( intArgNo < NumOfIntArgRegs) { LR->setColor( SparcIntRegOrder::i0 + intArgNo ); if( DEBUG_RA) printReg( LR ); } else { // TODO: Insert push code here assert( 0 && "Insert push code here!"); } ++intArgNo; } // if the arg is float/double else if ( RegClassID == FloatRegClassID) { if( LR->getTypeID() == Type::DoubleTyID ) { // find the first reg # we can pass a double arg for(unsigned i=0; i < NumOfFloatArgRegs; i+= 2) { if ( !FloatArgUsedArr[i] && !FloatArgUsedArr[i+1] ) { LR->setColor( SparcFloatRegOrder::f0 + i ); FloatArgUsedArr[i] = true; FloatArgUsedArr[i+1] = true; if( DEBUG_RA) printReg( LR ); break; } } if( ! LR->hasColor() ) { // if LR was not colored above assert(0 && "insert push code here for a double"); } } else if( LR->getTypeID() == Type::FloatTyID ) { // find the first reg # we can pass a float arg for(unsigned i=0; i < NumOfFloatArgRegs; ++i) { if ( !FloatArgUsedArr[i] ) { LR->setColor( SparcFloatRegOrder::f0 + i ); FloatArgUsedArr[i] = true; if( DEBUG_RA) printReg( LR ); break; } } if( ! LR->hasColor() ) { // if LR was not colored above assert(0 && "insert push code here for a float"); } } else assert(0 && "unknown float type in method arg"); } // float register class else assert(0 && "Unknown RegClassID"); } } void UltraSparcRegInfo::colorCallArgs(vector & CallInstrList, LiveRangeInfo& LRI, AddedInstrMapType &AddedInstrMap) const { vector::const_iterator InstIt; // First color the return value of all call instructions. The return value // will be in %o0 if the value is an integer type, or in %f0 if the // value is a float type. for(InstIt=CallInstrList.begin(); InstIt != CallInstrList.end(); ++InstIt) { const Instruction *const CallI = *InstIt; // get the live range of return value of this call LiveRange *const LR = LRI.getLiveRangeForValue( CallI ); if ( LR ) { // Since the call is a def, it cannot be colored by some other instr. // Therefore, we can definitely set a color here. // However, this def can be used by some other instr like another call // or return which places that in a special register. In that case // it has to put a copy. Note that, the def will have a call interference // with this call instr itself if it is live after this call. assert( ! LR->hasColor() && "Can't have a color since this is a def"); unsigned RegClassID = (LR->getRegClass())->getID(); if( RegClassID == IntRegClassID ) { LR->setColor(SparcIntRegOrder::o0); } else if (RegClassID == FloatRegClassID ) { LR->setColor(SparcFloatRegOrder::f0 ); } } else { cout << "Warning: No Live Range for return value of CALL" << endl; } } for( InstIt=CallInstrList.begin(); InstIt != CallInstrList.end(); ++InstIt) { // Inst = LLVM call instruction const Instruction *const CallI = *InstIt; // find the CALL/JMMPL machine instruction MachineCodeForVMInstr & MInstVec = CallI->getMachineInstrVec(); MachineCodeForVMInstr::const_iterator MIIt = MInstVec.begin(); /* for( ; MIIt != MInstVec.end() && ! getUltraSparcInfo().getInstrInfo().isCall((*MIIt)->getOpCode()); ++MIIt ); assert( (MIIt != MInstVec.end()) && "CALL/JMPL not found"); */ assert(getUltraSparcInfo().getInstrInfo().isCall((*MIIt)->getOpCode()) && "First machine instruction is not a Call/JMPL Machine Instr"); // CallMI = CALL/JMPL machine isntruction const MachineInstr *const CallMI = *MIIt; Instruction::op_const_iterator OpIt = CallI->op_begin(); unsigned intArgNo=0; // to keep track of which float regs are allocated for argument passing bool FloatArgUsedArr[NumOfFloatArgRegs]; // init float arg used array for(unsigned i=0; i < NumOfFloatArgRegs; ++i) FloatArgUsedArr[i] = false; // go thru all the operands of LLVM instruction for( ; OpIt != CallI->op_end(); ++OpIt ) { // get the LR of call operand (parameter) LiveRange *const LR = LRI.getLiveRangeForValue((const Value *) *OpIt); if ( !LR ) { cout << " Warning: In call instr, no LR for arg: " ; printValue(*OpIt); cout << endl; continue; } unsigned RegClassID = (LR->getRegClass())->getID(); // if the arg is in int class - allocate a reg for an int arg if( RegClassID == IntRegClassID ) { if( intArgNo < NumOfIntArgRegs) { setCallOrRetArgCol( LR, SparcIntRegOrder::o0 + intArgNo, CallMI, AddedInstrMap); } else { // TODO: Insert push code here assert( 0 && "Insert push code here!"); AddedInstrns * AI = AddedInstrMap[ CallMI ]; if( ! AI ) AI = new AddedInstrns(); // AI->InstrnsBefore.push_back( getStackPushInstr(LR) ); AddedInstrMap[ CallMI ] = AI; } ++intArgNo; } // if the arg is float/double else if ( RegClassID == FloatRegClassID) { if( LR->getTypeID() == Type::DoubleTyID ) { // find the first reg # we can pass a double arg for(unsigned i=0; i < NumOfFloatArgRegs; i+= 2) { if ( !FloatArgUsedArr[i] && !FloatArgUsedArr[i+1] ) { setCallOrRetArgCol(LR, SparcFloatRegOrder::f0 + i, CallMI, AddedInstrMap); FloatArgUsedArr[i] = true; FloatArgUsedArr[i+1] = true; //if( DEBUG_RA) printReg( LR ); break; } } if( ! LR->hasColor() ) { // if LR was not colored above assert(0 && "insert push code here for a double"); } } else if( LR->getTypeID() == Type::FloatTyID ) { // find the first reg # we can pass a float arg for(unsigned i=0; i < NumOfFloatArgRegs; ++i) { if ( !FloatArgUsedArr[i] ) { setCallOrRetArgCol(LR, SparcFloatRegOrder::f0 + i, CallMI, AddedInstrMap); FloatArgUsedArr[i] = true; // LR->setColor( SparcFloatRegOrder::f0 + i ); // if( DEBUG_RA) printReg( LR ); break; } } if( ! LR->hasColor() ) { // if LR was not colored above assert(0 && "insert push code here for a float"); } } else assert(0 && "unknown float type in method arg"); } // float register class else assert(0 && "Unknown RegClassID"); } // for each operand in a call instruction } // for all call instrctions in CallInstrList } void UltraSparcRegInfo::colorRetArg(vector & RetInstrList, LiveRangeInfo& LRI, AddedInstrMapType &AddedInstrMap) const { vector::const_iterator InstIt; for(InstIt=RetInstrList.begin(); InstIt != RetInstrList.end(); ++InstIt) { const ReturnInst *const RetI = (ReturnInst *) *InstIt; // get the return value of this return instruction const Value *RetVal = (RetI)->getReturnValue(); if( RetVal ) { // find the CALL/JMMPL machine instruction MachineCodeForVMInstr & MInstVec = RetI->getMachineInstrVec(); MachineCodeForVMInstr::const_iterator MIIt = MInstVec.begin(); assert(getUltraSparcInfo().getInstrInfo().isReturn((*MIIt)->getOpCode()) && "First machine instruction is not a RET Machine Instr"); // RET machine isntruction const MachineInstr *const RetMI = *MIIt; LiveRange *const LR = LRI.getLiveRangeForValue( RetVal ); unsigned RegClassID = (LR->getRegClass())->getID(); if ( LR ) { if( RegClassID == IntRegClassID ) { setCallOrRetArgCol( LR, SparcIntRegOrder::i0, RetMI, AddedInstrMap); } else if (RegClassID==FloatRegClassID ) { setCallOrRetArgCol(LR, SparcFloatRegOrder::f0, RetMI, AddedInstrMap); } } else { cout << "Warning: No LR for return value" << endl; } } } } void UltraSparcRegInfo::setCallOrRetArgCol(LiveRange *const LR, const unsigned RegNo, const MachineInstr *MI, AddedInstrMapType &AIMap) const { // if no call interference and LR is NOT previously colored (e.g., as an // incoming arg) if( ! LR->getNumOfCallInterferences() && ! LR->hasColor() ) { // we can directly allocate a %o register LR->setColor( RegNo); if( DEBUG_RA) printReg( LR ); } else { // there are call interferences (e.g., live across a call or produced // by a call instr) or this LR is already colored as an incoming argument MachineInstr *MI = getCopy2RegMI((*(LR->begin())), RegNo, (LR->getRegClass())->getID()); AddedInstrns * AI = AIMap[ MI ]; // get already added instrns for MI if( ! AI ) AI = new AddedInstrns(); AI->InstrnsBefore.push_back( MI ); // add the new MI yp AMI AIMap[ MI ] = AI; cout << "Inserted a copy instr for a RET/CALL instr " << endl; // We don't color LR here. It's colored as any other normal LR or // as an incoming arg or a return value of a call. } } // Generates a copy machine instruction to copy a value to a given // register. MachineInstr * UltraSparcRegInfo::getCopy2RegMI(const Value *SrcVal, const unsigned Reg, unsigned RegClassID) const { MachineInstr * MI; if( RegClassID == IntRegClassID ) { // if integer move MI = new MachineInstr(ADD, 3); MI->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, SrcVal); MI->SetMachineOperand(1, SparcIntRegOrder::g0, false); MI->SetMachineOperand(2, Reg, true); } else { // if FP move if(SrcVal->getType()-> getPrimitiveID() == Type::FloatTyID ) MI = new MachineInstr(FMOVS, 2); else if(SrcVal->getType()-> getPrimitiveID() == Type::DoubleTyID) MI = new MachineInstr(FMOVD, 2); else assert( 0 && "Unknown Type"); MI->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, SrcVal); MI->SetMachineOperand(1, Reg, true); } return MI; } //--------------------------------------------------------------------------- // Print the register assigned to a LR //--------------------------------------------------------------------------- void UltraSparcRegInfo::printReg(const LiveRange *const LR) { unsigned RegClassID = (LR->getRegClass())->getID(); cout << " *Node " << (LR->getUserIGNode())->getIndex(); if( ! LR->hasColor() ) { cout << " - could not find a color" << endl; return; } // if a color is found cout << " colored with color "<< LR->getColor(); if( RegClassID == IntRegClassID ) { cout<< " [" << SparcIntRegOrder::getRegName(LR->getColor()) ; cout << "]" << endl; } else if ( RegClassID == FloatRegClassID) { cout << "[" << SparcFloatRegOrder::getRegName(LR->getColor()); if( LR->getTypeID() == Type::DoubleTyID ) cout << "+" << SparcFloatRegOrder::getRegName(LR->getColor()+1); cout << "]" << endl; } }