mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-03-20 11:32:33 +00:00
New revised variable argument handling support
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@9219 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8d1a81d524
commit
99e7ab72c8
include/llvm
lib/AsmParser
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
virtual Instruction *clone() const { return new VarArgInst(*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<Instruction>(V) && classof(cast<Instruction>(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 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<Instruction>(V) && classof(cast<Instruction>(V));
|
||||
|
@ -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); }
|
||||
|
@ -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<PointerType>(RetTy)->getElementType();
|
||||
Function *NF = Result->getOrInsertFunction("llvm.va_start", RetTy, 0);
|
||||
|
||||
while (!F->use_empty()) {
|
||||
CallInst *CI = cast<CallInst>(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<PointerType>(ArgTy)->getElementType();
|
||||
Function *NF = Result->getOrInsertFunction("llvm.va_end", Type::VoidTy,
|
||||
ArgTy, 0);
|
||||
|
||||
while (!F->use_empty()) {
|
||||
CallInst *CI = cast<CallInst>(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<PointerType>(ArgTy)->getElementType();
|
||||
Function *NF = Result->getOrInsertFunction("llvm.va_copy", ArgTy,
|
||||
ArgTy, 0);
|
||||
|
||||
while (!F->use_empty()) {
|
||||
CallInst *CI = cast<CallInst>(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 <OtherOpVal> ShiftOps
|
||||
%token <OtherOpVal> PHI CALL CAST SHL SHR VA_ARG
|
||||
%token <OtherOpVal> 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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user