From e5a57ee363ecceb1f0047da7d8e72460965ec102 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 25 Jul 2001 22:47:55 +0000 Subject: [PATCH 1/1] 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 --- include/llvm/DerivedTypes.h | 4 +- include/llvm/iOther.h | 2 +- lib/Bytecode/Reader/ConstantReader.cpp | 10 ++--- lib/Bytecode/Reader/InstructionReader.cpp | 54 +++++++++++++++-------- lib/Bytecode/Writer/ConstantWriter.cpp | 8 +++- lib/Bytecode/Writer/InstructionWriter.cpp | 53 +++++++++++++++++++++- lib/VMCore/AsmWriter.cpp | 7 ++- lib/VMCore/Type.cpp | 26 ++++++----- lib/VMCore/iCall.cpp | 10 ++--- 9 files changed, 129 insertions(+), 45 deletions(-) diff --git a/include/llvm/DerivedTypes.h b/include/llvm/DerivedTypes.h index c5a3abdfe48..6b3fd1fc48b 100644 --- a/include/llvm/DerivedTypes.h +++ b/include/llvm/DerivedTypes.h @@ -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 &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; } diff --git a/include/llvm/iOther.h b/include/llvm/iOther.h index e522e1453d2..5dc736510d5 100644 --- a/include/llvm/iOther.h +++ b/include/llvm/iOther.h @@ -111,7 +111,7 @@ public: class CallInst : public Instruction { CallInst(const CallInst &CI); public: - CallInst(Method *M, vector ¶ms, const string &Name = ""); + CallInst(Method *M, const vector ¶ms, const string &Name = ""); virtual const char *getOpcodeName() const { return "call"; } diff --git a/lib/Bytecode/Reader/ConstantReader.cpp b/lib/Bytecode/Reader/ConstantReader.cpp index 2994128f7d6..e367d02e7cf 100644 --- a/lib/Bytecode/Reader/ConstantReader.cpp +++ b/lib/Bytecode/Reader/ConstantReader.cpp @@ -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); diff --git a/lib/Bytecode/Reader/InstructionReader.cpp b/lib/Bytecode/Reader/InstructionReader.cpp index 3af40f2d813..f1dcf08e793 100644 --- a/lib/Bytecode/Reader/InstructionReader.cpp +++ b/lib/Bytecode/Reader/InstructionReader.cpp @@ -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 Params; const MethodType::ParamTypes &PL = M->getMethodType()->getParamTypes(); - MethodType::ParamTypes::const_iterator It = PL.begin(); - vector 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 &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 &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 &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 7e2c9307b99..bac5a4c0502 100644 --- a/lib/Bytecode/Writer/ConstantWriter.cpp +++ b/lib/Bytecode/Writer/ConstantWriter.cpp @@ -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; } diff --git a/lib/Bytecode/Writer/InstructionWriter.cpp b/lib/Bytecode/Writer/InstructionWriter.cpp index a9b5e8d3041..18140772a39 100644 --- a/lib/Bytecode/Writer/InstructionWriter.cpp +++ b/lib/Bytecode/Writer/InstructionWriter.cpp @@ -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] +// +static void outputInstrVarArgsCall(const Instruction *I, + const SlotCalculator &Table, unsigned Type, + vector &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 diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 1719bc532f8..cc62e6007df 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -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); diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index 2adba049bc7..9d09e295073 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -143,8 +143,10 @@ const Type *Type::VoidTy = new Type("void" , VoidTyID), //===----------------------------------------------------------------------===// MethodType::MethodType(const Type *Result, const vector &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 &Params) { static vector 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 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 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; } diff --git a/lib/VMCore/iCall.cpp b/lib/VMCore/iCall.cpp index 67826ff4bcb..22e238a2cfd 100644 --- a/lib/VMCore/iCall.cpp +++ b/lib/VMCore/iCall.cpp @@ -8,7 +8,7 @@ #include "llvm/DerivedTypes.h" #include "llvm/Method.h" -CallInst::CallInst(Method *M, vector ¶ms, +CallInst::CallInst(Method *M, const vector ¶ms, const string &Name) : Instruction(M->getReturnType(), Instruction::Call, Name) { @@ -17,14 +17,14 @@ CallInst::CallInst(Method *M, vector ¶ms, 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) -- 2.34.1