#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/SymbolTable.h"
+#include "llvm/Assembly/AutoUpgrade.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/MathExtras.h"
#include <algorithm>
#include <iostream>
#include <list>
#define YYERROR_VERBOSE 1
+static bool ObsoleteVarArgs;
+static bool NewVarArgs;
+static BasicBlock *CurBB;
+static GlobalVariable *CurGV;
+
+
// This contains info used when building the body of a function. It is
// destroyed when the function is completed.
//
ThrowException(UndefinedReferences);
}
+ // Rename any overloaded intrinsic functions.
+ for (Module::iterator FI = CurrentModule->begin(), FE =
+ CurrentModule->end(); FI != FE; ++FI)
+ UpgradeIntrinsicFunction(&(*FI));
+
Values.clear(); // Clear out function local definitions
Types.clear();
CurrentModule = 0;
}
-
// GetForwardRefForGlobal - Check to see if there is a forward reference
// for this global. If so, remove it from the GlobalRefs map and return it.
// If not, just return null.
case ValID::ConstUndefVal: // Is it an undef value?
return UndefValue::get(Ty);
+ case ValID::ConstZeroVal: // Is it a zero value?
+ return Constant::getNullValue(Ty);
+
case ValID::ConstantVal: // Fully resolved constant?
if (D.ConstantValue->getType() != Ty)
ThrowException("Constant expression type different from required type!");
/// ParseGlobalVariable - Handle parsing of a global. If Initializer is null,
/// this is a declaration, otherwise it is a definition.
-static void ParseGlobalVariable(char *NameStr,GlobalValue::LinkageTypes Linkage,
- bool isConstantGlobal, const Type *Ty,
- Constant *Initializer) {
+static GlobalVariable *
+ParseGlobalVariable(char *NameStr,GlobalValue::LinkageTypes Linkage,
+ bool isConstantGlobal, const Type *Ty,
+ Constant *Initializer) {
if (isa<FunctionType>(Ty))
ThrowException("Cannot declare global vars of function type!");
GV->setLinkage(Linkage);
GV->setConstant(isConstantGlobal);
InsertValue(GV, CurModule.Values);
- return;
+ return GV;
}
// If this global has a name, check to see if there is already a definition
if (isConstantGlobal)
EGV->setConstant(true);
EGV->setLinkage(Linkage);
- return;
+ return EGV;
}
ThrowException("Redefinition of global variable named '" + Name +
new GlobalVariable(Ty, isConstantGlobal, Linkage, Initializer, Name,
CurModule.CurrentModule);
InsertValue(GV, CurModule.Values);
+ return GV;
}
// setTypeName - Set the specified type to the name given. The name may be
}
-//===----------------------------------------------------------------------===//
-// RunVMAsmParser - Define an interface to this parser
-//===----------------------------------------------------------------------===//
-//
-Module *llvm::RunVMAsmParser(const std::string &Filename, FILE *F) {
- llvmAsmin = F;
- CurFilename = Filename;
- llvmAsmlineno = 1; // Reset the current line number...
+// common code from the two 'RunVMAsmParser' functions
+ static Module * RunParser(Module * M) {
- // Allocate a new module to read
- CurModule.CurrentModule = new Module(Filename);
+ llvmAsmlineno = 1; // Reset the current line number...
+ ObsoleteVarArgs = false;
+ NewVarArgs = false;
+ CurModule.CurrentModule = M;
yyparse(); // Parse the file, potentially throwing exception
Module *Result = ParserResult;
-
- llvmAsmin = stdin; // F is about to go away, don't use it anymore...
ParserResult = 0;
+ //Not all functions use vaarg, so make a second check for ObsoleteVarArgs
+ {
+ Function* F;
+ if ((F = Result->getNamedFunction("llvm.va_start"))
+ && F->getFunctionType()->getNumParams() == 0)
+ ObsoleteVarArgs = true;
+ if((F = Result->getNamedFunction("llvm.va_copy"))
+ && F->getFunctionType()->getNumParams() == 1)
+ ObsoleteVarArgs = true;
+ }
+
+ if (ObsoleteVarArgs && NewVarArgs)
+ ThrowException("This file is corrupt: it uses both new and old style varargs");
+
+ if(ObsoleteVarArgs) {
+ if(Function* F = Result->getNamedFunction("llvm.va_start")) {
+ if (F->arg_size() != 0)
+ ThrowException("Obsolete va_start takes 0 argument!");
+
+ //foo = va_start()
+ // ->
+ //bar = alloca typeof(foo)
+ //va_start(bar)
+ //foo = load bar
+
+ const Type* RetTy = Type::getPrimitiveType(Type::VoidTyID);
+ const Type* ArgTy = F->getFunctionType()->getReturnType();
+ const Type* ArgTyPtr = PointerType::get(ArgTy);
+ Function* NF = Result->getOrInsertFunction("llvm.va_start",
+ RetTy, ArgTyPtr, (Type *)0);
+
+ while (!F->use_empty()) {
+ CallInst* CI = cast<CallInst>(F->use_back());
+ AllocaInst* bar = new AllocaInst(ArgTy, 0, "vastart.fix.1", CI);
+ new CallInst(NF, bar, "", CI);
+ Value* foo = new LoadInst(bar, "vastart.fix.2", CI);
+ CI->replaceAllUsesWith(foo);
+ CI->getParent()->getInstList().erase(CI);
+ }
+ Result->getFunctionList().erase(F);
+ }
+
+ if(Function* F = Result->getNamedFunction("llvm.va_end")) {
+ if(F->arg_size() != 1)
+ ThrowException("Obsolete va_end takes 1 argument!");
+
+ //vaend foo
+ // ->
+ //bar = alloca 1 of typeof(foo)
+ //vaend bar
+ const Type* RetTy = Type::getPrimitiveType(Type::VoidTyID);
+ const Type* ArgTy = F->getFunctionType()->getParamType(0);
+ const Type* ArgTyPtr = PointerType::get(ArgTy);
+ Function* NF = Result->getOrInsertFunction("llvm.va_end",
+ RetTy, ArgTyPtr, (Type *)0);
+
+ while (!F->use_empty()) {
+ CallInst* CI = cast<CallInst>(F->use_back());
+ AllocaInst* bar = new AllocaInst(ArgTy, 0, "vaend.fix.1", CI);
+ new StoreInst(CI->getOperand(1), bar, CI);
+ new CallInst(NF, bar, "", CI);
+ CI->getParent()->getInstList().erase(CI);
+ }
+ Result->getFunctionList().erase(F);
+ }
+
+ if(Function* F = Result->getNamedFunction("llvm.va_copy")) {
+ if(F->arg_size() != 1)
+ ThrowException("Obsolete va_copy takes 1 argument!");
+ //foo = vacopy(bar)
+ // ->
+ //a = alloca 1 of typeof(foo)
+ //b = alloca 1 of typeof(foo)
+ //store bar -> b
+ //vacopy(a, b)
+ //foo = load a
+
+ const Type* RetTy = Type::getPrimitiveType(Type::VoidTyID);
+ const Type* ArgTy = F->getFunctionType()->getReturnType();
+ const Type* ArgTyPtr = PointerType::get(ArgTy);
+ Function* NF = Result->getOrInsertFunction("llvm.va_copy",
+ RetTy, ArgTyPtr, ArgTyPtr,
+ (Type *)0);
+
+ while (!F->use_empty()) {
+ CallInst* CI = cast<CallInst>(F->use_back());
+ AllocaInst* a = new AllocaInst(ArgTy, 0, "vacopy.fix.1", CI);
+ AllocaInst* b = new AllocaInst(ArgTy, 0, "vacopy.fix.2", CI);
+ new StoreInst(CI->getOperand(1), b, CI);
+ new CallInst(NF, a, b, "", CI);
+ Value* foo = new LoadInst(a, "vacopy.fix.3", CI);
+ CI->replaceAllUsesWith(foo);
+ CI->getParent()->getInstList().erase(CI);
+ }
+ Result->getFunctionList().erase(F);
+ }
+ }
+
return Result;
+
+ }
+
+//===----------------------------------------------------------------------===//
+// RunVMAsmParser - Define an interface to this parser
+//===----------------------------------------------------------------------===//
+//
+Module *llvm::RunVMAsmParser(const std::string &Filename, FILE *F) {
+ set_scan_file(F);
+
+ CurFilename = Filename;
+ return RunParser(new Module(CurFilename));
+}
+
+Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
+ set_scan_string(AsmString);
+
+ CurFilename = "from_memory";
+ if (M == NULL) {
+ return RunParser(new Module (CurFilename));
+ } else {
+ return RunParser(M);
+ }
}
%}
%token <StrVal> VAR_ID LABELSTR STRINGCONSTANT
%type <StrVal> Name OptName OptAssign
-
+%type <UIntVal> OptAlign OptCAlign
+%type <StrVal> OptSection SectionString
%token IMPLEMENTATION ZEROINITIALIZER TRUETOK FALSETOK BEGINTOK ENDTOK
-%token DECLARE GLOBAL CONSTANT VOLATILE
+%token DECLARE GLOBAL CONSTANT SECTION VOLATILE
%token TO DOTDOTDOT NULL_TOK UNDEF CONST INTERNAL LINKONCE WEAK APPENDING
-%token OPAQUE NOT EXTERNAL TARGET TRIPLE ENDIAN POINTERSIZE LITTLE BIG
+%token OPAQUE NOT EXTERNAL TARGET TRIPLE ENDIAN POINTERSIZE LITTLE BIG ALIGN
%token DEPLIBS CALL TAIL
%token CC_TOK CCC_TOK FASTCC_TOK COLDCC_TOK
%type <UIntVal> OptCallingConv
// Other Operators
%type <OtherOpVal> ShiftOps
-%token <OtherOpVal> PHI_TOK CAST SELECT SHL SHR VAARG VANEXT
+%token <OtherOpVal> PHI_TOK CAST SELECT SHL SHR VAARG EXTRACTELEMENT
+%token VAARG_old VANEXT_old //OBSOLETE
%start Module
$$ = $2;
};
+// OptAlign/OptCAlign - An optional alignment, and an optional alignment with
+// a comma before it.
+OptAlign : /*empty*/ { $$ = 0; } |
+ ALIGN EUINT64VAL {
+ $$ = $2;
+ if ($$ != 0 && !isPowerOf2_32($$))
+ ThrowException("Alignment must be a power of two!");
+};
+OptCAlign : /*empty*/ { $$ = 0; } |
+ ',' ALIGN EUINT64VAL {
+ $$ = $3;
+ if ($$ != 0 && !isPowerOf2_32($$))
+ ThrowException("Alignment must be a power of two!");
+};
+
+
+SectionString : SECTION STRINGCONSTANT {
+ for (unsigned i = 0, e = strlen($2); i != e; ++i)
+ if ($2[i] == '"' || $2[i] == '\\')
+ ThrowException("Invalid character in section name!");
+ $$ = $2;
+};
+
+OptSection : /*empty*/ { $$ = 0; } |
+ SectionString { $$ = $1; };
+
+// GlobalVarAttributes - Used to pass the attributes string on a global. CurGV
+// is set to be the global we are processing.
+//
+GlobalVarAttributes : /* empty */ {} |
+ ',' GlobalVarAttribute GlobalVarAttributes {};
+GlobalVarAttribute : SectionString {
+ CurGV->setSection($1);
+ free($1);
+ }
+ | ALIGN EUINT64VAL {
+ if ($2 != 0 && !isPowerOf2_32($2))
+ ThrowException("Alignment must be a power of two!");
+ CurGV->setAlignment($2);
+ };
+
//===----------------------------------------------------------------------===//
// Types includes all predefined types... except void, because it can only be
// used in specific contexts (function returning void for example). To have
}
| '<' EUINT64VAL 'x' UpRTypes '>' { // Packed array type?
const llvm::Type* ElemTy = $4->get();
- if ((unsigned)$2 != $2) {
+ if ((unsigned)$2 != $2)
ThrowException("Unsigned result not equal to signed result");
- }
- if(!ElemTy->isPrimitiveType()) {
+ if (!ElemTy->isPrimitiveType())
ThrowException("Elemental type of a PackedType must be primitive");
- }
+ if (!isPowerOf2_32($2))
+ ThrowException("Vector length should be a power of 2!");
$$ = new PATypeHolder(HandleUpRefs(PackedType::get(*$4, (unsigned)$2)));
delete $4;
}
| LogicalOps '(' ConstVal ',' ConstVal ')' {
if ($3->getType() != $5->getType())
ThrowException("Logical operator types must match!");
- if (!$3->getType()->isIntegral())
- ThrowException("Logical operands must have integral types!");
+ if (!$3->getType()->isIntegral()) {
+ if (!isa<PackedType>($3->getType()) ||
+ !cast<PackedType>($3->getType())->getElementType()->isIntegral())
+ ThrowException("Logical operator requires integral operands!");
+ }
$$ = ConstantExpr::get($1, $3, $5);
}
| SetCondOps '(' ConstVal ',' ConstVal ')' {
if (!$3->getType()->isInteger())
ThrowException("Shift constant expression requires integer operand!");
$$ = ConstantExpr::get($1, $3, $5);
+ }
+ | EXTRACTELEMENT '(' ConstVal ',' ConstVal ')' {
+ if (!isa<PackedType>($3->getType()))
+ ThrowException("First operand of extractelement must be "
+ "packed type!");
+ if ($5->getType() != Type::UIntTy)
+ ThrowException("Second operand of extractelement must be uint!");
+ $$ = ConstantExpr::getExtractElement($3, $5);
};
-
// ConstVector - A list of comma separated constants.
ConstVector : ConstVector ',' ConstVal {
($$ = $1)->push_back($3);
}
| ConstPool OptAssign OptLinkage GlobalType ConstVal {
if ($5 == 0) ThrowException("Global value initializer is not a constant!");
- ParseGlobalVariable($2, $3, $4, $5->getType(), $5);
+ CurGV = ParseGlobalVariable($2, $3, $4, $5->getType(), $5);
+ } GlobalVarAttributes {
+ CurGV = 0;
}
| ConstPool OptAssign EXTERNAL GlobalType Types {
- ParseGlobalVariable($2, GlobalValue::ExternalLinkage, $4, *$5, 0);
+ CurGV = ParseGlobalVariable($2, GlobalValue::ExternalLinkage,
+ $4, *$5, 0);
delete $5;
+ } GlobalVarAttributes {
+ CurGV = 0;
}
| ConstPool TARGET TargetDefinition {
}
$$ = 0;
};
-FunctionHeaderH : OptCallingConv TypesV Name '(' ArgList ')' {
+FunctionHeaderH : OptCallingConv TypesV Name '(' ArgList ')'
+ OptSection OptAlign {
UnEscapeLexed($3);
std::string FunctionName($3);
free($3); // Free strdup'd memory!
CurFun.FunctionStart(Fn);
Fn->setCallingConv($1);
+ Fn->setAlignment($8);
+ if ($7) {
+ Fn->setSection($7);
+ free($7);
+ }
// Add all of the arguments we parsed to the function...
if ($5) { // Is null if empty...
| UNDEF {
$$ = ValID::createUndef();
}
+ | ZEROINITIALIZER { // A vector zero constant.
+ $$ = ValID::createZeroInit();
+ }
| '<' ConstVector '>' { // Nonempty unsized packed vector
const Type *ETy = (*$2)[0]->getType();
int NumElements = $2->size();
$$ = $1;
}
| /* empty */ {
- $$ = getBBVal(ValID::create((int)CurFun.NextBBNum++), true);
+ $$ = CurBB = getBBVal(ValID::create((int)CurFun.NextBBNum++), true);
// Make sure to move the basic block to the correct location in the
// function, instead of leaving it inserted wherever it was first
BBL.splice(BBL.end(), BBL, $$);
}
| LABELSTR {
- $$ = getBBVal(ValID::create($1), true);
+ $$ = CurBB = getBBVal(ValID::create($1), true);
// Make sure to move the basic block to the correct location in the
// function, instead of leaving it inserted wherever it was first
delete $2;
}
| LogicalOps Types ValueRef ',' ValueRef {
- if (!(*$2)->isIntegral())
- ThrowException("Logical operator requires integral operands!");
+ if (!(*$2)->isIntegral()) {
+ if (!isa<PackedType>($2->get()) ||
+ !cast<PackedType>($2->get())->getElementType()->isIntegral())
+ ThrowException("Logical operator requires integral operands!");
+ }
$$ = BinaryOperator::create($1, getVal(*$2, $3), getVal(*$2, $5));
if ($$ == 0)
ThrowException("binary operator returned null!");
$$ = new SelectInst($2, $4, $6);
}
| VAARG ResolvedVal ',' Types {
+ NewVarArgs = true;
$$ = new VAArgInst($2, *$4);
delete $4;
}
- | VANEXT ResolvedVal ',' Types {
- $$ = new VANextInst($2, *$4);
+ | VAARG_old ResolvedVal ',' Types {
+ ObsoleteVarArgs = true;
+ const Type* ArgTy = $2->getType();
+ Function* NF = CurModule.CurrentModule->
+ getOrInsertFunction("llvm.va_copy", ArgTy, ArgTy, (Type *)0);
+
+ //b = vaarg a, t ->
+ //foo = alloca 1 of t
+ //bar = vacopy a
+ //store bar -> foo
+ //b = vaarg foo, t
+ AllocaInst* foo = new AllocaInst(ArgTy, 0, "vaarg.fix");
+ CurBB->getInstList().push_back(foo);
+ CallInst* bar = new CallInst(NF, $2);
+ CurBB->getInstList().push_back(bar);
+ CurBB->getInstList().push_back(new StoreInst(bar, foo));
+ $$ = new VAArgInst(foo, *$4);
delete $4;
}
+ | VANEXT_old ResolvedVal ',' Types {
+ ObsoleteVarArgs = true;
+ const Type* ArgTy = $2->getType();
+ Function* NF = CurModule.CurrentModule->
+ getOrInsertFunction("llvm.va_copy", ArgTy, ArgTy, (Type *)0);
+
+ //b = vanext a, t ->
+ //foo = alloca 1 of t
+ //bar = vacopy a
+ //store bar -> foo
+ //tmp = vaarg foo, t
+ //b = load foo
+ AllocaInst* foo = new AllocaInst(ArgTy, 0, "vanext.fix");
+ CurBB->getInstList().push_back(foo);
+ CallInst* bar = new CallInst(NF, $2);
+ CurBB->getInstList().push_back(bar);
+ CurBB->getInstList().push_back(new StoreInst(bar, foo));
+ Instruction* tmp = new VAArgInst(foo, *$4);
+ CurBB->getInstList().push_back(tmp);
+ $$ = new LoadInst(foo);
+ delete $4;
+ }
+ | EXTRACTELEMENT ResolvedVal ',' ResolvedVal {
+ if (!isa<PackedType>($2->getType()))
+ ThrowException("First operand of extractelement must be a "
+ "packed type val!");
+ if ($4->getType() != Type::UIntTy)
+ ThrowException("Second operand of extractelement must be a uint!");
+ $$ = new ExtractElementInst($2, $4);
+ }
| PHI_TOK PHIList {
const Type *Ty = $2->front().first->getType();
if (!Ty->isFirstClassType())
-MemoryInst : MALLOC Types {
- $$ = new MallocInst(*$2);
+MemoryInst : MALLOC Types OptCAlign {
+ $$ = new MallocInst(*$2, 0, $3);
delete $2;
}
- | MALLOC Types ',' UINT ValueRef {
- $$ = new MallocInst(*$2, getVal($4, $5));
+ | MALLOC Types ',' UINT ValueRef OptCAlign {
+ $$ = new MallocInst(*$2, getVal($4, $5), $6);
delete $2;
}
- | ALLOCA Types {
- $$ = new AllocaInst(*$2);
+ | ALLOCA Types OptCAlign {
+ $$ = new AllocaInst(*$2, 0, $3);
delete $2;
}
- | ALLOCA Types ',' UINT ValueRef {
- $$ = new AllocaInst(*$2, getVal($4, $5));
+ | ALLOCA Types ',' UINT ValueRef OptCAlign {
+ $$ = new AllocaInst(*$2, getVal($4, $5), $6);
delete $2;
}
| FREE ResolvedVal {