Add support for extern varargs methods & varargs method calls


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Bytecode/Reader/ConstantReader.cpp b/lib/Bytecode/Reader/ConstantReader.cpp
index 2994128..e367d02 100644
--- a/lib/Bytecode/Reader/ConstantReader.cpp
+++ b/lib/Bytecode/Reader/ConstantReader.cpp
@@ -33,15 +33,15 @@
     const Type *RetType = getType(Typ);
     if (RetType == 0) return true;
 
-    MethodType::ParamTypes Params;
+    unsigned NumParams;
+    if (read_vbr(Buf, EndBuf, NumParams)) return true;
 
-    if (read_vbr(Buf, EndBuf, Typ)) return true;
-    while (Typ) {
+    MethodType::ParamTypes Params;
+    while (NumParams--) {
+      if (read_vbr(Buf, EndBuf, Typ)) return true;
       const Type *Ty = getType(Typ);
       if (Ty == 0) return true;
       Params.push_back(Ty);
-      
-      if (read_vbr(Buf, EndBuf, Typ)) return true;
     }
 
     Val = MethodType::getMethodType(RetType, Params);
diff --git a/lib/Bytecode/Reader/InstructionReader.cpp b/lib/Bytecode/Reader/InstructionReader.cpp
index 3af40f2..f1dcf08 100644
--- a/lib/Bytecode/Reader/InstructionReader.cpp
+++ b/lib/Bytecode/Reader/InstructionReader.cpp
@@ -196,30 +196,48 @@
     Method *M = (Method*)getValue(Raw.Ty, Raw.Arg1);
     if (M == 0) return true;
 
-    const MethodType::ParamTypes &PL = M->getMethodType()->getParamTypes();
-    MethodType::ParamTypes::const_iterator It = PL.begin();
-
     vector<Value *> Params;
-    switch (Raw.NumOperands) {
-    case 0: cerr << "Invalid call instruction encountered!\n";
-	    return true;
-    case 1: break;
-    case 2: Params.push_back(getValue(*It++, Raw.Arg2)); break;
-    case 3: Params.push_back(getValue(*It++, Raw.Arg2)); 
-            if (It == PL.end()) return true;
-            Params.push_back(getValue(*It++, Raw.Arg3)); break;
-    default:
-      Params.push_back(getValue(*It++, Raw.Arg2));
-      {
-        vector<unsigned> &args = *Raw.VarArgs;
-        for (unsigned i = 0; i < args.size(); i++) {
-	  if (It == PL.end()) return true;
-          Params.push_back(getValue(*It++, args[i]));
+    const MethodType::ParamTypes &PL = M->getMethodType()->getParamTypes();
+
+    if (!M->getType()->isMethodType()->isVarArg()) {
+      MethodType::ParamTypes::const_iterator It = PL.begin();
+
+      switch (Raw.NumOperands) {
+      case 0: cerr << "Invalid call instruction encountered!\n";
+	return true;
+      case 1: break;
+      case 2: Params.push_back(getValue(*It++, Raw.Arg2)); break;
+      case 3: Params.push_back(getValue(*It++, Raw.Arg2)); 
+	if (It == PL.end()) return true;
+	Params.push_back(getValue(*It++, Raw.Arg3)); break;
+      default:
+	Params.push_back(getValue(*It++, Raw.Arg2));
+	{
+	  vector<unsigned> &args = *Raw.VarArgs;
+	  for (unsigned i = 0; i < args.size(); i++) {
+	    if (It == PL.end()) return true;
+	    // TODO: Check getValue for null!
+	    Params.push_back(getValue(*It++, args[i]));
+	  }
 	}
+	delete Raw.VarArgs;
+      }
+      if (It != PL.end()) return true;
+    } else {
+      // The first parameter does not have a type specifier... because there
+      // must be at least one concrete argument to a vararg type...
+      Params.push_back(getValue(PL.front(), Raw.Arg2));
+
+      vector<unsigned> &args = *Raw.VarArgs;
+      if ((args.size() & 1) != 0) return true;  // Must be pairs of type/value
+      for (unsigned i = 0; i < args.size(); i+=2) {
+	Value *Ty = getValue(Type::TypeTy, args[i]);
+	if (!Ty) return true;
+	// TODO: Check getValue for null!
+	Params.push_back(getValue(Ty->castTypeAsserting(), args[i+1]));
       }
       delete Raw.VarArgs;
     }
-    if (It != PL.end()) return true;
 
     Res = new CallInst(M, Params);
     return false;
diff --git a/lib/Bytecode/Writer/ConstantWriter.cpp b/lib/Bytecode/Writer/ConstantWriter.cpp
index 7e2c930..bac5a4c 100644
--- a/lib/Bytecode/Writer/ConstantWriter.cpp
+++ b/lib/Bytecode/Writer/ConstantWriter.cpp
@@ -28,6 +28,9 @@
     assert(Slot != -1 && "Type used but not available!!");
     output_vbr((unsigned)Slot, Out);
 
+    // Output the number of arguments to method (+1 if varargs):
+    output_vbr(MT->getParamTypes().size()+MT->isVarArg(), Out);
+
     // Output all of the arguments...
     MethodType::ParamTypes::const_iterator I = MT->getParamTypes().begin();
     for (; I != MT->getParamTypes().end(); ++I) {
@@ -36,8 +39,9 @@
       output_vbr((unsigned)Slot, Out);
     }
 
-    // Terminate list with VoidTy
-    output_vbr((unsigned)Type::VoidTy->getPrimitiveID(), Out);
+    // Terminate list with VoidTy if we are a varargs function...
+    if (MT->isVarArg())
+      output_vbr((unsigned)Type::VoidTy->getPrimitiveID(), Out);
     break;
   }
 
diff --git a/lib/Bytecode/Writer/InstructionWriter.cpp b/lib/Bytecode/Writer/InstructionWriter.cpp
index a9b5e8d..1814077 100644
--- a/lib/Bytecode/Writer/InstructionWriter.cpp
+++ b/lib/Bytecode/Writer/InstructionWriter.cpp
@@ -35,8 +35,53 @@
   output_vbr(NumArgs, Out);
 
   for (unsigned i = 0; i < NumArgs; ++i) {
-    const Value *N = I->getOperand(i);
-    int Slot = Table.getValSlot(N);
+    int Slot = Table.getValSlot(I->getOperand(i));
+    assert(Slot >= 0 && "No slot number for value!?!?");      
+    output_vbr((unsigned)Slot, Out);
+  }
+  align32(Out);    // We must maintain correct alignment!
+}
+
+
+// outputInstrVarArgsCall - Output the obsurdly annoying varargs method calls.
+// This are more annoying than most because the signature of the call does not
+// tell us anything about the types of the arguments in the varargs portion.
+// Because of this, we encode (as type 0) all of the argument types explicitly
+// before the argument value.  This really sucks, but you shouldn't be using
+// varargs functions in your code! *death to printf*!
+//
+// Format: [opcode] [type] [numargs] [arg0] [arg1] ... [arg<numargs-1>]
+//
+static void outputInstrVarArgsCall(const Instruction *I,
+				   const SlotCalculator &Table, unsigned Type,
+				   vector<uchar> &Out) {
+  assert(I->getOpcode() == Instruction::Call /*|| 
+	 I->getOpcode() == Instruction::ICall */);
+  // Opcode must have top two bits clear...
+  output_vbr(I->getOpcode(), Out);               // Instruction Opcode ID
+  output_vbr(Type, Out);                         // Result type (varargs type)
+
+  unsigned NumArgs = I->getNumOperands();
+  output_vbr((NumArgs-2)*2+2, Out); // Don't duplicate method & Arg1 types
+
+  // Output the method type without an extra type argument.
+  int Slot = Table.getValSlot(I->getOperand(0));
+  assert(Slot >= 0 && "No slot number for value!?!?");      
+  output_vbr((unsigned)Slot, Out);
+
+  // VarArgs methods must have at least one specified operand
+  Slot = Table.getValSlot(I->getOperand(1));
+  assert(Slot >= 0 && "No slot number for value!?!?");      
+  output_vbr((unsigned)Slot, Out);
+
+  for (unsigned i = 2; i < NumArgs; ++i) {
+    // Output Arg Type ID
+    Slot = Table.getValSlot(I->getOperand(i)->getType());
+    assert(Slot >= 0 && "No slot number for value!?!?");      
+    output_vbr((unsigned)Slot, Out);
+
+    // Output arg ID itself
+    Slot = Table.getValSlot(I->getOperand(i));
     assert(Slot >= 0 && "No slot number for value!?!?");      
     output_vbr((unsigned)Slot, Out);
   }
@@ -161,6 +206,10 @@
     assert(Slots[1] != -1 && "Cast return type unknown?");
     if (Slots[1] > MaxOpSlot) MaxOpSlot = Slots[1];
     NumOperands++;
+  } else if (I->getOpcode() == Instruction::Call &&  // Handle VarArg calls
+	     I->getOperand(0)->getType()->isMethodType()->isVarArg()) {
+    outputInstrVarArgsCall(I, Table, Type, Out);
+    return false;
   }
 
   // Decide which instruction encoding to use.  This is determined primarily by