Add support for compiling varargs functions.
authorVikram S. Adve <vadve@cs.uiuc.edu>
Sun, 25 May 2003 15:59:47 +0000 (15:59 +0000)
committerVikram S. Adve <vadve@cs.uiuc.edu>
Sun, 25 May 2003 15:59:47 +0000 (15:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6325 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/SparcV9/SparcV9.burg.in
lib/Target/SparcV9/SparcV9InstrSelection.cpp
lib/Target/SparcV9/SparcV9Internals.h
lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp

index 6d28d8ad06cc111565a781f9148d998ca632c406..516a1fcb4bd7bca2bb883bf620afe026e6ceb19b 100644 (file)
@@ -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.
index 61a804513e26d03517aee65439252798b4412005..709c338fd356c6520a594d9df3d69e2f9df65757 100644 (file)
@@ -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
index ec04d3b8d2c029af8cefeebf2ea2775bbaf462bf..f49f61583330d62d22e8b5170cc2abf630538c9e 100644 (file)
@@ -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
index be55e3b0a20baedb91f9b129dc14df5b9474ced3..532a178a33baaa477a911baa4dc32d2dbbd886dc 100644 (file)
@@ -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());
 }