Add support for extern varargs methods & varargs method calls
authorChris Lattner <sabre@nondot.org>
Wed, 25 Jul 2001 22:47:55 +0000 (22:47 +0000)
committerChris Lattner <sabre@nondot.org>
Wed, 25 Jul 2001 22:47:55 +0000 (22:47 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DerivedTypes.h
include/llvm/iOther.h
lib/Bytecode/Reader/ConstantReader.cpp
lib/Bytecode/Reader/InstructionReader.cpp
lib/Bytecode/Writer/ConstantWriter.cpp
lib/Bytecode/Writer/InstructionWriter.cpp
lib/VMCore/AsmWriter.cpp
lib/VMCore/Type.cpp
lib/VMCore/iCall.cpp

index c5a3abdfe4804eaa1b21be264b1684e16bc4b201..6b3fd1fc48be6be6ccf9820e270c9a4c45c148f8 100644 (file)
@@ -24,6 +24,7 @@ public:
 private:
   const Type *ResultType;
   ParamTypes ParamTys;
+  bool isVarArgs;
 
   MethodType(const MethodType &);                   // Do not implement
   const MethodType &operator=(const MethodType &);  // Do not implement
@@ -34,9 +35,10 @@ protected:
 
   // Private ctor - Only can be created by a static member...
   MethodType(const Type *Result, const vector<const Type*> &Params, 
-             const string &Name);
+             bool IsVarArgs, const string &Name);
 public:
 
+  inline bool isVarArg() const { return isVarArgs; }
   inline const Type *getReturnType() const { return ResultType; }
   inline const ParamTypes &getParamTypes() const { return ParamTys; }
 
index e522e1453d25b513efd11d190121505d14725933..5dc736510d5615fb116dbe16f2fa00cab32830a7 100644 (file)
@@ -111,7 +111,7 @@ public:
 class CallInst : public Instruction {
   CallInst(const CallInst &CI);
 public:
-  CallInst(Method *M, vector<Value*> &params, const string &Name = "");
+  CallInst(Method *M, const vector<Value*> &params, const string &Name = "");
 
   virtual const char *getOpcodeName() const { return "call"; }
 
index 2994128f7d6d07c13734cd8a13e3d5d2b2d80dbd..e367d02e7cfc2a4b0299c46dbc0c6d40d98c16c5 100644 (file)
@@ -33,15 +33,15 @@ bool BytecodeParser::parseTypeConstant(const uchar *&Buf, const uchar *EndBuf,
     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);
index 3af40f2d8134876429951a58a411a86093c89642..f1dcf08e793215c970e44cc8785c6e9e92005c16 100644 (file)
@@ -196,30 +196,48 @@ bool BytecodeParser::ParseInstruction(const uchar *&Buf, const uchar *EndBuf,
     Method *M = (Method*)getValue(Raw.Ty, Raw.Arg1);
     if (M == 0) return true;
 
+    vector<Value *> Params;
     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]));
+    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;
index 7e2c9307b992a133b6f793a51189ec1710c6f7e9..bac5a4c0502a517b57340e423871060485930555 100644 (file)
@@ -28,6 +28,9 @@ void BytecodeWriter::outputType(const Type *T) {
     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 @@ void BytecodeWriter::outputType(const Type *T) {
       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;
   }
 
index a9b5e8d3041201b27910fb38a7b686469540dfc0..18140772a394e5947128074035b8dc52aac743ed 100644 (file)
@@ -35,8 +35,53 @@ static void outputInstructionFormat0(const Instruction *I,
   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 @@ bool BytecodeWriter::processInstruction(const Instruction *I) {
     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
index 1719bc532f881f252fb811d010fe7aaf00a6a4ae..cc62e6007df204972ffa937a899cf36ba7aa3e56 100644 (file)
@@ -107,7 +107,12 @@ bool AssemblyWriter::visitMethod(const Method *M) {
 
 bool AssemblyWriter::processConstPool(const ConstantPool &CP, bool isMethod) {
   // Done printing arguments...
-  if (isMethod) Out << ")\n";
+  if (isMethod) {
+    if (CP.getParentV()->castMethodAsserting()->getType()->
+       isMethodType()->isVarArg())
+      Out << ", ...";  // Output varargs portion of signature!
+    Out << ")\n";
+  }
 
   ModuleAnalyzer::processConstPool(CP, isMethod);
   
index 2adba049bc766659b4ed1fa2eae4f525b0f22d43..9d09e2950733685b4998c394acb48ec91981d27a 100644 (file)
@@ -143,8 +143,10 @@ const Type *Type::VoidTy   = new            Type("void"  , VoidTyID),
 //===----------------------------------------------------------------------===//
 
 MethodType::MethodType(const Type *Result, const vector<const Type*> &Params, 
-                       const string &Name) 
-  : Type(Name, MethodTyID), ResultType(Result), ParamTys(Params) {
+                       bool IsVarArgs, const string &Name) 
+  : Type(Name, MethodTyID), ResultType(Result), 
+    ParamTys(Params.begin(), Params.end()-IsVarArgs), 
+    isVarArgs(IsVarArgs) {
 }
 
 ArrayType::ArrayType(const Type *ElType, int NumEl, const string &Name) 
@@ -171,20 +173,23 @@ PointerType::PointerType(const Type *E)
 const MethodType *MethodType::getMethodType(const Type *ReturnType, 
                                             const vector<const Type*> &Params) {
   static vector<const MethodType*> ExistingMethodTypesCache;
+
+  bool IsVarArg = Params.size() && (Params[Params.size()-1] == Type::VoidTy);
+
   for (unsigned i = 0; i < ExistingMethodTypesCache.size(); ++i) {
     const MethodType *T = ExistingMethodTypesCache[i];
-    if (T->getReturnType() == ReturnType) {
+    if (T->getReturnType() == ReturnType && T->isVarArg() == IsVarArg) {
       const ParamTypes &EParams = T->getParamTypes();
-      ParamTypes::const_iterator I = Params.begin()
+      ParamTypes::const_iterator I = Params.begin(), EI = Params.end()-IsVarArg;
       ParamTypes::const_iterator J = EParams.begin(); 
-      for (; I != Params.end() && J != EParams.end(); ++I, ++J)
+      for (; I != EI && J != EParams.end(); ++I, ++J)
         if (*I != *J) break;  // These types aren't equal!
 
-      if (I == Params.end() && J == EParams.end()) {
+      if (I == EI && J == EParams.end()) {
 #if TEST_MERGE_TYPES == 2
         ostream_iterator<const Type*> out(cerr, ", ");
         cerr << "Type: \"";
-        copy(Params.begin(), Params.end(), out);
+        copy(Params.begin(), EI, out);
         cerr << "\"\nEquals: \"";
         copy(EParams.begin(), EParams.end(), out);
         cerr << "\"" << endl;
@@ -196,25 +201,26 @@ const MethodType *MethodType::getMethodType(const Type *ReturnType,
 #if TEST_MERGE_TYPES == 2
   ostream_iterator<const Type*> out(cerr, ", ");
   cerr << "Input Types: ";
-  copy(Params.begin(), Params.end(), out);
+  copy(Params.begin(), Params.end()-IsVarArg, out);
   cerr << endl;
 #endif
 
   // Calculate the string name for the new type...
   string Name = ReturnType->getName() + " (";
   for (ParamTypes::const_iterator I = Params.begin();  
-       I != Params.end(); ++I) {
+       I != (Params.end()-IsVarArg); ++I) {
     if (I != Params.begin())
       Name += ", ";
     Name += (*I)->getName();
   }
+  if (IsVarArg) Name += ", ...";
   Name += ")";
 
 #if TEST_MERGE_TYPES
   cerr << "Derived new type: " << Name << endl;
 #endif
 
-  MethodType *Result = new MethodType(ReturnType, Params, Name);
+  MethodType *Result = new MethodType(ReturnType, Params, IsVarArg, Name);
   ExistingMethodTypesCache.push_back(Result);
   return Result;
 }
index 67826ff4bcb5168d46c9f7c07945ab7a51eafc67..22e238a2cfd2dfbc0cdc7462e8e21ae0647b1afc 100644 (file)
@@ -8,7 +8,7 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/Method.h"
 
-CallInst::CallInst(Method *M, vector<Value*> &params, 
+CallInst::CallInst(Method *M, const vector<Value*> &params, 
                    const string &Name) 
   : Instruction(M->getReturnType(), Instruction::Call, Name) {
 
@@ -17,14 +17,14 @@ CallInst::CallInst(Method *M, vector<Value*> &params,
 
   const MethodType* MT = M->getMethodType();
   const MethodType::ParamTypes &PL = MT->getParamTypes();
-  assert(params.size() == PL.size() && "Calling a function with bad signature");
+  assert((params.size() == PL.size()) || 
+        (MT->isVarArg() && params.size() > PL.size()) &&
+        "Calling a function with bad signature");
 #ifndef NDEBUG
   MethodType::ParamTypes::const_iterator It = PL.begin();
 #endif
-  for (unsigned i = 0; i < params.size(); i++) {
-    assert(*It++ == params[i]->getType() && "Call Operands not correct type!");
+  for (unsigned i = 0; i < params.size(); i++)
     Operands.push_back(Use(params[i], this));
-  }
 }
 
 CallInst::CallInst(const CallInst &CI)