diff --git a/ast.cpp b/ast.cpp index 16732bc3..d6c51fe1 100644 --- a/ast.cpp +++ b/ast.cpp @@ -36,9 +36,7 @@ */ #include "ast.h" -#include "decl.h" #include "func.h" -#include "type.h" #include "sym.h" /////////////////////////////////////////////////////////////////////////// @@ -52,8 +50,8 @@ ASTNode::~ASTNode() { // AST void -AST::AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code) { - functions.push_back(new Function(ds, decl, code)); +AST::AddFunction(Symbol *sym, const std::vector &args, Stmt *code) { + functions.push_back(new Function(sym, args, code)); } diff --git a/ast.h b/ast.h index e5771deb..31c932b0 100644 --- a/ast.h +++ b/ast.h @@ -80,7 +80,8 @@ class AST { public: /** Add the AST for a function described by the given declaration information and source code. */ - void AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code); + void AddFunction(Symbol *sym, const std::vector &args, + Stmt *code); /** Generate LLVM IR for all of the functions into the current module. */ diff --git a/decl.cpp b/decl.cpp index 0ad0ea08..cfecf289 100644 --- a/decl.cpp +++ b/decl.cpp @@ -38,10 +38,13 @@ #include "decl.h" #include "util.h" +#include "module.h" #include "sym.h" #include "type.h" +#include "stmt.h" #include "expr.h" #include +#include /////////////////////////////////////////////////////////////////////////// // DeclSpecs @@ -117,6 +120,30 @@ Declarator::Print() const { } +void +Declarator::GetFunctionInfo(DeclSpecs *ds, Symbol **funSym, + std::vector *funArgs) { + // Get the symbol for the function from the symbol table. (It should + // already have been added to the symbol table by AddGlobal() by the + // time we get here.) + const FunctionType *type = + dynamic_cast(GetType(ds)); + assert(type != NULL); + *funSym = m->symbolTable->LookupFunction(sym->name.c_str(), type); + if (*funSym != NULL) + // May be NULL due to error earlier in compilation + (*funSym)->pos = pos; + + if (functionArgs != NULL) { + for (unsigned int i = 0; i < functionArgs->size(); ++i) { + Declaration *pdecl = (*functionArgs)[i]; + assert(pdecl->declarators.size() == 1); + funArgs->push_back(pdecl->declarators[0]->sym); + } + } +} + + static const Type * lGetType(const Declarator *decl, DeclSpecs *ds, std::vector::const_iterator arrayIter) { @@ -292,13 +319,43 @@ Declarator::GetType(DeclSpecs *ds) const { /////////////////////////////////////////////////////////////////////////// // Declaration -void -Declaration::AddSymbols(SymbolTable *st) const { - assert(declSpecs->storageClass != SC_TYPEDEF); - +Declaration::Declaration(DeclSpecs *ds, std::vector *dlist) { + declSpecs = ds; + if (dlist != NULL) + declarators = *dlist; for (unsigned int i = 0; i < declarators.size(); ++i) - if (declarators[i]) - st->AddVariable(declarators[i]->sym); + if (declarators[i] != NULL) + declarators[i]->InitFromDeclSpecs(declSpecs); +} + + +Declaration::Declaration(DeclSpecs *ds, Declarator *d) { + declSpecs = ds; + if (d) { + d->InitFromDeclSpecs(ds); + declarators.push_back(d); + } +} + + +std::vector +Declaration::GetVariableDeclarations() const { + assert(declSpecs->storageClass != SC_TYPEDEF); + std::vector vars; + + for (unsigned int i = 0; i < declarators.size(); ++i) { + if (declarators[i] == NULL) + continue; + Declarator *decl = declarators[i]; + if (!decl || decl->isFunction) + continue; + + m->symbolTable->AddVariable(declarators[i]->sym); + + vars.push_back(VariableDeclaration(declarators[i]->sym, + declarators[i]->initExpr)); + } + return vars; } diff --git a/decl.h b/decl.h index dca751ba..a4d869ee 100644 --- a/decl.h +++ b/decl.h @@ -56,6 +56,11 @@ #include "ispc.h" +struct VariableDeclaration; + +class Declaration; +class Declarator; + enum StorageClass { SC_NONE, SC_EXTERN, @@ -137,6 +142,9 @@ public: DeclSpecs */ const Type *GetType(DeclSpecs *ds) const; + void GetFunctionInfo(DeclSpecs *ds, Symbol **sym, + std::vector *args); + void Print() const; const SourcePos pos; @@ -157,27 +165,13 @@ public: */ class Declaration { public: - Declaration(DeclSpecs *ds, std::vector *dlist = NULL) { - declSpecs = ds; - if (dlist != NULL) - declarators = *dlist; - for (unsigned int i = 0; i < declarators.size(); ++i) - if (declarators[i] != NULL) - declarators[i]->InitFromDeclSpecs(declSpecs); - } - Declaration(DeclSpecs *ds, Declarator *d) { - declSpecs = ds; - if (d) { - d->InitFromDeclSpecs(ds); - declarators.push_back(d); - } - } + Declaration(DeclSpecs *ds, std::vector *dlist = NULL); + Declaration(DeclSpecs *ds, Declarator *d); - /** Adds the symbols for the variables in the declaration to the symbol - table. */ - void AddSymbols(SymbolTable *st) const; void Print() const; + std::vector GetVariableDeclarations() const; + DeclSpecs *declSpecs; std::vector declarators; }; diff --git a/func.cpp b/func.cpp index ed15af49..5be26871 100644 --- a/func.cpp +++ b/func.cpp @@ -37,7 +37,6 @@ #include "func.h" #include "ctx.h" -#include "decl.h" #include "expr.h" #include "llvmutil.h" #include "module.h" @@ -67,7 +66,9 @@ #include #include -Function::Function(DeclSpecs *ds, Declarator *decl, Stmt *c) { +Function::Function(Symbol *s, const std::vector &a, Stmt *c) { + sym = s; + args = a; code = c; maskSymbol = m->symbolTable->LookupVariable("__mask"); @@ -80,37 +81,17 @@ Function::Function(DeclSpecs *ds, Declarator *decl, Stmt *c) { } if (g->debugPrint) { - printf("Add Function\n"); - ds->Print(); - printf("\n"); - decl->Print(); - printf("\n"); + printf("Add Function %s\n", sym->name.c_str()); code->Print(0); printf("\n\n\n"); } - // Get the symbol for the function from the symbol table. (It should - // already have been added to the symbol table by AddGlobal() by the - // time we get here.) - type = dynamic_cast(decl->GetType(ds)); + const FunctionType *type = dynamic_cast(sym->type); assert(type != NULL); - sym = m->symbolTable->LookupFunction(decl->sym->name.c_str(), type); - if (sym != NULL) - // May be NULL due to error earlier in compilation - sym->pos = decl->pos; - isExported = (ds->storageClass == SC_EXPORT); - - if (decl->functionArgs != NULL) { - for (unsigned int i = 0; i < decl->functionArgs->size(); ++i) { - Declaration *pdecl = (*decl->functionArgs)[i]; - assert(pdecl->declarators.size() == 1); - Symbol *sym = pdecl->declarators[0]->sym; - if (dynamic_cast(sym->type) == NULL) - sym->parentFunction = this; - args.push_back(sym); - } - } + for (unsigned int i = 0; i < args.size(); ++i) + if (dynamic_cast(args[i]->type) == NULL) + args[i]->parentFunction = this; if (type->isTask) { threadIndexSym = m->symbolTable->LookupVariable("threadIndex"); @@ -127,264 +108,18 @@ Function::Function(DeclSpecs *ds, Declarator *decl, Stmt *c) { } -/** Given an arbitrary type, see if it or any of the types contained in it - are varying. Returns true if so, false otherwise. -*/ -static bool -lRecursiveCheckVarying(const Type *t) { - t = t->GetBaseType(); - if (t->IsVaryingType()) return true; - - const StructType *st = dynamic_cast(t); - if (st) { - for (int i = 0; i < st->GetElementCount(); ++i) - if (lRecursiveCheckVarying(st->GetElementType(i))) - return true; - } - return false; -} - - -/** Given a Symbol representing a function parameter, see if it or any - contained types are varying. If so, issue an error. (This function - should only be called for parameters to 'export'ed functions, where - varying parameters is illegal. - */ -static void -lCheckForVaryingParameter(Symbol *sym) { - if (lRecursiveCheckVarying(sym->type)) { - const Type *t = sym->type->GetBaseType(); - if (dynamic_cast(t)) - Error(sym->pos, "Struct parameter \"%s\" with varying member(s) is illegal " - "in an exported function.", - sym->name.c_str()); - else - Error(sym->pos, "Varying parameter \"%s\" is illegal in an exported function.", - sym->name.c_str()); - } -} - - -/** Given a function type, loop through the function parameters and see if - any are StructTypes. If so, issue an error (this seems to be broken - currently). - - @todo Fix passing structs from C/C++ to ispc functions. - */ -static void -lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) { - const std::vector &argTypes = ftype->GetArgumentTypes(); - for (unsigned int i = 0; i < argTypes.size(); ++i) { - const Type *type = argTypes[i]; - if (dynamic_cast(type) != NULL) { - Error(pos, "Passing structs to/from application functions is currently broken. " - "Use a reference or const reference instead for now."); - return; - } - } -} - - -/** We've got a declaration for a function to process. This function does - all the work of creating the corresponding llvm::Function instance, - adding the symbol for the function to the symbol table and doing - various sanity checks. This function returns true upon success and - false if any errors were encountered. - */ -Symbol * -Function::InitFunctionSymbol(DeclSpecs *ds, Declarator *decl) { - // Make sure that we've got what we expect here - Symbol *funSym = decl->sym; - assert(decl->isFunction); - assert(decl->arraySize.size() == 0); - - // So far, so good. Go ahead and set the type of the function symbol - funSym->type = decl->GetType(ds); - - // If a global variable with the same name has already been declared - // issue an error. - if (m->symbolTable->LookupVariable(funSym->name.c_str()) != NULL) { - Error(decl->pos, "Function \"%s\" shadows previously-declared global variable. " - "Ignoring this definition.", - funSym->name.c_str()); - return NULL; - } - - if (ds->storageClass == SC_EXTERN_C) { - // Make sure the user hasn't supplied both an 'extern "C"' and a - // 'task' qualifier with the function - if (ds->typeQualifier & TYPEQUAL_TASK) { - Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern " - "function \"%s\". Ignoring this function.", funSym->name.c_str()); - return NULL; - } - std::vector *funcs; - funcs = m->symbolTable->LookupFunction(decl->sym->name.c_str()); - if (funcs != NULL) { - if (funcs->size() > 1) { - // Multiple functions with this name have already been declared; - // can't overload here - Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; " - "%d functions with the same name have already been declared.", - funSym->name.c_str(), (int)funcs->size()); - return NULL; - } - - // One function with the same name has been declared; see if it - // has the same type as this one, in which case it's ok. - if (Type::Equal((*funcs)[0]->type, funSym->type)) - return (*funcs)[0]; - else { - Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".", - funSym->name.c_str()); - return NULL; - } - } - } - - // We should have gotten a FunctionType back from the GetType() call above. - const FunctionType *functionType = - dynamic_cast(funSym->type); - assert(functionType != NULL); - - // Get the LLVM FunctionType - bool includeMask = (ds->storageClass != SC_EXTERN_C); - LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType = - functionType->LLVMFunctionType(g->ctx, includeMask); - if (llvmFunctionType == NULL) - return NULL; - - // And create the llvm::Function - llvm::GlobalValue::LinkageTypes linkage = (ds->storageClass == SC_STATIC || - (ds->typeQualifier & TYPEQUAL_INLINE)) ? - llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage; - std::string functionName = ((ds->storageClass == SC_EXTERN_C) ? - funSym->name : funSym->MangledName()); - if (g->mangleFunctionsWithTarget) - functionName += g->target.GetISAString(); - llvm::Function *function = - llvm::Function::Create(llvmFunctionType, linkage, functionName.c_str(), m->module); - - // Set function attributes: we never throw exceptions, and want to - // inline everything we can - function->setDoesNotThrow(true); - if (!(ds->storageClass == SC_EXTERN_C) && !g->generateDebuggingSymbols && - (ds->typeQualifier & TYPEQUAL_INLINE)) - function->addFnAttr(llvm::Attribute::AlwaysInline); - if (functionType->isTask) - // This also applies transitively to members I think? - function->setDoesNotAlias(1, true); - - // Make sure that the return type isn't 'varying' if the function is - // 'export'ed. - if (ds->storageClass == SC_EXPORT && - lRecursiveCheckVarying(functionType->GetReturnType())) - Error(decl->pos, "Illegal to return a \"varying\" type from exported function \"%s\"", - funSym->name.c_str()); - - if (functionType->isTask && (functionType->GetReturnType() != AtomicType::Void)) - Error(funSym->pos, "Task-qualified functions must have void return type."); - - if (functionType->isExported || functionType->isExternC) - lCheckForStructParameters(functionType, funSym->pos); - - // Loop over all of the arguments; process default values if present - // and do other checks and parameter attribute setting. - bool seenDefaultArg = false; - std::vector argDefaults; - int nArgs = decl->functionArgs ? decl->functionArgs->size() : 0; - for (int i = 0; i < nArgs; ++i) { - Declaration *pdecl = (*decl->functionArgs)[i]; - assert(pdecl->declarators.size() == 1); - Symbol *sym = pdecl->declarators[0]->sym; - - // If the function is exported, make sure that the parameter - // doesn't have any varying stuff going on in it. - if (ds->storageClass == SC_EXPORT) - lCheckForVaryingParameter(sym); - - // ISPC assumes that all memory passed in is aligned to the native - // width and that no pointers alias. (It should be possible to - // specify when this is not the case, but this should be the - // default.) Set parameter attributes accordingly. - if (!functionType->isTask && dynamic_cast(sym->type) != NULL) { - // NOTE: LLVM indexes function parameters starting from 1. - // This is unintuitive. - function->setDoesNotAlias(i+1, true); - int align = 4 * RoundUpPow2(g->target.nativeVectorWidth); - function->addAttribute(i+1, llvm::Attribute::constructAlignmentFromInt(align)); - } - - if (m->symbolTable->LookupFunction(sym->name.c_str()) != NULL) - Warning(sym->pos, "Function parameter \"%s\" shadows a function " - "declared in global scope.", sym->name.c_str()); - - // See if a default argument value was provided with the parameter - Expr *defaultValue = pdecl->declarators[0]->initExpr; - if (defaultValue != NULL) { - // If we have one, make sure it's a compile-time constant - seenDefaultArg = true; - defaultValue = defaultValue->TypeCheck(); - defaultValue = defaultValue->Optimize(); - defaultValue = dynamic_cast(defaultValue); - if (!defaultValue) { - Error(sym->pos, "Default value for parameter \"%s\" must be " - "a compile-time constant.", sym->name.c_str()); - return NULL; - } - } - else if (seenDefaultArg) { - // Once one parameter has provided a default value, then all of - // the following ones must have them as well. - Error(sym->pos, "Parameter \"%s\" is missing default: all parameters after " - "the first parameter with a default value must have default values " - "as well.", sym->name.c_str()); - } - - // Add the default value to argDefaults. Note that we make this - // call for all parameters, even those where no default value was - // provided. In that case, a NULL value is stored here. This - // approach means that we can always just look at the i'th entry of - // argDefaults to find the default value for the i'th parameter. - argDefaults.push_back(dynamic_cast(defaultValue)); - } - - // And only now can we set the default values in the FunctionType - functionType->SetArgumentDefaults(argDefaults); - - // If llvm gave us back a Function * with a different name than the one - // we asked for, then there's already a function with that same - // (mangled) name in the llvm::Module. In that case, erase the one we - // tried to add and just work with the one it already had. - if (function->getName() != functionName) { - function->eraseFromParent(); - function = m->module->getFunction(functionName); - } - funSym->function = function; - - // But if that function has a definition, we don't want to redefine it. - if (!function->empty()) { - Warning(funSym->pos, "Ignoring redefinition of function \"%s\".", - funSym->name.c_str()); - return NULL; - } - - // Finally, we know all is good and we can add the function to the - // symbol table - bool ok = m->symbolTable->AddFunction(funSym); - assert(ok); - return funSym; -} - - const Type * Function::GetReturnType() const { + const FunctionType *type = dynamic_cast(sym->type); + assert(type != NULL); return type->GetReturnType(); } const FunctionType * Function::GetType() const { + const FunctionType *type = dynamic_cast(sym->type); + assert(type != NULL); return type; } @@ -444,6 +179,8 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function, #if 0 llvm::BasicBlock *entryBBlock = ctx->GetCurrentBasicBlock(); #endif + const FunctionType *type = dynamic_cast(sym->type); + assert(type != NULL); if (type->isTask == true) { // For tasks, we there should always be three parmeters: the // pointer to the structure that holds all of the arguments, the @@ -612,7 +349,9 @@ Function::GenerateIR() { // If the function is 'export'-qualified, emit a second version of // it without a mask parameter and without name mangling so that // the application can call it - if (isExported) { + const FunctionType *type = dynamic_cast(sym->type); + assert(type != NULL); + if (type->isExported) { if (!type->isTask) { LLVM_TYPE_CONST llvm::FunctionType *ftype = type->LLVMFunctionType(g->ctx); diff --git a/func.h b/func.h index 5923b9d2..d0bf0731 100644 --- a/func.h +++ b/func.h @@ -43,9 +43,7 @@ class Function { public: - Function(DeclSpecs *ds, Declarator *decl, Stmt *code); - - static Symbol *InitFunctionSymbol(DeclSpecs *ds, Declarator *decl); + Function(Symbol *sym, const std::vector &args, Stmt *code); const Type *GetReturnType() const; const FunctionType *GetType() const; @@ -58,10 +56,8 @@ private: SourcePos firstStmtPos); Symbol *sym; - const FunctionType *type; std::vector args; Stmt *code; - bool isExported; Symbol *maskSymbol; Symbol *threadIndexSym, *threadCountSym; Symbol *taskIndexSym, *taskCountSym; diff --git a/ispc.h b/ispc.h index a2cacc99..fed84bda 100644 --- a/ispc.h +++ b/ispc.h @@ -84,9 +84,6 @@ namespace llvm { class ArrayType; class AtomicType; -class DeclSpecs; -class Declaration; -class Declarator; class FunctionEmitContext; class Expr; class ExprList; @@ -97,6 +94,7 @@ class Stmt; class Symbol; class SymbolTable; class Type; +struct VariableDeclaration; /** @brief Representation of a range of positions in a source file. diff --git a/lex.ll b/lex.ll index d083de47..f2487a34 100644 --- a/lex.ll +++ b/lex.ll @@ -34,13 +34,13 @@ %{ #include "ispc.h" -#include "decl.h" #include "sym.h" #include "util.h" #include "module.h" #include "type.h" #include "parse.hh" #include +#include static uint64_t lParseBinary(const char *ptr, SourcePos pos); static void lCComment(SourcePos *); diff --git a/module.cpp b/module.cpp index bdc629b1..d58c7349 100644 --- a/module.cpp +++ b/module.cpp @@ -41,7 +41,6 @@ #include "ctx.h" #include "func.h" #include "builtins.h" -#include "decl.h" #include "type.h" #include "expr.h" #include "sym.h" @@ -95,9 +94,10 @@ // Module Module::Module(const char *fn) { - // FIXME: It's a hack to do this here, but it must be done after the - // target information has been set (so e.g. the vector width is - // known...) + // It's a hack to do this here, but it must be done after the target + // information has been set (so e.g. the vector width is known...) In + // particular, if we're compiling to multiple targets with different + // vector widths, this needs to be redone each time through. InitLLVMUtil(g->ctx, g->target); filename = fn; @@ -209,130 +209,358 @@ Module::CompileFile() { void -Module::AddGlobal(DeclSpecs *ds, Declarator *decl) { - // This function is called for a number of cases: function - // declarations, typedefs, and global variables declarations / - // definitions. Figure out what we've got and take care of it. +Module::AddTypeDef(Symbol *sym) { + // Typedefs are easy; just add the mapping between the given name and + // the given type. + symbolTable->AddType(sym->name.c_str(), sym->type, sym->pos); +} - if (ds == NULL || decl == NULL) - // Error happened earlier during parsing + +void +Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) { + // These may be NULL due to errors in parsing; just gracefully return + // here if so. + if (sym == NULL || sym->type == NULL) { + // But if these are NULL and there haven't been any previous + // errors, something surprising is going on + assert(errorCount > 0); return; - - if (decl->isFunction) { - // function declaration - const Type *t = decl->GetType(ds); - const FunctionType *ft = dynamic_cast(t); - assert(ft != NULL); - if (m->symbolTable->LookupFunction(decl->sym->name.c_str(), ft) != NULL) - // Ignore redeclaration of a function with the same name and type - return; - // Otherwise do all of the llvm Module and SymbolTable work.. - Function::InitFunctionSymbol(ds, decl); } - else if (ds->storageClass == SC_TYPEDEF) { - // Typedefs are easy; just add the mapping between the given name - // and the given type. - m->symbolTable->AddType(decl->sym->name.c_str(), decl->sym->type, - decl->sym->pos); + + if (symbolTable->LookupFunction(sym->name.c_str()) != NULL) { + Error(sym->pos, "Global variable \"%s\" shadows previously-declared function.", + sym->name.c_str()); + return; } - else { - // global variable - if (m->symbolTable->LookupFunction(decl->sym->name.c_str()) != NULL) { - Error(decl->pos, "Global variable \"%s\" shadows previously-declared function.", - decl->sym->name.c_str()); - return; - } - // These may be NULL due to errors in parsing; just gracefully - // return here if so. - if (!decl->sym || !decl->sym->type) { - // But if these are NULL and there haven't been any previous - // errors, something surprising is going on - assert(errorCount > 0); - return; - } + if (sym->storageClass == SC_EXTERN_C) { + Error(sym->pos, "extern \"C\" qualifier can only be used for functions."); + return; + } - if (ds->storageClass == SC_EXTERN_C) { - Error(decl->pos, "extern \"C\" qualifier can only be used for functions."); - return; - } + LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx); - LLVM_TYPE_CONST llvm::Type *llvmType = decl->sym->type->LLVMType(g->ctx); + // See if we have an initializer expression for the global. If so, + // make sure it's a compile-time constant! + llvm::Constant *llvmInitializer = NULL; + if (sym->storageClass == SC_EXTERN || sym->storageClass == SC_EXTERN_C) { + if (initExpr != NULL) + Error(sym->pos, "Initializer can't be provided with \"extern\" " + "global variable \"%s\".", sym->name.c_str()); + } + else if (initExpr != NULL) { + initExpr = initExpr->TypeCheck(); + if (initExpr != NULL) { + // We need to make sure the initializer expression is + // the same type as the global. (But not if it's an + // ExprList; they don't have types per se / can't type + // convert themselves anyway.) + if (dynamic_cast(initExpr) == NULL) + initExpr = initExpr->TypeConv(sym->type, "initializer"); - // See if we have an initializer expression for the global. If so, - // make sure it's a compile-time constant! - llvm::Constant *llvmInitializer = NULL; - if (ds->storageClass == SC_EXTERN || ds->storageClass == SC_EXTERN_C) { - if (decl->initExpr != NULL) - Error(decl->pos, "Initializer can't be provided with \"extern\" " - "global variable \"%s\".", decl->sym->name.c_str()); - } - else { - if (decl->initExpr != NULL) { - decl->initExpr = decl->initExpr->TypeCheck(); - if (decl->initExpr != NULL) { - // We need to make sure the initializer expression is - // the same type as the global. (But not if it's an - // ExprList; they don't have types per se / can't type - // convert themselves anyway.) - if (dynamic_cast(decl->initExpr) == NULL) - decl->initExpr = - decl->initExpr->TypeConv(decl->sym->type, "initializer"); + if (initExpr != NULL) { + initExpr = initExpr->Optimize(); + // Fingers crossed, now let's see if we've got a + // constant value.. + llvmInitializer = initExpr->GetConstant(sym->type); - if (decl->initExpr != NULL) { - decl->initExpr = decl->initExpr->Optimize(); - // Fingers crossed, now let's see if we've got a - // constant value.. - llvmInitializer = decl->initExpr->GetConstant(decl->sym->type); - - if (llvmInitializer != NULL) { - if (decl->sym->type->IsConstType()) - // Try to get a ConstExpr associated with - // the symbol. This dynamic_cast can - // validly fail, for example for types like - // StructTypes where a ConstExpr can't - // represent their values. - decl->sym->constValue = - dynamic_cast(decl->initExpr); - } - else - Error(decl->pos, "Initializer for global variable \"%s\" " - "must be a constant.", decl->sym->name.c_str()); - } + if (llvmInitializer != NULL) { + if (sym->type->IsConstType()) + // Try to get a ConstExpr associated with + // the symbol. This dynamic_cast can + // validly fail, for example for types like + // StructTypes where a ConstExpr can't + // represent their values. + sym->constValue = + dynamic_cast(initExpr); } + else + Error(sym->pos, "Initializer for global variable \"%s\" " + "must be a constant.", sym->name.c_str()); } - - // If no initializer was provided or if we couldn't get a value - // above, initialize it with zeros.. - if (llvmInitializer == NULL) - llvmInitializer = llvm::Constant::getNullValue(llvmType); } + } - bool isConst = (ds->typeQualifier & TYPEQUAL_CONST) != 0; - llvm::GlobalValue::LinkageTypes linkage = - (ds->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage : - llvm::GlobalValue::ExternalLinkage; - decl->sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst, - linkage, llvmInitializer, - decl->sym->name.c_str()); - m->symbolTable->AddVariable(decl->sym); + // If no initializer was provided or if we couldn't get a value + // above, initialize it with zeros.. + if (llvmInitializer == NULL) + llvmInitializer = llvm::Constant::getNullValue(llvmType); - if (diBuilder && (ds->storageClass != SC_EXTERN)) { - llvm::DIFile file = decl->pos.GetDIFile(); - diBuilder->createGlobalVariable(decl->sym->name, - file, - decl->pos.first_line, - decl->sym->type->GetDIType(file), - (ds->storageClass == SC_STATIC), - decl->sym->storagePtr); + llvm::GlobalValue::LinkageTypes linkage = + (sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage : + llvm::GlobalValue::ExternalLinkage; + sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst, + linkage, llvmInitializer, + sym->name.c_str()); + symbolTable->AddVariable(sym); + + if (diBuilder && (sym->storageClass != SC_EXTERN)) { + llvm::DIFile file = sym->pos.GetDIFile(); + diBuilder->createGlobalVariable(sym->name, + file, + sym->pos.first_line, + sym->type->GetDIType(file), + (sym->storageClass == SC_STATIC), + sym->storagePtr); + } +} + + + + +/** Given an arbitrary type, see if it or any of the types contained in it + are varying. Returns true if so, false otherwise. +*/ +static bool +lRecursiveCheckVarying(const Type *t) { + t = t->GetBaseType(); + if (t->IsVaryingType()) return true; + + const StructType *st = dynamic_cast(t); + if (st) { + for (int i = 0; i < st->GetElementCount(); ++i) + if (lRecursiveCheckVarying(st->GetElementType(i))) + return true; + } + return false; +} + + +/** Given a Symbol representing a function parameter, see if it or any + contained types are varying. If so, issue an error. (This function + should only be called for parameters to 'export'ed functions, where + varying parameters is illegal. + */ +static void +lCheckForVaryingParameter(Symbol *sym) { + if (lRecursiveCheckVarying(sym->type)) { + const Type *t = sym->type->GetBaseType(); + if (dynamic_cast(t)) + Error(sym->pos, "Struct parameter \"%s\" with varying member(s) is illegal " + "in an exported function.", + sym->name.c_str()); + else + Error(sym->pos, "Varying parameter \"%s\" is illegal in an exported function.", + sym->name.c_str()); + } +} + + +/** Given a function type, loop through the function parameters and see if + any are StructTypes. If so, issue an error (this seems to be broken + currently). + + @todo Fix passing structs from C/C++ to ispc functions. + */ +static void +lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) { + const std::vector &argTypes = ftype->GetArgumentTypes(); + for (unsigned int i = 0; i < argTypes.size(); ++i) { + const Type *type = argTypes[i]; + if (dynamic_cast(type) != NULL) { + Error(pos, "Passing structs to/from application functions is currently broken. " + "Use a reference or const reference instead for now."); + return; } } } +/** We've got a declaration for a function to process. This function does + all the work of creating the corresponding llvm::Function instance, + adding the symbol for the function to the symbol table and doing + various sanity checks. This function returns true upon success and + false if any errors were encountered. + */ void -Module::AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code) { - ast->AddFunction(ds, decl, code); +Module::AddFunctionDeclaration(Symbol *funSym, + const std::vector &args, + bool isInline) { + // We should have gotten a FunctionType back from the GetType() call above. + const FunctionType *functionType = + dynamic_cast(funSym->type); + assert(functionType != NULL); + + // If a global variable with the same name has already been declared + // issue an error. + if (symbolTable->LookupVariable(funSym->name.c_str()) != NULL) { + Error(funSym->pos, "Function \"%s\" shadows previously-declared global variable. " + "Ignoring this definition.", + funSym->name.c_str()); + return; + } + + if (symbolTable->LookupFunction(funSym->name.c_str(), + functionType) != NULL) + // Ignore redeclaration of a function with the same name and type + return; + + if (funSym->storageClass == SC_EXTERN_C) { + // Make sure the user hasn't supplied both an 'extern "C"' and a + // 'task' qualifier with the function + if (functionType->isTask) { + Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern " + "function \"%s\". Ignoring this function.", funSym->name.c_str()); + return; + } + + std::vector *funcs = + symbolTable->LookupFunction(funSym->name.c_str()); + if (funcs != NULL) { + if (funcs->size() > 1) { + // Multiple functions with this name have already been declared; + // can't overload here + Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; " + "%d functions with the same name have already been declared.", + funSym->name.c_str(), (int)funcs->size()); + return; + } + + // One function with the same name has been declared; see if it + // has the same type as this one, in which case it's ok. + if (Type::Equal((*funcs)[0]->type, funSym->type)) + return; + else { + Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".", + funSym->name.c_str()); + return; + } + } + } + + // Get the LLVM FunctionType + bool includeMask = (funSym->storageClass != SC_EXTERN_C); + LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType = + functionType->LLVMFunctionType(g->ctx, includeMask); + if (llvmFunctionType == NULL) + return; + + // And create the llvm::Function + llvm::GlobalValue::LinkageTypes linkage = (funSym->storageClass == SC_STATIC || + isInline) ? + llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage; + std::string functionName = ((funSym->storageClass == SC_EXTERN_C) ? + funSym->name : funSym->MangledName()); + if (g->mangleFunctionsWithTarget) + functionName += g->target.GetISAString(); + llvm::Function *function = + llvm::Function::Create(llvmFunctionType, linkage, functionName.c_str(), + module); + + // Set function attributes: we never throw exceptions, and want to + // inline everything we can + function->setDoesNotThrow(true); + if (!(funSym->storageClass == SC_EXTERN_C) && + !g->generateDebuggingSymbols && + isInline) + function->addFnAttr(llvm::Attribute::AlwaysInline); + if (functionType->isTask) + // This also applies transitively to members I think? + function->setDoesNotAlias(1, true); + + // Make sure that the return type isn't 'varying' if the function is + // 'export'ed. + if (funSym->storageClass == SC_EXPORT && + lRecursiveCheckVarying(functionType->GetReturnType())) + Error(funSym->pos, "Illegal to return a \"varying\" type from exported " + "function \"%s\"", funSym->name.c_str()); + + if (functionType->isTask && (functionType->GetReturnType() != AtomicType::Void)) + Error(funSym->pos, "Task-qualified functions must have void return type."); + + if (functionType->isExported || functionType->isExternC) + lCheckForStructParameters(functionType, funSym->pos); + + // Loop over all of the arguments; process default values if present + // and do other checks and parameter attribute setting. + bool seenDefaultArg = false; + std::vector argDefaults; + for (unsigned int i = 0; i < args.size(); ++i) { + Symbol *argSym = args[i].sym; + + // If the function is exported, make sure that the parameter + // doesn't have any varying stuff going on in it. + if (funSym->storageClass == SC_EXPORT) + lCheckForVaryingParameter(argSym); + + // ISPC assumes that all memory passed in is aligned to the native + // width and that no pointers alias. (It should be possible to + // specify when this is not the case, but this should be the + // default.) Set parameter attributes accordingly. + if (!functionType->isTask && + dynamic_cast(argSym->type) != NULL) { + // NOTE: LLVM indexes function parameters starting from 1. + // This is unintuitive. + function->setDoesNotAlias(i+1, true); + int align = 4 * RoundUpPow2(g->target.nativeVectorWidth); + function->addAttribute(i+1, llvm::Attribute::constructAlignmentFromInt(align)); + } + + if (symbolTable->LookupFunction(argSym->name.c_str()) != NULL) + Warning(argSym->pos, "Function parameter \"%s\" shadows a function " + "declared in global scope.", argSym->name.c_str()); + + // See if a default argument value was provided with the parameter + Expr *defaultValue = args[i].init; + if (defaultValue != NULL) { + // If we have one, make sure it's a compile-time constant + seenDefaultArg = true; + defaultValue = defaultValue->TypeCheck(); + defaultValue = defaultValue->Optimize(); + defaultValue = dynamic_cast(defaultValue); + if (!defaultValue) { + Error(argSym->pos, "Default value for parameter \"%s\" must be " + "a compile-time constant.", argSym->name.c_str()); + return; + } + } + else if (seenDefaultArg) { + // Once one parameter has provided a default value, then all of + // the following ones must have them as well. + Error(argSym->pos, "Parameter \"%s\" is missing default: all " + "parameters after the first parameter with a default value " + "must have default values as well.", argSym->name.c_str()); + } + + // Add the default value to argDefaults. Note that we make this + // call for all parameters, even those where no default value was + // provided. In that case, a NULL value is stored here. This + // approach means that we can always just look at the i'th entry of + // argDefaults to find the default value for the i'th parameter. + argDefaults.push_back(dynamic_cast(defaultValue)); + } + + // And only now can we set the default values in the FunctionType + functionType->SetArgumentDefaults(argDefaults); + + // If llvm gave us back a Function * with a different name than the one + // we asked for, then there's already a function with that same + // (mangled) name in the llvm::Module. In that case, erase the one we + // tried to add and just work with the one it already had. + if (function->getName() != functionName) { + function->eraseFromParent(); + function = module->getFunction(functionName); + } + funSym->function = function; + + // But if that function has a definition, we don't want to redefine it. + if (!function->empty()) { + Warning(funSym->pos, "Ignoring redefinition of function \"%s\".", + funSym->name.c_str()); + return; + } + + // Finally, we know all is good and we can add the function to the + // symbol table + bool ok = symbolTable->AddFunction(funSym); + assert(ok); +} + + +void +Module::AddFunctionDefinition(Symbol *sym, const std::vector &args, + Stmt *code) { + ast->AddFunction(sym, args, code); } @@ -725,24 +953,6 @@ lPrintFunctionDeclarations(FILE *file, const std::vector &funcs) { } -/** Given an arbitrary type, see if it or any of the types contained in it - are varying. Returns true if so, false otherwise. -*/ -static bool -lRecursiveCheckVarying(const Type *t) { - t = t->GetBaseType(); - if (t->IsVaryingType()) return true; - - const StructType *st = dynamic_cast(t); - if (st) { - for (int i = 0; i < st->GetElementCount(); ++i) - if (lRecursiveCheckVarying(st->GetElementType(i))) - return true; - } - return false; -} - - static void lPrintExternGlobals(FILE *file, const std::vector &externGlobals) { for (unsigned int i = 0; i < externGlobals.size(); ++i) { diff --git a/module.h b/module.h index 4f3c548b..a61aad4a 100644 --- a/module.h +++ b/module.h @@ -58,13 +58,24 @@ public: SymbolTable. Returns the number of errors during compilation. */ int CompileFile(); - /** Adds the global variable described by the declaration information to - the module. */ - void AddGlobal(DeclSpecs *ds, Declarator *decl); + /** Add a named type definition to the module. */ + void AddTypeDef(Symbol *sym); + + /** Add a new global variable corresponding to the given Symbol to the + module. If non-NULL, initExpr gives the initiailizer expression + for the global's inital value. */ + void AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst); + + /** Add a declaration of the function defined by the given function + symbol with given arguments to the module. */ + void AddFunctionDeclaration(Symbol *funSym, + const std::vector &args, + bool isInline); /** Adds the function described by the declaration information and the provided statements to the module. */ - void AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code); + void AddFunctionDefinition(Symbol *sym, const std::vector &args, + Stmt *code); /** After a source file has been compiled, output can be generated in a number of different formats. */ diff --git a/parse.yy b/parse.yy index b9b1c6e4..53c97b9b 100644 --- a/parse.yy +++ b/parse.yy @@ -89,6 +89,7 @@ extern char *yytext; void yyerror(const char *s) { fprintf(stderr, "Parse error: %s\n", s); } +static void lAddDeclaration(DeclSpecs *ds, Declarator *decl); static void lAddFunctionParams(Declarator *decl); static void lAddMaskToSymbolTable(SourcePos pos); static void lAddThreadIndexCountToSymbolTable(SourcePos pos); @@ -460,7 +461,11 @@ constant_expression ; declaration_statement - : declaration { $$ = new DeclStmt(@1, $1, m->symbolTable); } + : declaration + { + std::vector vars = $1->GetVariableDeclarations(); + $$ = new DeclStmt(vars, @1); + } ; declaration @@ -1224,14 +1229,14 @@ external_declaration { if ($1 != NULL) for (unsigned int i = 0; i < $1->declarators.size(); ++i) - m->AddGlobal($1->declSpecs, $1->declarators[i]); + lAddDeclaration($1->declSpecs, $1->declarators[i]); } ; function_definition : declaration_specifiers declarator { - m->AddGlobal($1, $2); + lAddDeclaration($1, $2); lAddFunctionParams($2); lAddMaskToSymbolTable(@2); if ($1->typeQualifier & TYPEQUAL_TASK) @@ -1239,14 +1244,17 @@ function_definition } compound_statement { - m->AddFunction($1, $2, $4); + Symbol *sym; + std::vector args; + $2->GetFunctionInfo($1, &sym, &args); + m->AddFunctionDefinition(sym, args, $4); m->symbolTable->PopScope(); // push in lAddFunctionParams(); } /* function with no declared return type?? func(...) | declarator { lAddFunctionParams($1); } compound_statement { - m->AddFunction(new DeclSpecs(, $1, $3); + m->AddFunction(new DeclSpecs(XXX, $1, $3); m->symbolTable->PopScope(); // push in lAddFunctionParams(); } */ @@ -1255,6 +1263,48 @@ func(...) %% +static void +lAddDeclaration(DeclSpecs *ds, Declarator *decl) { + if (ds == NULL || decl == NULL) + // Error happened earlier during parsing + return; + + if (decl->isFunction) { + // function declaration + const Type *t = decl->GetType(ds); + const FunctionType *ft = dynamic_cast(t); + assert(ft != NULL); + + // Make sure that we've got what we expect here + Symbol *funSym = decl->sym; + assert(decl->isFunction); + assert(decl->arraySize.size() == 0); + + // So far, so good. Go ahead and set the type of the function symbol + funSym->type = decl->GetType(ds); + funSym->storageClass = ds->storageClass; + + std::vector args; + int nArgs = decl->functionArgs ? decl->functionArgs->size() : 0; + for (int i = 0; i < nArgs; ++i) { + Declaration *pdecl = (*decl->functionArgs)[i]; + assert(pdecl->declarators.size() == 1); + Symbol *sym = pdecl->declarators[0]->sym; + Expr *defaultExpr = pdecl->declarators[0]->initExpr; + args.push_back(VariableDeclaration(sym, defaultExpr)); + } + + bool isInline = (ds->typeQualifier & TYPEQUAL_INLINE); + m->AddFunctionDeclaration(funSym, args, isInline); + } + else if (ds->storageClass == SC_TYPEDEF) + m->AddTypeDef(decl->sym); + else + m->AddGlobalVariable(decl->sym, decl->initExpr, + (ds->typeQualifier & TYPEQUAL_CONST) != 0); +} + + /** We're about to start parsing the body of a function; add all of the parameters to the symbol table so that they're available. */ diff --git a/stmt.cpp b/stmt.cpp index 364f931b..c2673112 100644 --- a/stmt.cpp +++ b/stmt.cpp @@ -40,7 +40,6 @@ #include "util.h" #include "expr.h" #include "type.h" -#include "decl.h" #include "sym.h" #include "module.h" #include "llvmutil.h" @@ -116,9 +115,8 @@ ExprStmt::EstimateCost() const { /////////////////////////////////////////////////////////////////////////// // DeclStmt -DeclStmt::DeclStmt(SourcePos p, Declaration *d, SymbolTable *s) - : Stmt(p), declaration(d) { - declaration->AddSymbols(s); +DeclStmt::DeclStmt(const std::vector &v, SourcePos p) + : Stmt(p), vars(v) { } @@ -240,16 +238,13 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { if (!ctx->GetCurrentBasicBlock()) return; - for (unsigned int i = 0; i < declaration->declarators.size(); ++i) { - Declarator *decl = declaration->declarators[i]; - if (!decl || decl->isFunction) - continue; - - Symbol *sym = decl->sym; - assert(decl->sym != NULL); + for (unsigned int i = 0; i < vars.size(); ++i) { + Symbol *sym = vars[i].sym; + assert(sym != NULL); const Type *type = sym->type; - if (!type) + if (type == NULL) continue; + Expr *initExpr = vars[i].init; // Now that we're in the thick of emitting code, it's easy for us // to find out the level of nesting of varying control flow we're @@ -265,7 +260,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { // initializer list to finally set the array's size. const ArrayType *at = dynamic_cast(type); if (at && at->GetElementCount() == 0) { - ExprList *exprList = dynamic_cast(decl->initExpr); + ExprList *exprList = dynamic_cast(initExpr); if (exprList) { ArrayType *t = at->GetSizedArray(exprList->exprs.size()); assert(t != NULL); @@ -280,7 +275,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { } // References must have initializer expressions as well. - if (dynamic_cast(type) && decl->initExpr == NULL) { + if (dynamic_cast(type) && initExpr == NULL) { Error(sym->pos, "Must provide initializer for reference-type variable \"%s\".", sym->name.c_str()); @@ -290,18 +285,18 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { LLVM_TYPE_CONST llvm::Type *llvmType = type->LLVMType(g->ctx); assert(llvmType != NULL); - if (declaration->declSpecs->storageClass == SC_STATIC) { + if (sym->storageClass == SC_STATIC) { // For static variables, we need a compile-time constant value // for its initializer; if there's no initializer, we use a // zero value. llvm::Constant *cinit = NULL; - if (decl->initExpr) { - cinit = decl->initExpr->GetConstant(type); - if (!cinit) + if (initExpr != NULL) { + cinit = initExpr->GetConstant(type); + if (cinit == NULL) Error(sym->pos, "Initializer for static variable \"%s\" must be a constant.", sym->name.c_str()); } - if (!cinit) + if (cinit == NULL) cinit = llvm::Constant::getNullValue(llvmType); // Allocate space for the static variable in global scope, so @@ -323,7 +318,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { ctx->EmitVariableDebugInfo(sym); // And then get it initialized... sym->parentFunction = ctx->GetFunction(); - lInitSymbol(sym->storagePtr, sym->name.c_str(), type, decl->initExpr, + lInitSymbol(sym->storagePtr, sym->name.c_str(), type, initExpr, ctx, sym->pos); } } @@ -332,10 +327,10 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { Stmt * DeclStmt::Optimize() { - for (unsigned int i = 0; i < declaration->declarators.size(); ++i) { - Declarator *decl = declaration->declarators[i]; - if (decl && decl->initExpr) { - decl->initExpr = decl->initExpr->Optimize(); + for (unsigned int i = 0; i < vars.size(); ++i) { + if (vars[i].init != NULL) { + vars[i].init = vars[i].init->Optimize(); + Expr *init = vars[i].init; // If the variable is const-qualified, after we've optimized // the initializer expression, see if we have a ConstExpr. If @@ -352,11 +347,11 @@ DeclStmt::Optimize() { // is definitely a compile-time constant for things like // computing array sizes from non-trivial expressions is // consequently limited. - Symbol *sym = decl->sym; - if (sym->type && sym->type->IsConstType() && decl->initExpr && - dynamic_cast(decl->initExpr) == NULL && - Type::Equal(decl->initExpr->GetType(), sym->type)) - sym->constValue = dynamic_cast(decl->initExpr); + Symbol *sym = vars[i].sym; + if (sym->type && sym->type->IsConstType() && init != NULL && + dynamic_cast(init) == NULL && + Type::Equal(init->GetType(), sym->type)) + sym->constValue = dynamic_cast(init); } } return this; @@ -366,30 +361,29 @@ DeclStmt::Optimize() { Stmt * DeclStmt::TypeCheck() { bool encounteredError = false; - for (unsigned int i = 0; i < declaration->declarators.size(); ++i) { - Declarator *decl = declaration->declarators[i]; - if (!decl) { + for (unsigned int i = 0; i < vars.size(); ++i) { + if (!vars[i].sym) { encounteredError = true; continue; } - if (!decl->initExpr) + if (vars[i].init == NULL) continue; - decl->initExpr = decl->initExpr->TypeCheck(); - if (!decl->initExpr) + vars[i].init = vars[i].init->TypeCheck(); + if (vars[i].init == NULL) continue; // get the right type for stuff like const float foo = 2; so that // the int->float type conversion is in there and we don't return // an int as the constValue later... - const Type *type = decl->sym->type; + const Type *type = vars[i].sym->type; if (dynamic_cast(type) != NULL || dynamic_cast(type) != NULL) { // If it's an expr list with an atomic type, we'll later issue // an error. Need to leave decl->initExpr as is in that case so it // is in fact caught later, though. - if (dynamic_cast(decl->initExpr) == NULL) - decl->initExpr = decl->initExpr->TypeConv(type, "initializer"); + if (dynamic_cast(vars[i].init) == NULL) + vars[i].init = vars[i].init->TypeConv(type, "initializer"); } } return encounteredError ? NULL : this; @@ -400,8 +394,16 @@ void DeclStmt::Print(int indent) const { printf("%*cDecl Stmt:", indent, ' '); pos.Print(); - if (declaration) - declaration->Print(); + for (unsigned int i = 0; i < vars.size(); ++i) { + printf("%*cVariable %s (%s)", indent+4, ' ', + vars[i].sym->name.c_str(), + vars[i].sym->type->GetString().c_str()); + if (vars[i].init != NULL) { + printf(" = "); + vars[i].init->Print(); + } + printf("\n"); + } printf("\n"); } @@ -409,9 +411,9 @@ DeclStmt::Print(int indent) const { int DeclStmt::EstimateCost() const { int cost = 0; - for (unsigned int i = 0; i < declaration->declarators.size(); ++i) - if (declaration->declarators[i]->initExpr) - cost += declaration->declarators[i]->initExpr->EstimateCost(); + for (unsigned int i = 0; i < vars.size(); ++i) + if (vars[i].init != NULL) + cost += vars[i].init->EstimateCost(); return cost; } @@ -716,8 +718,8 @@ lSafeToRunWithAllLanesOff(Stmt *stmt) { DeclStmt *ds; if ((ds = dynamic_cast(stmt)) != NULL) { - for (unsigned int i = 0; i < ds->declaration->declarators.size(); ++i) - if (!lSafeToRunWithAllLanesOff(ds->declaration->declarators[i]->initExpr)) + for (unsigned int i = 0; i < ds->vars.size(); ++i) + if (!lSafeToRunWithAllLanesOff(ds->vars[i].init)) return false; return true; } diff --git a/stmt.h b/stmt.h index 1c7cc355..21d94420 100644 --- a/stmt.h +++ b/stmt.h @@ -82,11 +82,19 @@ public: }; +struct VariableDeclaration { + VariableDeclaration(Symbol *s = NULL, Expr *i = NULL) { + sym = s; init = i; + } + Symbol *sym; + Expr *init; +}; + /** @brief Statement representing a single declaration (which in turn may declare a number of variables. */ class DeclStmt : public Stmt { public: - DeclStmt(SourcePos pos, Declaration *declaration, SymbolTable *symbolTable); + DeclStmt(const std::vector &v, SourcePos pos); void EmitCode(FunctionEmitContext *ctx) const; void Print(int indent) const; @@ -95,7 +103,7 @@ public: Stmt *TypeCheck(); int EstimateCost() const; - Declaration *declaration; + std::vector vars; };