From 99e7ab72c8909469141358552ece13d701d17274 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 18 Oct 2003 05:53:13 +0000 Subject: [PATCH] New revised variable argument handling support git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@9219 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Instruction.def | 9 ++-- include/llvm/Intrinsics.h | 6 +-- include/llvm/Support/InstVisitor.h | 8 +-- include/llvm/iOther.h | 59 +++++++++++++++----- lib/AsmParser/Lexer.l | 6 ++- lib/AsmParser/llvmAsmParser.y | 107 +++++++++++++++++++++++++++++++++++-- 6 files changed, 167 insertions(+), 28 deletions(-) diff --git a/include/llvm/Instruction.def b/include/llvm/Instruction.def index ea3b71d53c8..4a78edfccc6 100644 --- a/include/llvm/Instruction.def +++ b/include/llvm/Instruction.def @@ -120,11 +120,12 @@ HANDLE_OTHER_INST(28, Call , CallInst ) // Call a function HANDLE_OTHER_INST(29, Shl , ShiftInst ) // Shift operations HANDLE_OTHER_INST(30, Shr , ShiftInst ) -HANDLE_OTHER_INST(31, VarArg , VarArgInst ) // va_arg instruction +HANDLE_OTHER_INST(31, VANext , VANextInst ) // vanext instruction +HANDLE_OTHER_INST(32, VAArg , VAArgInst ) // vaarg instruction -HANDLE_OTHER_INST(32, UserOp1, Instruction) // May be used internally in a pass -HANDLE_OTHER_INST(33, UserOp2, Instruction) - LAST_OTHER_INST(33) +HANDLE_OTHER_INST(33, UserOp1, Instruction) // May be used internally in a pass +HANDLE_OTHER_INST(34, UserOp2, Instruction) + LAST_OTHER_INST(34) #undef FIRST_TERM_INST #undef HANDLE_TERM_INST diff --git a/include/llvm/Intrinsics.h b/include/llvm/Intrinsics.h index 12cf378f651..dbc0273e897 100644 --- a/include/llvm/Intrinsics.h +++ b/include/llvm/Intrinsics.h @@ -18,9 +18,9 @@ namespace LLVMIntrinsic { not_intrinsic = 0, // Must be zero // Varargs handling intrinsics... - va_start, // Used to represent a va_start call in C - va_end, // Used to represent a va_end call in C - va_copy, // Used to represent a va_copy call in C + va_start, // Used to implement the va_start macro in C + va_end, // Used to implement the va_end macro in C + va_copy, // Used to implement the va_copy macro in C // Setjmp/Longjmp intrinsics... setjmp, // Used to represent a setjmp call in C diff --git a/include/llvm/Support/InstVisitor.h b/include/llvm/Support/InstVisitor.h index 9934522f456..f8298e313d8 100644 --- a/include/llvm/Support/InstVisitor.h +++ b/include/llvm/Support/InstVisitor.h @@ -136,7 +136,7 @@ struct InstVisitor { // #define HANDLE_INST(NUM, OPCODE, CLASS) \ RetTy visit##OPCODE(CLASS &I) { DELEGATE(CLASS); } -#define HANDLE_OTHER_INST(NUM, OPCODE, CLASS) // Ignore "other" instructions +#define HANDLE_OTHER_INST(NUM, OPCODE, CLASS) // Handle "other" insts specially #include "llvm/Instruction.def" // Implement all "other" instructions, except for PHINode @@ -144,7 +144,8 @@ struct InstVisitor { RetTy visitCall(CallInst &I) { DELEGATE(CallInst); } RetTy visitShr(ShiftInst &I) { DELEGATE(ShiftInst); } RetTy visitShl(ShiftInst &I) { DELEGATE(ShiftInst); } - RetTy visitVarArg(VarArgInst &I) { DELEGATE(VarArgInst); } + RetTy visitVANext(VANextInst &I) { DELEGATE(VANextInst); } + RetTy visitVAArg (VAArgInst &I) { DELEGATE(VAArgInst); } RetTy visitUserOp1(Instruction &I) { DELEGATE(Instruction); } RetTy visitUserOp2(Instruction &I) { DELEGATE(Instruction); } @@ -168,7 +169,8 @@ struct InstVisitor { RetTy visitCastInst(CastInst &I) { DELEGATE(Instruction); } RetTy visitCallInst(CallInst &I) { DELEGATE(Instruction); } RetTy visitShiftInst(ShiftInst &I) { DELEGATE(Instruction); } - RetTy visitVarArgInst(VarArgInst &I) { DELEGATE(Instruction); } + RetTy visitVANextInst(VANextInst &I) { DELEGATE(Instruction); } + RetTy visitVAArgInst(VAArgInst &I) { DELEGATE(Instruction); } // Next level propagators... if the user does not overload a specific // instruction type, they can overload one of these to get the whole class diff --git a/include/llvm/iOther.h b/include/llvm/iOther.h index 787483348fb..fa440acffa0 100644 --- a/include/llvm/iOther.h +++ b/include/llvm/iOther.h @@ -123,34 +123,67 @@ public: //===----------------------------------------------------------------------===// -// VarArgInst Class +// VANextInst Class //===----------------------------------------------------------------------===// -/// VarArgInst - This class represents the va_arg llvm instruction, which reads -/// an argument of the destination type from the va_list operand pointed to by -/// the only operand. +/// VANextInst - This class represents the va_next llvm instruction, which +/// advances a vararg list passed an argument of the specified type, returning +/// the resultant list. /// -class VarArgInst : public Instruction { - VarArgInst(const VarArgInst &VAI) : Instruction(VAI.getType(), VarArg) { +class VANextInst : public Instruction { + PATypeHolder ArgTy; + VANextInst(const VANextInst &VAN) + : Instruction(VAN.getType(), VANext), ArgTy(VAN.getArgType()) { Operands.reserve(1); - Operands.push_back(Use(VAI.Operands[0], this)); + Operands.push_back(Use(VAN.Operands[0], this)); } public: - VarArgInst(Value *S, const Type *Ty, const std::string &Name = "", + VANextInst(Value *List, const Type *Ty, const std::string &Name = "", Instruction *InsertBefore = 0) - : Instruction(Ty, VarArg, Name, InsertBefore) { + : Instruction(List->getType(), VANext, Name, InsertBefore), ArgTy(Ty) { Operands.reserve(1); - Operands.push_back(Use(S, this)); + Operands.push_back(Use(List, this)); + } + + const Type *getArgType() const { return ArgTy; } + + virtual Instruction *clone() const { return new VANextInst(*this); } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const VANextInst *) { return true; } + static inline bool classof(const Instruction *I) { + return I->getOpcode() == VANext; + } + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + +/// VAArgInst - This class represents the va_arg llvm instruction, which returns +/// an argument of the specified type given a va_list. +/// +class VAArgInst : public Instruction { + VAArgInst(const VAArgInst &VAA) + : Instruction(VAA.getType(), VAArg) { + Operands.reserve(1); + Operands.push_back(Use(VAA.Operands[0], this)); + } +public: + VAArgInst(Value *List, const Type *Ty, const std::string &Name = "", + Instruction *InsertBefore = 0) + : Instruction(Ty, VAArg, Name, InsertBefore) { + Operands.reserve(1); + Operands.push_back(Use(List, this)); } - virtual Instruction *clone() const { return new VarArgInst(*this); } + virtual Instruction *clone() const { return new VAArgInst(*this); } bool mayWriteToMemory() const { return true; } // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const VarArgInst *) { return true; } + static inline bool classof(const VAArgInst *) { return true; } static inline bool classof(const Instruction *I) { - return I->getOpcode() == VarArg; + return I->getOpcode() == VAArg; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); diff --git a/lib/AsmParser/Lexer.l b/lib/AsmParser/Lexer.l index 6c03d029be9..f0f007b4b3a 100644 --- a/lib/AsmParser/Lexer.l +++ b/lib/AsmParser/Lexer.l @@ -129,7 +129,7 @@ VarID %[-a-zA-Z$._][-a-zA-Z$._0-9]* Label [-a-zA-Z$._0-9]+: /* Quoted names can contain any character except " and \ */ -StringConstant \"[^\"]+\" +StringConstant \"[^\"]*\" /* [PN]Integer: match positive and negative literal integer values that @@ -224,7 +224,9 @@ call { RET_TOK(OtherOpVal, Call, CALL); } cast { RET_TOK(OtherOpVal, Cast, CAST); } shl { RET_TOK(OtherOpVal, Shl, SHL); } shr { RET_TOK(OtherOpVal, Shr, SHR); } -va_arg { RET_TOK(OtherOpVal, VarArg, VA_ARG); } +va_arg { return VA_ARG; /* FIXME: OBSOLETE */} +vanext { RET_TOK(OtherOpVal, VANext, VANEXT); } +vaarg { RET_TOK(OtherOpVal, VAArg , VAARG); } ret { RET_TOK(TermOpVal, Ret, RET); } br { RET_TOK(TermOpVal, Br, BR); } diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y index b14d6a7ecc0..efb9d3e8909 100644 --- a/lib/AsmParser/llvmAsmParser.y +++ b/lib/AsmParser/llvmAsmParser.y @@ -37,6 +37,14 @@ std::string CurFilename; #define YYERROR_VERBOSE 1 +// HACK ALERT: This variable is used to implement the automatic conversion of +// variable argument instructions from their old to new forms. When this +// compatiblity "Feature" is removed, this should be too. +// +static BasicBlock *CurBB; +static bool ObsoleteVarArgs; + + // This contains info used when building the body of a function. It is // destroyed when the function is completed. // @@ -595,11 +603,76 @@ Module *RunVMAsmParser(const std::string &Filename, FILE *F) { llvmAsmin = F; CurFilename = Filename; llvmAsmlineno = 1; // Reset the current line number... + ObsoleteVarArgs = false; // Allocate a new module to read CurModule.CurrentModule = new Module(Filename); yyparse(); // Parse the file. + Module *Result = ParserResult; + + // Check to see if they called va_start but not va_arg.. + if (!ObsoleteVarArgs) + if (Function *F = Result->getNamedFunction("llvm.va_start")) + if (F->asize() == 1) { + std::cerr << "WARNING: this file uses obsolete features. " + << "Assemble and disassemble to update it.\n"; + ObsoleteVarArgs = true; + } + + + if (ObsoleteVarArgs) { + // If the user is making use of obsolete varargs intrinsics, adjust them for + // the user. + if (Function *F = Result->getNamedFunction("llvm.va_start")) { + assert(F->asize() == 1 && "Obsolete va_start takes 1 argument!"); + + const Type *RetTy = F->getFunctionType()->getParamType(0); + RetTy = cast(RetTy)->getElementType(); + Function *NF = Result->getOrInsertFunction("llvm.va_start", RetTy, 0); + + while (!F->use_empty()) { + CallInst *CI = cast(F->use_back()); + Value *V = new CallInst(NF, "", CI); + new StoreInst(V, CI->getOperand(1), CI); + CI->getParent()->getInstList().erase(CI); + } + Result->getFunctionList().erase(F); + } + + if (Function *F = Result->getNamedFunction("llvm.va_end")) { + assert(F->asize() == 1 && "Obsolete va_end takes 1 argument!"); + const Type *ArgTy = F->getFunctionType()->getParamType(0); + ArgTy = cast(ArgTy)->getElementType(); + Function *NF = Result->getOrInsertFunction("llvm.va_end", Type::VoidTy, + ArgTy, 0); + + while (!F->use_empty()) { + CallInst *CI = cast(F->use_back()); + Value *V = new LoadInst(CI->getOperand(1), "", CI); + new CallInst(NF, V, "", CI); + CI->getParent()->getInstList().erase(CI); + } + Result->getFunctionList().erase(F); + } + + if (Function *F = Result->getNamedFunction("llvm.va_copy")) { + assert(F->asize() == 2 && "Obsolete va_copy takes 2 argument!"); + const Type *ArgTy = F->getFunctionType()->getParamType(0); + ArgTy = cast(ArgTy)->getElementType(); + Function *NF = Result->getOrInsertFunction("llvm.va_copy", ArgTy, + ArgTy, 0); + + while (!F->use_empty()) { + CallInst *CI = cast(F->use_back()); + Value *V = new CallInst(NF, CI->getOperand(2), "", CI); + new StoreInst(V, CI->getOperand(1), CI); + CI->getParent()->getInstList().erase(CI); + } + Result->getFunctionList().erase(F); + } + } + llvmAsmin = stdin; // F is about to go away, don't use it anymore... ParserResult = 0; @@ -712,7 +785,8 @@ Module *RunVMAsmParser(const std::string &Filename, FILE *F) { // Other Operators %type ShiftOps -%token PHI CALL CAST SHL SHR VA_ARG +%token PHI CALL CAST SHL SHR VAARG VANEXT +%token VA_ARG // FIXME: OBSOLETE %start Module %% @@ -1452,7 +1526,7 @@ InstructionList : InstructionList Inst { $$ = $1; } | /* empty */ { - $$ = new BasicBlock(); + $$ = CurBB = new BasicBlock(); }; BBTerminatorInst : RET ResolvedVal { // Return with a result... @@ -1643,7 +1717,34 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef { delete $4; } | VA_ARG ResolvedVal ',' Types { - $$ = new VarArgInst($2, *$4); + // FIXME: This is emulation code for an obsolete syntax. This should be + // removed at some point. + if (!ObsoleteVarArgs) { + std::cerr << "WARNING: this file uses obsolete features. " + << "Assemble and disassemble to update it.\n"; + ObsoleteVarArgs = true; + } + + // First, load the valist... + Instruction *CurVAList = new LoadInst($2, ""); + CurBB->getInstList().push_back(CurVAList); + + // Emit the vaarg instruction. + $$ = new VAArgInst(CurVAList, *$4); + + // Now we must advance the pointer and update it in memory. + Instruction *TheVANext = new VANextInst(CurVAList, *$4); + CurBB->getInstList().push_back(TheVANext); + + CurBB->getInstList().push_back(new StoreInst(TheVANext, $2)); + delete $4; + } + | VAARG ResolvedVal ',' Types { + $$ = new VAArgInst($2, *$4); + delete $4; + } + | VANEXT ResolvedVal ',' Types { + $$ = new VANextInst($2, *$4); delete $4; } | PHI PHIList { -- 2.11.0