From 5b1b47b8240b483ad815b8c60270f0d63f097b53 Mon Sep 17 00:00:00 2001 From: "Vikram S. Adve" Date: Sun, 25 May 2003 15:59:47 +0000 Subject: [PATCH] Add support for compiling varargs functions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6325 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SparcV9/SparcV9.burg.in | 4 +- lib/Target/SparcV9/SparcV9InstrSelection.cpp | 218 ++++++++++++------ lib/Target/SparcV9/SparcV9Internals.h | 4 +- .../SparcV9/SparcV9PrologEpilogInserter.cpp | 30 +++ 4 files changed, 179 insertions(+), 77 deletions(-) diff --git a/lib/Target/SparcV9/SparcV9.burg.in b/lib/Target/SparcV9/SparcV9.burg.in index 6d28d8ad06c..516a1fcb4bd 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 61a804513e2..709c338fd35 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 @@ -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& 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(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(subtreeRoot->getInstruction()); Value *callee = callInstr->getCalledValue(); + Function* calledFunc = dyn_cast(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(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(cast(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(cast(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 copyMvec; - target.getInstrInfo().CreateCodeToCopyFloatToInt(target, - callInstr->getParent()->getParent(), - argVal, (TmpInstruction*) intArgReg, - copyMvec, destMCFI); - mvec.insert(mvec.begin(),copyMvec.begin(),copyMvec.end()); + std::vector 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(callee)) - mvec.back()->addImplicitRef(retAddrReg, /*isDef*/ true); + // For the CALL instruction, the ret. addr. reg. is also implicit + if (isa(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 ec04d3b8d2c..f49f6158333 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 be55e3b0a20..532a178a33b 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()); } -- 2.34.1