mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-14 07:31:47 +00:00
Add support for compiling varargs functions.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6325 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
12745c55e1
commit
5b1b47b824
@ -87,7 +87,8 @@ Xdefine PANIC printf
|
||||
%term Call=CallOPCODE
|
||||
%term Shl=ShlOPCODE
|
||||
%term Shr=ShrOPCODE
|
||||
/* 30...46 are unused */
|
||||
%term VaArg=VarArgOPCODE
|
||||
/* 32...46 are unused */
|
||||
/*
|
||||
* The foll. values should match the constants in InstrForest.h
|
||||
*/
|
||||
@ -256,6 +257,7 @@ reg: Call = 61 (20); /* just ignore the operands! */
|
||||
reg: Shl(reg,reg) = 62 (20); /* 1 for issue restrictions */
|
||||
reg: Shr(reg,reg) = 63 (20); /* 1 for issue restrictions */
|
||||
reg: Phi(reg,reg) = 64 (0);
|
||||
reg: VaArg(reg) = 65 (40); /* load from stack then incr */
|
||||
|
||||
/*
|
||||
* Finally, leaf nodes of expression trees.
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/ConstantHandling.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "Support/MathExtras.h"
|
||||
#include <math.h>
|
||||
|
||||
@ -1298,6 +1299,46 @@ AllUsesAreBranches(const Instruction* setccI)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate code for any intrinsic that needs a special code sequence
|
||||
// instead of a regular call. If not that kind of intrinsic, do nothing.
|
||||
// Returns true if code was generated, otherwise false.
|
||||
//
|
||||
bool CodeGenIntrinsic(LLVMIntrinsic::ID iid, CallInst &callInstr,
|
||||
TargetMachine &target,
|
||||
std::vector<MachineInstr*>& mvec)
|
||||
{
|
||||
switch (iid) {
|
||||
case LLVMIntrinsic::va_start: {
|
||||
// Get the address of the first vararg value on stack and copy it to
|
||||
// the argument of va_start(va_list* ap).
|
||||
bool ignore;
|
||||
Function* func = cast<Function>(callInstr.getParent()->getParent());
|
||||
int numFixedArgs = func->getFunctionType()->getNumParams();
|
||||
int fpReg = target.getFrameInfo().getIncomingArgBaseRegNum();
|
||||
int argSize = target.getFrameInfo().getSizeOfEachArgOnStack();
|
||||
int firstVarArgOff = numFixedArgs * argSize + target.getFrameInfo().
|
||||
getFirstIncomingArgOffset(MachineFunction::get(func), ignore);
|
||||
mvec.push_back(BuildMI(V9::ADD, 3).addMReg(fpReg).addSImm(firstVarArgOff).
|
||||
addReg(callInstr.getOperand(1)));
|
||||
return true;
|
||||
}
|
||||
|
||||
case LLVMIntrinsic::va_end:
|
||||
return true; // no-op on Sparc
|
||||
|
||||
case LLVMIntrinsic::va_copy:
|
||||
// Simple copy of current va_list (arg2) to new va_list (arg1)
|
||||
mvec.push_back(BuildMI(V9::OR, 3).
|
||||
addMReg(target.getRegInfo().getZeroRegNum()).
|
||||
addReg(callInstr.getOperand(2)).
|
||||
addReg(callInstr.getOperand(1)));
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//******************* Externally Visible Functions *************************/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@ -2101,96 +2142,112 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
//
|
||||
CallInst *callInstr = cast<CallInst>(subtreeRoot->getInstruction());
|
||||
Value *callee = callInstr->getCalledValue();
|
||||
Function* calledFunc = dyn_cast<Function>(callee);
|
||||
|
||||
// Create hidden virtual register for return address with type void*
|
||||
TmpInstruction* retAddrReg =
|
||||
new TmpInstruction(PointerType::get(Type::VoidTy), callInstr);
|
||||
MachineCodeForInstruction::get(callInstr).addTemp(retAddrReg);
|
||||
|
||||
// Generate the machine instruction and its operands.
|
||||
// Use CALL for direct function calls; this optimistically assumes
|
||||
// the PC-relative address fits in the CALL address field (22 bits).
|
||||
// Use JMPL for indirect calls.
|
||||
// Check if this is an intrinsic function that needs a special code
|
||||
// sequence (e.g., va_start). Indirect calls cannot be special.
|
||||
//
|
||||
if (isa<Function>(callee)) // direct function call
|
||||
M = BuildMI(V9::CALL, 1).addPCDisp(callee);
|
||||
else // indirect function call
|
||||
M = BuildMI(V9::JMPLCALL, 3).addReg(callee).addSImm((int64_t)0)
|
||||
.addRegDef(retAddrReg);
|
||||
mvec.push_back(M);
|
||||
bool specialIntrinsic = false;
|
||||
LLVMIntrinsic::ID iid;
|
||||
if (calledFunc && (iid=(LLVMIntrinsic::ID)calledFunc->getIntrinsicID()))
|
||||
specialIntrinsic = CodeGenIntrinsic(iid, *callInstr, target, mvec);
|
||||
|
||||
const FunctionType* funcType =
|
||||
cast<FunctionType>(cast<PointerType>(callee->getType())
|
||||
->getElementType());
|
||||
bool isVarArgs = funcType->isVarArg();
|
||||
bool noPrototype = isVarArgs && funcType->getNumParams() == 0;
|
||||
|
||||
// Use a descriptor to pass information about call arguments
|
||||
// to the register allocator. This descriptor will be "owned"
|
||||
// and freed automatically when the MachineCodeForInstruction
|
||||
// object for the callInstr goes away.
|
||||
CallArgsDescriptor* argDesc = new CallArgsDescriptor(callInstr,
|
||||
retAddrReg, isVarArgs, noPrototype);
|
||||
|
||||
assert(callInstr->getOperand(0) == callee
|
||||
&& "This is assumed in the loop below!");
|
||||
|
||||
for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i)
|
||||
// If not, generate the normal call sequence for the function.
|
||||
// This can also handle any intrinsics that are just function calls.
|
||||
//
|
||||
if (! specialIntrinsic)
|
||||
{
|
||||
Value* argVal = callInstr->getOperand(i);
|
||||
Instruction* intArgReg = NULL;
|
||||
// Create hidden virtual register for return address with type void*
|
||||
TmpInstruction* retAddrReg =
|
||||
new TmpInstruction(PointerType::get(Type::VoidTy), callInstr);
|
||||
MachineCodeForInstruction::get(callInstr).addTemp(retAddrReg);
|
||||
|
||||
// Generate the machine instruction and its operands.
|
||||
// Use CALL for direct function calls; this optimistically assumes
|
||||
// the PC-relative address fits in the CALL address field (22 bits).
|
||||
// Use JMPL for indirect calls.
|
||||
//
|
||||
if (calledFunc) // direct function call
|
||||
M = BuildMI(V9::CALL, 1).addPCDisp(callee);
|
||||
else // indirect function call
|
||||
M = BuildMI(V9::JMPLCALL, 3).addReg(callee).addSImm((int64_t)0)
|
||||
.addRegDef(retAddrReg);
|
||||
mvec.push_back(M);
|
||||
|
||||
const FunctionType* funcType =
|
||||
cast<FunctionType>(cast<PointerType>(callee->getType())
|
||||
->getElementType());
|
||||
bool isVarArgs = funcType->isVarArg();
|
||||
bool noPrototype = isVarArgs && funcType->getNumParams() == 0;
|
||||
|
||||
// Use a descriptor to pass information about call arguments
|
||||
// to the register allocator. This descriptor will be "owned"
|
||||
// and freed automatically when the MachineCodeForInstruction
|
||||
// object for the callInstr goes away.
|
||||
CallArgsDescriptor* argDesc = new CallArgsDescriptor(callInstr,
|
||||
retAddrReg, isVarArgs,noPrototype);
|
||||
|
||||
// Check for FP arguments to varargs functions.
|
||||
// Any such argument in the first $K$ args must be passed in an
|
||||
// integer register, where K = #integer argument registers.
|
||||
if (isVarArgs && argVal->getType()->isFloatingPoint())
|
||||
assert(callInstr->getOperand(0) == callee
|
||||
&& "This is assumed in the loop below!");
|
||||
|
||||
for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i)
|
||||
{
|
||||
// If it is a function with no prototype, pass value
|
||||
// as an FP value as well as a varargs value
|
||||
if (noPrototype)
|
||||
argDesc->getArgInfo(i-1).setUseFPArgReg();
|
||||
|
||||
// If this arg. is in the first $K$ regs, add a copy
|
||||
// float-to-int instruction to pass the value as an integer.
|
||||
if (i <= target.getRegInfo().GetNumOfIntArgRegs())
|
||||
Value* argVal = callInstr->getOperand(i);
|
||||
Instruction* intArgReg = NULL;
|
||||
|
||||
// Check for FP arguments to varargs functions.
|
||||
// Any such argument in the first $K$ args must be passed in an
|
||||
// integer register, where K = #integer argument registers.
|
||||
if (isVarArgs && argVal->getType()->isFloatingPoint())
|
||||
{
|
||||
MachineCodeForInstruction &destMCFI =
|
||||
MachineCodeForInstruction::get(callInstr);
|
||||
intArgReg = new TmpInstruction(Type::IntTy, argVal);
|
||||
destMCFI.addTemp(intArgReg);
|
||||
// If it is a function with no prototype, pass value
|
||||
// as an FP value as well as a varargs value
|
||||
if (noPrototype)
|
||||
argDesc->getArgInfo(i-1).setUseFPArgReg();
|
||||
|
||||
// If this arg. is in the first $K$ regs, add a copy
|
||||
// float-to-int instruction to pass the value as an integer.
|
||||
if (i <= target.getRegInfo().getNumOfIntArgRegs())
|
||||
{
|
||||
MachineCodeForInstruction &destMCFI =
|
||||
MachineCodeForInstruction::get(callInstr);
|
||||
intArgReg = new TmpInstruction(Type::IntTy, argVal);
|
||||
destMCFI.addTemp(intArgReg);
|
||||
|
||||
std::vector<MachineInstr*> copyMvec;
|
||||
target.getInstrInfo().CreateCodeToCopyFloatToInt(target,
|
||||
callInstr->getParent()->getParent(),
|
||||
argVal, (TmpInstruction*) intArgReg,
|
||||
copyMvec, destMCFI);
|
||||
mvec.insert(mvec.begin(),copyMvec.begin(),copyMvec.end());
|
||||
std::vector<MachineInstr*> copyMvec;
|
||||
target.getInstrInfo().CreateCodeToCopyFloatToInt(target,
|
||||
callInstr->getParent()->getParent(),
|
||||
argVal, (TmpInstruction*) intArgReg,
|
||||
copyMvec, destMCFI);
|
||||
mvec.insert(mvec.begin(),copyMvec.begin(),copyMvec.end());
|
||||
|
||||
argDesc->getArgInfo(i-1).setUseIntArgReg();
|
||||
argDesc->getArgInfo(i-1).setArgCopy(intArgReg);
|
||||
argDesc->getArgInfo(i-1).setUseIntArgReg();
|
||||
argDesc->getArgInfo(i-1).setArgCopy(intArgReg);
|
||||
}
|
||||
else
|
||||
// Cannot fit in first $K$ regs so pass arg on stack
|
||||
argDesc->getArgInfo(i-1).setUseStackSlot();
|
||||
}
|
||||
else
|
||||
// Cannot fit in first $K$ regs so pass the arg on the stack
|
||||
argDesc->getArgInfo(i-1).setUseStackSlot();
|
||||
|
||||
if (intArgReg)
|
||||
mvec.back()->addImplicitRef(intArgReg);
|
||||
|
||||
mvec.back()->addImplicitRef(argVal);
|
||||
}
|
||||
|
||||
if (intArgReg)
|
||||
mvec.back()->addImplicitRef(intArgReg);
|
||||
|
||||
mvec.back()->addImplicitRef(argVal);
|
||||
|
||||
// Add the return value as an implicit ref. The call operands
|
||||
// were added above.
|
||||
if (callInstr->getType() != Type::VoidTy)
|
||||
mvec.back()->addImplicitRef(callInstr, /*isDef*/ true);
|
||||
|
||||
// For the CALL instruction, the ret. addr. reg. is also implicit
|
||||
if (isa<Function>(callee))
|
||||
mvec.back()->addImplicitRef(retAddrReg, /*isDef*/ true);
|
||||
|
||||
// delay slot
|
||||
mvec.push_back(BuildMI(V9::NOP, 0));
|
||||
}
|
||||
|
||||
// Add the return value as an implicit ref. The call operands
|
||||
// were added above.
|
||||
if (callInstr->getType() != Type::VoidTy)
|
||||
mvec.back()->addImplicitRef(callInstr, /*isDef*/ true);
|
||||
|
||||
// For the CALL instruction, the ret. addr. reg. is also implicit
|
||||
if (isa<Function>(callee))
|
||||
mvec.back()->addImplicitRef(retAddrReg, /*isDef*/ true);
|
||||
|
||||
// delay slot
|
||||
mvec.push_back(BuildMI(V9::NOP, 0));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2225,6 +2282,19 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
case 64: // reg: Phi(reg,reg)
|
||||
break; // don't forward the value
|
||||
|
||||
case 65: // reg: VaArg(reg)
|
||||
{
|
||||
// Use value initialized by va_start as pointer to args on the stack.
|
||||
// Load argument via current pointer value, then increment pointer.
|
||||
int argSize = target.getFrameInfo().getSizeOfEachArgOnStack();
|
||||
Instruction* vaArgI = subtreeRoot->getInstruction();
|
||||
mvec.push_back(BuildMI(V9::LDX, 3).addReg(vaArgI->getOperand(0)).
|
||||
addSImm(0).addRegDef(vaArgI));
|
||||
mvec.push_back(BuildMI(V9::ADD, 3).addReg(vaArgI->getOperand(0)).
|
||||
addSImm(argSize).addRegDef(vaArgI->getOperand(0)));
|
||||
break;
|
||||
}
|
||||
|
||||
case 71: // reg: VReg
|
||||
case 72: // reg: Constant
|
||||
break; // don't forward the value
|
||||
|
@ -374,8 +374,8 @@ public:
|
||||
// Number of registers used for passing int args (usually 6: %o0 - %o5)
|
||||
// and float args (usually 32: %f0 - %f31)
|
||||
//
|
||||
unsigned const GetNumOfIntArgRegs() const { return NumOfIntArgRegs; }
|
||||
unsigned const GetNumOfFloatArgRegs() const { return NumOfFloatArgRegs; }
|
||||
unsigned const getNumOfIntArgRegs() const { return NumOfIntArgRegs; }
|
||||
unsigned const getNumOfFloatArgRegs() const { return NumOfFloatArgRegs; }
|
||||
|
||||
// The following methods are used to color special live ranges (e.g.
|
||||
// function args and return values etc.) with specific hardware registers
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
|
||||
namespace {
|
||||
struct InsertPrologEpilogCode : public MachineFunctionPass {
|
||||
@ -93,6 +95,34 @@ void InsertPrologEpilogCode::InsertPrologCode(MachineFunction &MF)
|
||||
mvec.push_back(M);
|
||||
}
|
||||
|
||||
// For varargs function bodies, insert instructions to copy incoming
|
||||
// register arguments for the ... list to the stack.
|
||||
// The first K=6 arguments are always received via int arg regs
|
||||
// (%i0 ... %i5 if K=6) .
|
||||
// By copying the varargs arguments to the stack, va_arg() then can
|
||||
// simply assume that all vararg arguments are in an array on the stack.
|
||||
//
|
||||
if (MF.getFunction()->getFunctionType()->isVarArg()) {
|
||||
int numFixedArgs = MF.getFunction()->getFunctionType()->getNumParams();
|
||||
int numArgRegs = TM.getRegInfo().getNumOfIntArgRegs();
|
||||
if (numFixedArgs < numArgRegs) {
|
||||
bool ignore;
|
||||
int firstArgReg = TM.getRegInfo().getUnifiedRegNum(
|
||||
TM.getRegInfo().getRegClassIDOfType(Type::IntTy),
|
||||
SparcIntRegClass::i0);
|
||||
int fpReg = TM.getFrameInfo().getIncomingArgBaseRegNum();
|
||||
int argSize = TM.getFrameInfo().getSizeOfEachArgOnStack();
|
||||
int firstArgOffset=TM.getFrameInfo().getFirstIncomingArgOffset(MF,ignore);
|
||||
int nextArgOffset = firstArgOffset + numFixedArgs * argSize;
|
||||
|
||||
for (int i=numFixedArgs; i < numArgRegs; ++i) {
|
||||
mvec.push_back(BuildMI(V9::STX, 3).addMReg(firstArgReg+i).
|
||||
addMReg(fpReg).addSImm(nextArgOffset));
|
||||
nextArgOffset += argSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MF.front().insert(MF.front().begin(), mvec.begin(), mvec.end());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user