aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target
diff options
context:
space:
mode:
authorVikram S. Adve <vadve@cs.uiuc.edu>2003-05-25 15:59:47 +0000
committerVikram S. Adve <vadve@cs.uiuc.edu>2003-05-25 15:59:47 +0000
commit5b1b47b8240b483ad815b8c60270f0d63f097b53 (patch)
tree46fbfb6704093cf28c68302e10d0ce115410d849 /lib/Target
parent12745c55e1d5a6e76d41684f1b507ea7c6b888ac (diff)
downloadexternal_llvm-5b1b47b8240b483ad815b8c60270f0d63f097b53.zip
external_llvm-5b1b47b8240b483ad815b8c60270f0d63f097b53.tar.gz
external_llvm-5b1b47b8240b483ad815b8c60270f0d63f097b53.tar.bz2
Add support for compiling varargs functions.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6325 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target')
-rw-r--r--lib/Target/SparcV9/SparcV9.burg.in4
-rw-r--r--lib/Target/SparcV9/SparcV9InstrSelection.cpp218
-rw-r--r--lib/Target/SparcV9/SparcV9Internals.h4
-rw-r--r--lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp30
4 files changed, 179 insertions, 77 deletions
diff --git a/lib/Target/SparcV9/SparcV9.burg.in b/lib/Target/SparcV9/SparcV9.burg.in
index 6d28d8a..516a1fc 100644
--- a/lib/Target/SparcV9/SparcV9.burg.in
+++ b/lib/Target/SparcV9/SparcV9.burg.in
@@ -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.
diff --git a/lib/Target/SparcV9/SparcV9InstrSelection.cpp b/lib/Target/SparcV9/SparcV9InstrSelection.cpp
index 61a8045..709c338 100644
--- a/lib/Target/SparcV9/SparcV9InstrSelection.cpp
+++ b/lib/Target/SparcV9/SparcV9InstrSelection.cpp
@@ -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);
+ // Check if this is an intrinsic function that needs a special code
+ // sequence (e.g., va_start). Indirect calls cannot be special.
+ //
+ bool specialIntrinsic = false;
+ LLVMIntrinsic::ID iid;
+ if (calledFunc && (iid=(LLVMIntrinsic::ID)calledFunc->getIntrinsicID()))
+ specialIntrinsic = CodeGenIntrinsic(iid, *callInstr, target, mvec);
- // 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 not, generate the normal call sequence for the function.
+ // This can also handle any intrinsics that are just function calls.
//
- 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);
+ if (! specialIntrinsic)
+ {
+ // 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);
+ const FunctionType* funcType =
+ cast<FunctionType>(cast<PointerType>(callee->getType())
+ ->getElementType());
+ bool isVarArgs = funcType->isVarArg();
+ bool noPrototype = isVarArgs && funcType->getNumParams() == 0;
- 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);
- Instruction* intArgReg = NULL;
+ // 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);
+ if (intArgReg)
+ mvec.back()->addImplicitRef(intArgReg);
- mvec.back()->addImplicitRef(argVal);
- }
+ 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);
+ // 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);
+ // 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));
+ // 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
diff --git a/lib/Target/SparcV9/SparcV9Internals.h b/lib/Target/SparcV9/SparcV9Internals.h
index ec04d3b..f49f615 100644
--- a/lib/Target/SparcV9/SparcV9Internals.h
+++ b/lib/Target/SparcV9/SparcV9Internals.h
@@ -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
diff --git a/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp b/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp
index be55e3b..532a178 100644
--- a/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp
+++ b/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp
@@ -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());
}