forked from OSchip/llvm-project
Add support for compiling varargs functions.
llvm-svn: 6325
This commit is contained in:
parent
e2402c65d0
commit
c9a0a1d728
|
@ -17,6 +17,8 @@
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
|
#include "llvm/DerivedTypes.h"
|
||||||
|
#include "llvm/Intrinsics.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct InsertPrologEpilogCode : public MachineFunctionPass {
|
struct InsertPrologEpilogCode : public MachineFunctionPass {
|
||||||
|
@ -93,6 +95,34 @@ void InsertPrologEpilogCode::InsertPrologCode(MachineFunction &MF)
|
||||||
mvec.push_back(M);
|
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());
|
MF.front().insert(MF.front().begin(), mvec.begin(), mvec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,8 @@ Xdefine PANIC printf
|
||||||
%term Call=CallOPCODE
|
%term Call=CallOPCODE
|
||||||
%term Shl=ShlOPCODE
|
%term Shl=ShlOPCODE
|
||||||
%term Shr=ShrOPCODE
|
%term Shr=ShrOPCODE
|
||||||
/* 30...46 are unused */
|
%term VaArg=VarArgOPCODE
|
||||||
|
/* 32...46 are unused */
|
||||||
/*
|
/*
|
||||||
* The foll. values should match the constants in InstrForest.h
|
* 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: Shl(reg,reg) = 62 (20); /* 1 for issue restrictions */
|
||||||
reg: Shr(reg,reg) = 63 (20); /* 1 for issue restrictions */
|
reg: Shr(reg,reg) = 63 (20); /* 1 for issue restrictions */
|
||||||
reg: Phi(reg,reg) = 64 (0);
|
reg: Phi(reg,reg) = 64 (0);
|
||||||
|
reg: VaArg(reg) = 65 (40); /* load from stack then incr */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, leaf nodes of expression trees.
|
* Finally, leaf nodes of expression trees.
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
#include "llvm/Constants.h"
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/ConstantHandling.h"
|
#include "llvm/ConstantHandling.h"
|
||||||
|
#include "llvm/Intrinsics.h"
|
||||||
#include "Support/MathExtras.h"
|
#include "Support/MathExtras.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
@ -1298,6 +1299,46 @@ AllUsesAreBranches(const Instruction* setccI)
|
||||||
return true;
|
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 *************************/
|
//******************* Externally Visible Functions *************************/
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
|
@ -2101,96 +2142,112 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||||
//
|
//
|
||||||
CallInst *callInstr = cast<CallInst>(subtreeRoot->getInstruction());
|
CallInst *callInstr = cast<CallInst>(subtreeRoot->getInstruction());
|
||||||
Value *callee = callInstr->getCalledValue();
|
Value *callee = callInstr->getCalledValue();
|
||||||
|
Function* calledFunc = dyn_cast<Function>(callee);
|
||||||
|
|
||||||
// Create hidden virtual register for return address with type void*
|
// Check if this is an intrinsic function that needs a special code
|
||||||
TmpInstruction* retAddrReg =
|
// sequence (e.g., va_start). Indirect calls cannot be special.
|
||||||
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 (isa<Function>(callee)) // direct function call
|
bool specialIntrinsic = false;
|
||||||
M = BuildMI(V9::CALL, 1).addPCDisp(callee);
|
LLVMIntrinsic::ID iid;
|
||||||
else // indirect function call
|
if (calledFunc && (iid=(LLVMIntrinsic::ID)calledFunc->getIntrinsicID()))
|
||||||
M = BuildMI(V9::JMPLCALL, 3).addReg(callee).addSImm((int64_t)0)
|
specialIntrinsic = CodeGenIntrinsic(iid, *callInstr, target, mvec);
|
||||||
.addRegDef(retAddrReg);
|
|
||||||
mvec.push_back(M);
|
|
||||||
|
|
||||||
const FunctionType* funcType =
|
// If not, generate the normal call sequence for the function.
|
||||||
cast<FunctionType>(cast<PointerType>(callee->getType())
|
// This can also handle any intrinsics that are just function calls.
|
||||||
->getElementType());
|
//
|
||||||
bool isVarArgs = funcType->isVarArg();
|
if (! specialIntrinsic)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Value* argVal = callInstr->getOperand(i);
|
// Create hidden virtual register for return address with type void*
|
||||||
Instruction* intArgReg = NULL;
|
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.
|
assert(callInstr->getOperand(0) == callee
|
||||||
// Any such argument in the first $K$ args must be passed in an
|
&& "This is assumed in the loop below!");
|
||||||
// integer register, where K = #integer argument registers.
|
|
||||||
if (isVarArgs && argVal->getType()->isFloatingPoint())
|
for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i)
|
||||||
{
|
{
|
||||||
// If it is a function with no prototype, pass value
|
Value* argVal = callInstr->getOperand(i);
|
||||||
// as an FP value as well as a varargs value
|
Instruction* intArgReg = NULL;
|
||||||
if (noPrototype)
|
|
||||||
argDesc->getArgInfo(i-1).setUseFPArgReg();
|
// Check for FP arguments to varargs functions.
|
||||||
|
// Any such argument in the first $K$ args must be passed in an
|
||||||
// If this arg. is in the first $K$ regs, add a copy
|
// integer register, where K = #integer argument registers.
|
||||||
// float-to-int instruction to pass the value as an integer.
|
if (isVarArgs && argVal->getType()->isFloatingPoint())
|
||||||
if (i <= target.getRegInfo().GetNumOfIntArgRegs())
|
|
||||||
{
|
{
|
||||||
MachineCodeForInstruction &destMCFI =
|
// If it is a function with no prototype, pass value
|
||||||
MachineCodeForInstruction::get(callInstr);
|
// as an FP value as well as a varargs value
|
||||||
intArgReg = new TmpInstruction(Type::IntTy, argVal);
|
if (noPrototype)
|
||||||
destMCFI.addTemp(intArgReg);
|
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;
|
std::vector<MachineInstr*> copyMvec;
|
||||||
target.getInstrInfo().CreateCodeToCopyFloatToInt(target,
|
target.getInstrInfo().CreateCodeToCopyFloatToInt(target,
|
||||||
callInstr->getParent()->getParent(),
|
callInstr->getParent()->getParent(),
|
||||||
argVal, (TmpInstruction*) intArgReg,
|
argVal, (TmpInstruction*) intArgReg,
|
||||||
copyMvec, destMCFI);
|
copyMvec, destMCFI);
|
||||||
mvec.insert(mvec.begin(),copyMvec.begin(),copyMvec.end());
|
mvec.insert(mvec.begin(),copyMvec.begin(),copyMvec.end());
|
||||||
|
|
||||||
argDesc->getArgInfo(i-1).setUseIntArgReg();
|
argDesc->getArgInfo(i-1).setUseIntArgReg();
|
||||||
argDesc->getArgInfo(i-1).setArgCopy(intArgReg);
|
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
|
if (intArgReg)
|
||||||
argDesc->getArgInfo(i-1).setUseStackSlot();
|
mvec.back()->addImplicitRef(intArgReg);
|
||||||
|
|
||||||
|
mvec.back()->addImplicitRef(argVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intArgReg)
|
// Add the return value as an implicit ref. The call operands
|
||||||
mvec.back()->addImplicitRef(intArgReg);
|
// were added above.
|
||||||
|
if (callInstr->getType() != Type::VoidTy)
|
||||||
mvec.back()->addImplicitRef(argVal);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2225,6 +2282,19 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||||
case 64: // reg: Phi(reg,reg)
|
case 64: // reg: Phi(reg,reg)
|
||||||
break; // don't forward the value
|
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 71: // reg: VReg
|
||||||
case 72: // reg: Constant
|
case 72: // reg: Constant
|
||||||
break; // don't forward the value
|
break; // don't forward the value
|
||||||
|
|
|
@ -374,8 +374,8 @@ public:
|
||||||
// Number of registers used for passing int args (usually 6: %o0 - %o5)
|
// Number of registers used for passing int args (usually 6: %o0 - %o5)
|
||||||
// and float args (usually 32: %f0 - %f31)
|
// and float args (usually 32: %f0 - %f31)
|
||||||
//
|
//
|
||||||
unsigned const GetNumOfIntArgRegs() const { return NumOfIntArgRegs; }
|
unsigned const getNumOfIntArgRegs() const { return NumOfIntArgRegs; }
|
||||||
unsigned const GetNumOfFloatArgRegs() const { return NumOfFloatArgRegs; }
|
unsigned const getNumOfFloatArgRegs() const { return NumOfFloatArgRegs; }
|
||||||
|
|
||||||
// The following methods are used to color special live ranges (e.g.
|
// The following methods are used to color special live ranges (e.g.
|
||||||
// function args and return values etc.) with specific hardware registers
|
// function args and return values etc.) with specific hardware registers
|
||||||
|
|
Loading…
Reference in New Issue