]> granicus.if.org Git - llvm/commitdiff
Add support for variable argument functions!
authorChris Lattner <sabre@nondot.org>
Thu, 8 May 2003 19:44:13 +0000 (19:44 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 8 May 2003 19:44:13 +0000 (19:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6046 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/InstSelectSimple.cpp
lib/Target/X86/X86ISelSimple.cpp

index 0df00e2f942c1cd03535327bf6370250d40b46b9..d92303889c4595e1e2d235576034aa4c7e2a7522 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/Constants.h"
 #include "llvm/Pass.h"
+#include "llvm/Intrinsics.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/SSARegMap.h"
@@ -57,8 +58,9 @@ inline static MachineInstrBuilder BMI(MachineBasicBlock *MBB,
 namespace {
   struct ISel : public FunctionPass, InstVisitor<ISel> {
     TargetMachine &TM;
-    MachineFunction *F;                    // The function we are compiling into
-    MachineBasicBlock *BB;                 // The current MBB we are compiling
+    MachineFunction *F;                 // The function we are compiling into
+    MachineBasicBlock *BB;              // The current MBB we are compiling
+    int VarArgsFrameIndex;              // FrameIndex for start of varargs area
 
     std::map<Value*, unsigned> RegMap;  // Mapping between Val's and SSA Regs
 
@@ -134,6 +136,7 @@ namespace {
     void doCall(const ValueRecord &Ret, MachineInstr *CallMI,
                const std::vector<ValueRecord> &Args);
     void visitCallInst(CallInst &I);
+    void visitIntrinsicCall(LLVMIntrinsic::ID ID, CallInst &I);
 
     // Arithmetic operators
     void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
@@ -173,6 +176,7 @@ namespace {
     void visitShiftInst(ShiftInst &I);
     void visitPHINode(PHINode &I) {}      // PHI nodes handled by second pass
     void visitCastInst(CastInst &I);
+    void visitVarArgInst(VarArgInst &I);
 
     void visitInstruction(Instruction &I) {
       std::cerr << "Cannot instruction select: " << I;
@@ -434,6 +438,12 @@ void ISel::LoadArgumentsToVirtualRegs(Function &Fn) {
     }
     ArgOffset += 4;  // Each argument takes at least 4 bytes on the stack...
   }
+
+  // If the function takes variable number of arguments, add a frame offset for
+  // the start of the first vararg value... this is used to expand
+  // llvm.va_start.
+  if (Fn.getFunctionType()->isVarArg())
+    VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
 }
 
 
@@ -876,6 +886,12 @@ void ISel::doCall(const ValueRecord &Ret, MachineInstr *CallMI,
 void ISel::visitCallInst(CallInst &CI) {
   MachineInstr *TheCall;
   if (Function *F = CI.getCalledFunction()) {
+    // Is it an intrinsic function call?
+    if (LLVMIntrinsic::ID ID = (LLVMIntrinsic::ID)F->getIntrinsicID()) {
+      visitIntrinsicCall(ID, CI);   // Special intrinsics are not handled here
+      return;
+    }
+
     // Emit a CALL instruction with PC-relative displacement.
     TheCall = BuildMI(X86::CALLpcrel32, 1).addGlobalAddress(F, true);
   } else {  // Emit an indirect call...
@@ -892,6 +908,29 @@ void ISel::visitCallInst(CallInst &CI) {
   doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args);
 }       
 
+void ISel::visitIntrinsicCall(LLVMIntrinsic::ID ID, CallInst &CI) {
+  unsigned TmpReg1, TmpReg2;
+  switch (ID) {
+  case LLVMIntrinsic::va_start:
+    // Get the address of the first vararg value...
+    TmpReg1 = makeAnotherReg(Type::UIntTy);
+    addFrameReference(BuildMI(BB, X86::LEAr32, 5, TmpReg1), VarArgsFrameIndex);
+    TmpReg2 = getReg(CI.getOperand(1));
+    addDirectMem(BuildMI(BB, X86::MOVrm32, 5), TmpReg2).addReg(TmpReg1);
+    return;
+
+  case LLVMIntrinsic::va_end: return;   // Noop on X86
+  case LLVMIntrinsic::va_copy:
+    TmpReg1 = getReg(CI.getOperand(2));  // Get existing va_list
+    TmpReg2 = getReg(CI.getOperand(1));  // Get va_list* to store into
+    addDirectMem(BuildMI(BB, X86::MOVrm32, 5), TmpReg2).addReg(TmpReg1);
+    return;
+
+  default: assert(0 && "Unknown intrinsic for X86!");
+  }
+}
+
+
 
 /// visitSimpleBinary - Implement simple binary operators for integral types...
 /// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or,
@@ -1597,6 +1636,49 @@ void ISel::emitCastOperation(MachineBasicBlock *BB,
   abort();
 }
 
+/// visitVarArgInst - Implement the va_arg instruction...
+///
+void ISel::visitVarArgInst(VarArgInst &I) {
+  unsigned SrcReg = getReg(I.getOperand(0));
+  unsigned DestReg = getReg(I);
+
+  // Load the va_list into a register...
+  unsigned VAList = makeAnotherReg(Type::UIntTy);
+  addDirectMem(BuildMI(BB, X86::MOVmr32, 4, VAList), SrcReg);
+
+  unsigned Size;
+  switch (I.getType()->getPrimitiveID()) {
+  default:
+    std::cerr << I;
+    assert(0 && "Error: bad type for va_arg instruction!");
+    return;
+  case Type::PointerTyID:
+  case Type::UIntTyID:
+  case Type::IntTyID:
+    Size = 4;
+    addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList);
+    break;
+  case Type::ULongTyID:
+  case Type::LongTyID:
+    Size = 8;
+    addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList);
+    addRegOffset(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), VAList, 4);
+    break;
+  case Type::DoubleTyID:
+    Size = 8;
+    addDirectMem(BuildMI(BB, X86::FLDr64, 4, DestReg), VAList);
+    break;
+  }
+
+  // Increment the VAList pointer...
+  unsigned NextVAList = makeAnotherReg(Type::UIntTy);
+  BuildMI(BB, X86::ADDri32, 2, NextVAList).addReg(VAList).addZImm(Size);
+
+  // Update the VAList in memory...
+  addDirectMem(BuildMI(BB, X86::MOVrm32, 5), SrcReg).addReg(NextVAList);
+}
+
+
 // ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N.  It
 // returns zero when the input is not exactly a power of two.
 static unsigned ExactLog2(unsigned Val) {
index 0df00e2f942c1cd03535327bf6370250d40b46b9..d92303889c4595e1e2d235576034aa4c7e2a7522 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/Constants.h"
 #include "llvm/Pass.h"
+#include "llvm/Intrinsics.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/SSARegMap.h"
@@ -57,8 +58,9 @@ inline static MachineInstrBuilder BMI(MachineBasicBlock *MBB,
 namespace {
   struct ISel : public FunctionPass, InstVisitor<ISel> {
     TargetMachine &TM;
-    MachineFunction *F;                    // The function we are compiling into
-    MachineBasicBlock *BB;                 // The current MBB we are compiling
+    MachineFunction *F;                 // The function we are compiling into
+    MachineBasicBlock *BB;              // The current MBB we are compiling
+    int VarArgsFrameIndex;              // FrameIndex for start of varargs area
 
     std::map<Value*, unsigned> RegMap;  // Mapping between Val's and SSA Regs
 
@@ -134,6 +136,7 @@ namespace {
     void doCall(const ValueRecord &Ret, MachineInstr *CallMI,
                const std::vector<ValueRecord> &Args);
     void visitCallInst(CallInst &I);
+    void visitIntrinsicCall(LLVMIntrinsic::ID ID, CallInst &I);
 
     // Arithmetic operators
     void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
@@ -173,6 +176,7 @@ namespace {
     void visitShiftInst(ShiftInst &I);
     void visitPHINode(PHINode &I) {}      // PHI nodes handled by second pass
     void visitCastInst(CastInst &I);
+    void visitVarArgInst(VarArgInst &I);
 
     void visitInstruction(Instruction &I) {
       std::cerr << "Cannot instruction select: " << I;
@@ -434,6 +438,12 @@ void ISel::LoadArgumentsToVirtualRegs(Function &Fn) {
     }
     ArgOffset += 4;  // Each argument takes at least 4 bytes on the stack...
   }
+
+  // If the function takes variable number of arguments, add a frame offset for
+  // the start of the first vararg value... this is used to expand
+  // llvm.va_start.
+  if (Fn.getFunctionType()->isVarArg())
+    VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
 }
 
 
@@ -876,6 +886,12 @@ void ISel::doCall(const ValueRecord &Ret, MachineInstr *CallMI,
 void ISel::visitCallInst(CallInst &CI) {
   MachineInstr *TheCall;
   if (Function *F = CI.getCalledFunction()) {
+    // Is it an intrinsic function call?
+    if (LLVMIntrinsic::ID ID = (LLVMIntrinsic::ID)F->getIntrinsicID()) {
+      visitIntrinsicCall(ID, CI);   // Special intrinsics are not handled here
+      return;
+    }
+
     // Emit a CALL instruction with PC-relative displacement.
     TheCall = BuildMI(X86::CALLpcrel32, 1).addGlobalAddress(F, true);
   } else {  // Emit an indirect call...
@@ -892,6 +908,29 @@ void ISel::visitCallInst(CallInst &CI) {
   doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args);
 }       
 
+void ISel::visitIntrinsicCall(LLVMIntrinsic::ID ID, CallInst &CI) {
+  unsigned TmpReg1, TmpReg2;
+  switch (ID) {
+  case LLVMIntrinsic::va_start:
+    // Get the address of the first vararg value...
+    TmpReg1 = makeAnotherReg(Type::UIntTy);
+    addFrameReference(BuildMI(BB, X86::LEAr32, 5, TmpReg1), VarArgsFrameIndex);
+    TmpReg2 = getReg(CI.getOperand(1));
+    addDirectMem(BuildMI(BB, X86::MOVrm32, 5), TmpReg2).addReg(TmpReg1);
+    return;
+
+  case LLVMIntrinsic::va_end: return;   // Noop on X86
+  case LLVMIntrinsic::va_copy:
+    TmpReg1 = getReg(CI.getOperand(2));  // Get existing va_list
+    TmpReg2 = getReg(CI.getOperand(1));  // Get va_list* to store into
+    addDirectMem(BuildMI(BB, X86::MOVrm32, 5), TmpReg2).addReg(TmpReg1);
+    return;
+
+  default: assert(0 && "Unknown intrinsic for X86!");
+  }
+}
+
+
 
 /// visitSimpleBinary - Implement simple binary operators for integral types...
 /// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or,
@@ -1597,6 +1636,49 @@ void ISel::emitCastOperation(MachineBasicBlock *BB,
   abort();
 }
 
+/// visitVarArgInst - Implement the va_arg instruction...
+///
+void ISel::visitVarArgInst(VarArgInst &I) {
+  unsigned SrcReg = getReg(I.getOperand(0));
+  unsigned DestReg = getReg(I);
+
+  // Load the va_list into a register...
+  unsigned VAList = makeAnotherReg(Type::UIntTy);
+  addDirectMem(BuildMI(BB, X86::MOVmr32, 4, VAList), SrcReg);
+
+  unsigned Size;
+  switch (I.getType()->getPrimitiveID()) {
+  default:
+    std::cerr << I;
+    assert(0 && "Error: bad type for va_arg instruction!");
+    return;
+  case Type::PointerTyID:
+  case Type::UIntTyID:
+  case Type::IntTyID:
+    Size = 4;
+    addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList);
+    break;
+  case Type::ULongTyID:
+  case Type::LongTyID:
+    Size = 8;
+    addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList);
+    addRegOffset(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), VAList, 4);
+    break;
+  case Type::DoubleTyID:
+    Size = 8;
+    addDirectMem(BuildMI(BB, X86::FLDr64, 4, DestReg), VAList);
+    break;
+  }
+
+  // Increment the VAList pointer...
+  unsigned NextVAList = makeAnotherReg(Type::UIntTy);
+  BuildMI(BB, X86::ADDri32, 2, NextVAList).addReg(VAList).addZImm(Size);
+
+  // Update the VAList in memory...
+  addDirectMem(BuildMI(BB, X86::MOVrm32, 5), SrcReg).addReg(NextVAList);
+}
+
+
 // ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N.  It
 // returns zero when the input is not exactly a power of two.
 static unsigned ExactLog2(unsigned Val) {