From 7290f7b16b737538e9b36cacea1e2c2ea18a3e57 Mon Sep 17 00:00:00 2001 From: Matt Pharr Date: Mon, 7 Nov 2011 17:46:59 -0800 Subject: [PATCH] Generalize/improve parsing of pointer declarations. Substantial improvements and generalizations to the parsing and declaration handling code to properly parse declarations involving pointers. (No change to user-visible functionality, but this lays groundwork for supporting a more general pointer model.) --- ast.cpp | 2 + builtins.cpp | 8 - decl.cpp | 428 +++++++++++++++++++++----------------- decl.h | 41 ++-- expr.cpp | 2 +- module.cpp | 71 +++---- module.h | 6 +- parse.yy | 237 +++++++++++++++------ tests/funcptr-null-1.ispc | 2 +- tests/test-55.ispc | 2 +- type.cpp | 61 ++++-- type.h | 21 +- 12 files changed, 511 insertions(+), 370 deletions(-) diff --git a/ast.cpp b/ast.cpp index d6c51fe1..71dd06bb 100644 --- a/ast.cpp +++ b/ast.cpp @@ -51,6 +51,8 @@ ASTNode::~ASTNode() { void AST::AddFunction(Symbol *sym, const std::vector &args, Stmt *code) { + if (sym == NULL) + return; functions.push_back(new Function(sym, args, code)); } diff --git a/builtins.cpp b/builtins.cpp index bacb914d..1f1b5ca2 100644 --- a/builtins.cpp +++ b/builtins.cpp @@ -183,11 +183,6 @@ lCreateSymbol(const std::string &name, const Type *returnType, noPos.name = "__stdlib"; FunctionType *funcType = new FunctionType(returnType, argTypes, noPos); - // set NULL default arguments - std::vector defaults; - for (unsigned int j = 0; j < ftype->getNumParams(); ++j) - defaults.push_back(NULL); - funcType->SetArgumentDefaults(defaults); Symbol *sym = new Symbol(name, noPos, funcType); sym->function = func; @@ -222,11 +217,8 @@ lCreateISPCSymbol(llvm::Function *func, SymbolTable *symbolTable) { const Type *returnType = AtomicType::VaryingInt32; std::vector argTypes; argTypes.push_back(AtomicType::VaryingBool); - std::vector defaults; - defaults.push_back(NULL); FunctionType *funcType = new FunctionType(returnType, argTypes, noPos); - funcType->SetArgumentDefaults(defaults); Symbol *sym = new Symbol(name, noPos, funcType); sym->function = func; diff --git a/decl.cpp b/decl.cpp index f6ee1e59..2404e1eb 100644 --- a/decl.cpp +++ b/decl.cpp @@ -46,18 +46,72 @@ #include #include +static const Type * +lApplyTypeQualifiers(int typeQualifiers, const Type *type, SourcePos pos) { + if (type == NULL) + return NULL; + + // Account for 'unsigned' and 'const' qualifiers in the type + if ((typeQualifiers & TYPEQUAL_UNSIGNED) != 0) { + const Type *unsignedType = type->GetAsUnsignedType(); + if (unsignedType != NULL) + type = unsignedType; + else + Error(pos, "\"unsigned\" qualifier is illegal with \"%s\" type.", + type->GetString().c_str()); + } + if ((typeQualifiers & TYPEQUAL_CONST) != 0) + type = type->GetAsConstType(); + + // if uniform/varying is specified explicitly, then go with that + if (dynamic_cast(type) == NULL) { + if ((typeQualifiers & TYPEQUAL_UNIFORM) != 0) + type = type->GetAsUniformType(); + else if ((typeQualifiers & TYPEQUAL_VARYING) != 0) + type = type->GetAsVaryingType(); + else { + // otherwise, structs are uniform by default and everything + // else is varying by default + if (dynamic_cast(type->GetBaseType()) != NULL) + type = type->GetAsUniformType(); + else + type = type->GetAsVaryingType(); + } + } + + return type; +} + + /////////////////////////////////////////////////////////////////////////// // DeclSpecs DeclSpecs::DeclSpecs(const Type *t, StorageClass sc, int tq) { baseType = t; storageClass = sc; - typeQualifier = tq; + typeQualifiers = tq; soaWidth = 0; vectorSize = 0; } +const Type * +DeclSpecs::GetBaseType(SourcePos pos) const { + const Type *bt = baseType; + if (vectorSize > 0) { + const AtomicType *atomicType = dynamic_cast(bt); + if (atomicType == NULL) { + Error(pos, "Only atomic types (int, float, ...) are legal for vector " + "types."); + return NULL; + } + bt = new VectorType(atomicType, vectorSize); + } + + return lApplyTypeQualifiers(typeQualifiers, bt, pos); +} + + void DeclSpecs::Print() const { if (storageClass == SC_EXTERN) printf("extern "); @@ -68,13 +122,13 @@ DeclSpecs::Print() const { if (soaWidth > 0) printf("soa<%d> ", soaWidth); - if (typeQualifier & TYPEQUAL_INLINE) printf("inline "); - if (typeQualifier & TYPEQUAL_CONST) printf("const "); - if (typeQualifier & TYPEQUAL_UNIFORM) printf("uniform "); - if (typeQualifier & TYPEQUAL_VARYING) printf("varying "); - if (typeQualifier & TYPEQUAL_TASK) printf("task "); - if (typeQualifier & TYPEQUAL_REFERENCE) printf("reference "); - if (typeQualifier & TYPEQUAL_UNSIGNED) printf("unsigned "); + if (typeQualifiers & TYPEQUAL_INLINE) printf("inline "); + if (typeQualifiers & TYPEQUAL_CONST) printf("const "); + if (typeQualifiers & TYPEQUAL_UNIFORM) printf("uniform "); + if (typeQualifiers & TYPEQUAL_VARYING) printf("varying "); + if (typeQualifiers & TYPEQUAL_TASK) printf("task "); + if (typeQualifiers & TYPEQUAL_REFERENCE) printf("reference "); + if (typeQualifiers & TYPEQUAL_UNSIGNED) printf("unsigned "); printf("%s", baseType->GetString().c_str()); @@ -85,35 +139,33 @@ DeclSpecs::Print() const { /////////////////////////////////////////////////////////////////////////// // Declarator -Declarator::Declarator(Symbol *s, SourcePos p) - : pos(p) { - sym = s; - functionArgs = NULL; - isFunction = false; +Declarator::Declarator(DeclaratorKind dk, SourcePos p) + : pos(p), kind(dk) { + child = NULL; + typeQualifiers = 0; + arraySize = -1; + sym = NULL; initExpr = NULL; - pointerCount = 0; -} - - -void -Declarator::AddArrayDimension(int size) { - assert(size > 0 || size == -1); // -1 -> unsized - arraySize.push_back(size); } void Declarator::InitFromDeclSpecs(DeclSpecs *ds) { - sym->type = GetType(ds); - for (int i = 0; i < pointerCount; ++i) { - // Only function pointers for now... - if (dynamic_cast(sym->type) == NULL) - Error(pos, "Only pointers to functions are currently allowed, " - "not pointers to \"%s\".", sym->type->GetString().c_str()); - else - sym->type = new PointerType(sym->type, true, false); + const Type *t = GetType(ds); + Symbol *sym = GetSymbol(); + if (sym != NULL) { + sym->type = t; + sym->storageClass = ds->storageClass; } - sym->storageClass = ds->storageClass; +} + + +Symbol * +Declarator::GetSymbol() { + Declarator *d = this; + while (d->child != NULL) + d = d->child; + return d->sym; } @@ -137,162 +189,116 @@ Declarator::GetFunctionInfo(DeclSpecs *ds, Symbol **funSym, // time we get here.) const FunctionType *type = dynamic_cast(GetType(ds)); - assert(type != NULL); - *funSym = m->symbolTable->LookupFunction(sym->name.c_str(), type); + if (type == NULL) + return; + Symbol *declSym = GetSymbol(); + assert(declSym != NULL); + *funSym = m->symbolTable->LookupFunction(declSym->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) { - if (arrayIter == decl->arraySize.end()) { - // If we don't have an array (or have processed all of the array - // dimensions in previous recursive calls), we can go ahead and - // figure out the final non-array type we have here. - const Type *type = ds->baseType; - if (type == NULL) { - Error(decl->pos, "Type not provided in variable declaration for variable \"%s\".", - decl->sym->name.c_str()); - return NULL; - } - - // Account for 'unsigned' and 'const' qualifiers in the type - if ((ds->typeQualifier & TYPEQUAL_UNSIGNED) != 0) { - const Type *unsignedType = type->GetAsUnsignedType(); - if (unsignedType != NULL) - type = unsignedType; - else - Error(decl->pos, "\"unsigned\" qualifier is illegal with \"%s\" type.", - type->GetString().c_str()); - } - if ((ds->typeQualifier & TYPEQUAL_CONST) != 0) - type = type->GetAsConstType(); - - if (ds->vectorSize > 0) { - const AtomicType *atomicType = dynamic_cast(type); - if (atomicType == NULL) { - Error(decl->pos, "Only atomic types (int, float, ...) are legal for vector " - "types."); - return NULL; - } - type = new VectorType(atomicType, ds->vectorSize); - } - - // if uniform/varying is specified explicitly, then go with that - if ((ds->typeQualifier & TYPEQUAL_UNIFORM) != 0) - return type->GetAsUniformType(); - else if ((ds->typeQualifier & TYPEQUAL_VARYING) != 0) - return type->GetAsVaryingType(); - else { - // otherwise, structs are uniform by default and everything - // else is varying by default - if (dynamic_cast(type) != NULL) - return type->GetAsUniformType(); - else - return type->GetAsVaryingType(); - } - } - else { - // Peel off one dimension of the array - int arraySize = *arrayIter; - ++arrayIter; - - // Get the type, not including the arraySize dimension peeled off - // above. - const Type *childType = lGetType(decl, ds, arrayIter); - - int soaWidth = ds->soaWidth; - if (soaWidth == 0) - // If there's no "soa" stuff going on, just return a regular - // array with the appropriate size - return new ArrayType(childType, arraySize == -1 ? 0 : arraySize); - else { - // Make sure we actually have an array of structs .. - const StructType *childStructType = - dynamic_cast(childType); - if (childStructType == NULL) { - Error(decl->pos, "Illegal to provide soa<%d> qualifier with non-struct " - "type \"%s\".", soaWidth, childType->GetString().c_str()); - return new ArrayType(childType, arraySize == -1 ? 0 : arraySize); - } - else if ((soaWidth & (soaWidth - 1)) != 0) { - Error(decl->pos, "soa<%d> width illegal. Value must be power of two.", - soaWidth); - return NULL; - } - else if (arraySize != -1 && (arraySize % soaWidth) != 0) { - Error(decl->pos, "soa<%d> width must evenly divide array size %d.", - soaWidth, arraySize); - return NULL; - } - return new SOAArrayType(childStructType, arraySize == -1 ? 0 : arraySize, - soaWidth); - } + for (unsigned int i = 0; i < functionArgs.size(); ++i) { + Declaration *pdecl = functionArgs[i]; + assert(pdecl->declarators.size() == 1); + funArgs->push_back(pdecl->declarators[0]->GetSymbol()); } } const Type * -Declarator::GetType(DeclSpecs *ds) const { - bool hasUniformQual = ((ds->typeQualifier & TYPEQUAL_UNIFORM) != 0); - bool hasVaryingQual = ((ds->typeQualifier & TYPEQUAL_VARYING) != 0); - bool isTask = ((ds->typeQualifier & TYPEQUAL_TASK) != 0); - bool isReference = ((ds->typeQualifier & TYPEQUAL_REFERENCE) != 0); +Declarator::GetType(const Type *base, DeclSpecs *ds) const { + bool hasUniformQual = ((typeQualifiers & TYPEQUAL_UNIFORM) != 0); + bool hasVaryingQual = ((typeQualifiers & TYPEQUAL_VARYING) != 0); + bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0); + bool isReference = ((typeQualifiers & TYPEQUAL_REFERENCE) != 0); + bool isConst = ((typeQualifiers & TYPEQUAL_CONST) != 0); if (hasUniformQual && hasVaryingQual) { Error(pos, "Can't provide both \"uniform\" and \"varying\" qualifiers."); return NULL; } + if (kind != DK_FUNCTION && isTask) + Error(pos, "\"task\" qualifier illegal in variable declaration."); - if (isFunction) { + const Type *type = base; + switch (kind) { + case DK_BASE: + assert(typeQualifiers == 0); + assert(child == NULL); + return type; + + case DK_POINTER: + type = new PointerType(type, hasUniformQual, isConst); + if (child) + return child->GetType(type, ds); + else + return type; + break; + + case DK_ARRAY: + type = new ArrayType(type, arraySize); + if (child) + return child->GetType(type, ds); + else + return type; + break; + + case DK_FUNCTION: { std::vector args; std::vector argNames; - if (functionArgs) { - // Loop over the function arguments and get names and types for - // each one in the args and argNames arrays - for (unsigned int i = 0; i < functionArgs->size(); ++i) { - Declaration *d = (*functionArgs)[i]; - Symbol *sym; - if (d->declarators.size() == 0) { - // function declaration like foo(float), w/o a name for - // the parameter - char buf[32]; + std::vector argDefaults; + std::vector argPos; + + // Loop over the function arguments and get names and types for + // each one in the args and argNames arrays + for (unsigned int i = 0; i < functionArgs.size(); ++i) { + Declaration *d = functionArgs[i]; + char buf[32]; + Symbol *sym; + if (d->declarators.size() == 0) { + // function declaration like foo(float), w/o a name for + // the parameter + sprintf(buf, "__anon_parameter_%d", i); + sym = new Symbol(buf, pos); + sym->type = d->declSpecs->GetBaseType(pos); + } + else { + sym = d->declarators[0]->GetSymbol(); + if (sym == NULL) { sprintf(buf, "__anon_parameter_%d", i); sym = new Symbol(buf, pos); - Declarator *declarator = new Declarator(sym, sym->pos); - sym->type = declarator->GetType(d->declSpecs); - d->declarators.push_back(declarator); + sym->type = d->declarators[0]->GetType(d->declSpecs); } - else { - assert(d->declarators.size() == 1); - sym = d->declarators[0]->sym; - } - - // Arrays are passed by reference, so convert array - // parameters to be references here. - if (dynamic_cast(sym->type) != NULL) - sym->type = new ReferenceType(sym->type, sym->type->IsConstType()); - - args.push_back(sym->type); - argNames.push_back(sym->name); } - } - if (ds->baseType == NULL) { - Warning(pos, "No return type provided in declaration of function \"%s\". " - "Treating as \"void\".", sym->name.c_str()); - ds->baseType = AtomicType::Void; + // Arrays are passed by reference, so convert array + // parameters to be references here. + if (dynamic_cast(sym->type) != NULL) + sym->type = new ReferenceType(sym->type, sym->type->IsConstType()); + + args.push_back(sym->type); + argNames.push_back(sym->name); + argPos.push_back(sym->pos); + + ConstExpr *init = NULL; + if (d->declarators.size()) { + Declarator *decl = d->declarators[0]; + while (decl->child != NULL) { + assert(decl->initExpr == NULL); + decl = decl->child; + } + + if (decl->initExpr != NULL && + (decl->initExpr = decl->initExpr->TypeCheck()) != NULL && + (decl->initExpr = decl->initExpr->Optimize()) != NULL && + (init = dynamic_cast(decl->initExpr)) == NULL) { + Error(decl->initExpr->pos, "Default value for parameter " + "\"%s\" must be a compile-time constant.", + sym->name.c_str()); + } + } + argDefaults.push_back(init); } if (isReference) { @@ -300,31 +306,64 @@ Declarator::GetType(DeclSpecs *ds) const { return NULL; } - const Type *returnType = lGetType(this, ds, arraySize.begin()); - if (returnType == NULL) + const Type *returnType = type; + if (returnType == NULL) { + Error(pos, "No return type provided in function declaration."); return NULL; - - bool isExported = (ds->storageClass == SC_EXPORT); - bool isExternC = (ds->storageClass == SC_EXTERN_C); - return new FunctionType(returnType, args, pos, &argNames, isTask, - isExported, isExternC); - } - else { - if (isTask) - Error(pos, "\"task\" qualifier illegal in variable declaration \"%s\".", - sym->name.c_str()); - - const Type *type = lGetType(this, ds, arraySize.begin()); - - if (type != NULL && isReference) { - bool hasConstQual = ((ds->typeQualifier & TYPEQUAL_CONST) != 0); - type = new ReferenceType(type, hasConstQual); } - return type; + bool isExported = ds && (ds->storageClass == SC_EXPORT); + bool isExternC = ds && (ds->storageClass == SC_EXTERN_C); + bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0); + Type *functionType = + new FunctionType(returnType, args, pos, argNames, argDefaults, + argPos, isTask, isExported, isExternC); + return child->GetType(functionType, ds); } + default: + FATAL("Unexpected decl kind"); + return NULL; + } + +#if 0 + // Make sure we actually have an array of structs .. + const StructType *childStructType = + dynamic_cast(childType); + if (childStructType == NULL) { + Error(pos, "Illegal to provide soa<%d> qualifier with non-struct " + "type \"%s\".", soaWidth, childType->GetString().c_str()); + return new ArrayType(childType, arraySize == -1 ? 0 : arraySize); + } + else if ((soaWidth & (soaWidth - 1)) != 0) { + Error(pos, "soa<%d> width illegal. Value must be power of two.", + soaWidth); + return NULL; + } + else if (arraySize != -1 && (arraySize % soaWidth) != 0) { + Error(pos, "soa<%d> width must evenly divide array size %d.", + soaWidth, arraySize); + return NULL; + } + return new SOAArrayType(childStructType, arraySize == -1 ? 0 : arraySize, + soaWidth); +#endif } + +const Type * +Declarator::GetType(DeclSpecs *ds) const { + const Type *baseType = ds->GetBaseType(pos); + const Type *type = GetType(baseType, ds); + + if ((ds->typeQualifiers & TYPEQUAL_REFERENCE) != 0) { + bool hasConstQual = ((ds->typeQualifiers & TYPEQUAL_CONST) != 0); + type = new ReferenceType(type, hasConstQual); + } + + return type; +} + + /////////////////////////////////////////////////////////////////////////// // Declaration @@ -356,13 +395,13 @@ Declaration::GetVariableDeclarations() const { if (declarators[i] == NULL) continue; Declarator *decl = declarators[i]; - if (!decl || decl->isFunction) + if (decl == NULL || decl->kind == DK_FUNCTION) continue; - m->symbolTable->AddVariable(declarators[i]->sym); + Symbol *sym = decl->GetSymbol(); + m->symbolTable->AddVariable(sym); - vars.push_back(VariableDeclaration(declarators[i]->sym, - declarators[i]->initExpr)); + vars.push_back(VariableDeclaration(sym, decl->initExpr)); } return vars; } @@ -392,9 +431,9 @@ GetStructTypesNamesPositions(const std::vector &sd, // disgusting DeclSpecs ds(type); if (type->IsUniformType()) - ds.typeQualifier |= TYPEQUAL_UNIFORM; + ds.typeQualifiers |= TYPEQUAL_UNIFORM; else - ds.typeQualifier |= TYPEQUAL_VARYING; + ds.typeQualifiers |= TYPEQUAL_VARYING; for (unsigned int j = 0; j < sd[i]->declarators->size(); ++j) { Declarator *d = (*sd[i]->declarators)[j]; @@ -402,13 +441,14 @@ GetStructTypesNamesPositions(const std::vector &sd, // if it's an unsized array, make it a reference to an unsized // array, so the caller can pass a pointer... - const ArrayType *at = dynamic_cast(d->sym->type); + Symbol *sym = d->GetSymbol(); + const ArrayType *at = dynamic_cast(sym->type); if (at && at->GetElementCount() == 0) - d->sym->type = new ReferenceType(d->sym->type, type->IsConstType()); + sym->type = new ReferenceType(sym->type, type->IsConstType()); - elementTypes->push_back(d->sym->type); - elementNames->push_back(d->sym->name); - elementPositions->push_back(d->sym->pos); + elementTypes->push_back(sym->type); + elementNames->push_back(sym->name); + elementPositions->push_back(sym->pos); } } } diff --git a/decl.h b/decl.h index 5ee05a21..019b251e 100644 --- a/decl.h +++ b/decl.h @@ -97,7 +97,7 @@ public: StorageClass storageClass; /** Zero or more of the TYPEQUAL_* values, ANDed together. */ - int typeQualifier; + int typeQualifiers; /** The basic type provided in the declaration; this should be an AtomicType, a StructType, or a VectorType; other types (like @@ -106,6 +106,8 @@ public: */ const Type *baseType; + const Type *GetBaseType(SourcePos pos) const; + /** If this is a declaration with a vector type, this gives the vector width. For non-vector types, this is zero. */ @@ -118,6 +120,13 @@ public: }; +enum DeclaratorKind { + DK_BASE, + DK_POINTER, + DK_ARRAY, + DK_FUNCTION +}; + /** @brief Representation of the declaration of a single variable. In conjunction with an instance of the DeclSpecs, this gives us @@ -125,13 +134,7 @@ public: */ class Declarator { public: - Declarator(Symbol *s, SourcePos p); - - /** As the parser peels off array dimension declarations after the - symbol name, it calls this method to provide them to the - Declarator. - */ - void AddArrayDimension(int size); + Declarator(DeclaratorKind dk, SourcePos p); /** Once a DeclSpecs instance is available, this method completes the initialization of the Symbol, setting its Type accordingly. @@ -141,23 +144,31 @@ public: /** Get the actual type of the combination of Declarator and the given DeclSpecs */ const Type *GetType(DeclSpecs *ds) const; + const Type *GetType(const Type *base, DeclSpecs *ds) const; void GetFunctionInfo(DeclSpecs *ds, Symbol **sym, std::vector *args); + Symbol *GetSymbol(); + void Print() const; const SourcePos pos; + + const DeclaratorKind kind; + + Declarator *child; + + int typeQualifiers; + + int arraySize; + Symbol *sym; - /** If this declarator includes an array specification, the sizes of - the array dimensions are represented here. - */ - std::vector arraySize; + /** Initialization expression for the variable. May be NULL. */ Expr *initExpr; - bool isFunction; - int pointerCount; - std::vector *functionArgs; + + std::vector functionArgs; }; diff --git a/expr.cpp b/expr.cpp index df8b262a..efa202f7 100644 --- a/expr.cpp +++ b/expr.cpp @@ -594,7 +594,7 @@ lEmitPrePostIncDec(UnaryExpr::Op op, Expr *expr, SourcePos pos, if (lvalue == NULL) { // If we can't get a lvalue, then we have an error here - Error(expr->pos, "Can't %s-%s non-lvalues.", + Error(pos, "Can't %s-%s non-lvalues.", (op == UnaryExpr::PreInc || op == UnaryExpr::PreDec) ? "pre" : "post", (op == UnaryExpr::PreInc || op == UnaryExpr::PostInc) ? "increment" : "decrement"); return NULL; diff --git a/module.cpp b/module.cpp index ce607649..7d713085 100644 --- a/module.cpp +++ b/module.cpp @@ -331,16 +331,16 @@ lRecursiveCheckVarying(const Type *t) { varying parameters is illegal. */ static void -lCheckForVaryingParameter(Symbol *sym) { - if (lRecursiveCheckVarying(sym->type)) { - const Type *t = sym->type->GetBaseType(); +lCheckForVaryingParameter(const Type *type, const std::string &name, + SourcePos pos) { + if (lRecursiveCheckVarying(type)) { + const Type *t = 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()); + Error(pos, "Struct parameter \"%s\" with varying member(s) is illegal " + "in an exported function.", name.c_str()); else - Error(sym->pos, "Varying parameter \"%s\" is illegal in an exported function.", - sym->name.c_str()); + Error(pos, "Varying parameter \"%s\" is illegal in an exported function.", + name.c_str()); } } @@ -372,10 +372,7 @@ lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) { false if any errors were encountered. */ void -Module::AddFunctionDeclaration(Symbol *funSym, - const std::vector &args, - bool isInline) { - // We should have gotten a FunctionType back from the GetType() call above. +Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) { const FunctionType *functionType = dynamic_cast(funSym->type); assert(functionType != NULL); @@ -446,8 +443,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, llvm::Function::Create(llvmFunctionType, linkage, functionName.c_str(), module); - // Set function attributes: we never throw exceptions, and want to - // inline everything we can + // Set function attributes: we never throw exceptions function->setDoesNotThrow(true); if (!(funSym->storageClass == SC_EXTERN_C) && !g->generateDebuggingSymbols && @@ -473,21 +469,24 @@ Module::AddFunctionDeclaration(Symbol *funSym, // 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; + int nArgs = functionType->GetNumParameters(); + for (int i = 0; i < nArgs; ++i) { + const Type *argType = (functionType->GetArgumentTypes())[i]; + const std::string &argName = functionType->GetArgumentName(i); + ConstExpr *defaultValue = (functionType->GetArgumentDefaults())[i]; + const SourcePos &argPos = (functionType->GetArgumentSourcePos())[i]; // 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); + lCheckForVaryingParameter(argType, argName, argPos); // 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) { + dynamic_cast(argType) != NULL) { // NOTE: LLVM indexes function parameters starting from 1. // This is unintuitive. function->setDoesNotAlias(i+1, true); @@ -495,43 +494,21 @@ Module::AddFunctionDeclaration(Symbol *funSym, 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()); + if (symbolTable->LookupFunction(argName.c_str()) != NULL) + Warning(argPos, "Function parameter \"%s\" shadows a function " + "declared in global scope.", argName.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 + if (defaultValue != NULL) 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 " + Error(argPos, "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()); + "must have default values as well.", argName.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 diff --git a/module.h b/module.h index a61aad4a..f5fe75a9 100644 --- a/module.h +++ b/module.h @@ -67,10 +67,8 @@ public: 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); + symbol to the module. */ + void AddFunctionDeclaration(Symbol *funSym, bool isInline); /** Adds the function described by the declaration information and the provided statements to the module. */ diff --git a/parse.yy b/parse.yy index d3363518..6d58cebe 100644 --- a/parse.yy +++ b/parse.yy @@ -183,7 +183,8 @@ static const char *lParamListTokens[] = { %type declaration parameter_declaration %type init_declarator_list %type parameter_list parameter_type_list -%type declarator init_declarator direct_declarator struct_declarator +%type declarator pointer init_declarator direct_declarator struct_declarator +%type abstract_declarator direct_abstract_declarator %type struct_declarator_list %type struct_declaration @@ -198,7 +199,7 @@ static const char *lParamListTokens[] = { %type short_vec_specifier %type atomic_var_type_specifier -%type type_qualifier +%type type_qualifier type_qualifier_list %type storage_class_specifier %type declaration_specifiers @@ -553,7 +554,7 @@ declaration_specifiers { DeclSpecs *ds = (DeclSpecs *)$2; if (ds != NULL) - ds->typeQualifier |= $1; + ds->typeQualifiers |= $1; $$ = ds; } ; @@ -731,8 +732,6 @@ specifier_qualifier_list else $$ = NULL; } -/* K&R--implicit int type--e.g. "static foo" -> foo is an int */ -/* | type_qualifier { UNIMPLEMENTED; }*/ ; @@ -865,13 +864,27 @@ type_qualifier | TOKEN_UNSIGNED { $$ = TYPEQUAL_UNSIGNED; } ; -declarator - : direct_declarator - | '*' direct_declarator +type_qualifier_list + : type_qualifier { - $2->pointerCount++; - $$ = $2; + $$ = $1; } + | type_qualifier_list type_qualifier + { + $$ = $1 | $2; + } + ; + +declarator + : pointer direct_declarator + { + Declarator *tail = $1; + while (tail->child != NULL) + tail = tail->child; + tail->child = $2; + $$ = $1; + } + | direct_declarator ; int_constant @@ -881,41 +894,83 @@ int_constant direct_declarator : TOKEN_IDENTIFIER { - Symbol *sym = new Symbol(yytext, @1); - $$ = new Declarator(sym, @1); + Declarator *d = new Declarator(DK_BASE, @1); + d->sym = new Symbol(yytext, @1); + $$ = d; } - | '(' declarator ')' { $$ = $2; } + | '(' declarator ')' + { + $$ = $2; + } | direct_declarator '[' constant_expression ']' { int size; if ($1 != NULL && lGetConstantInt($3, &size, @3, "Array dimension")) { - $1->AddArrayDimension(size); - $$ = $1; + Declarator *d = new Declarator(DK_ARRAY, Union(@1, @4)); + d->arraySize = size; + d->child = $1; + $$ = d; } else $$ = NULL; } | direct_declarator '[' ']' { - if ($1 != NULL) - $1->AddArrayDimension(-1); // unsized - $$ = $1; + if ($1 != NULL) { + Declarator *d = new Declarator(DK_ARRAY, Union(@1, @3)); + d->arraySize = 0; // unsize + d->child = $1; + $$ = d; + } + else + $$ = NULL; } | direct_declarator '(' parameter_type_list ')' { - Declarator *d = (Declarator *)$1; - if (d != NULL) { - d->isFunction = true; - d->functionArgs = $3; + if ($1 != NULL) { + Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @4)); + d->child = $1; + d->functionArgs = *$3; + $$ = d; } - $$ = d; + else + $$ = NULL; } -/* K&R? | direct_declarator '(' identifier_list ')' */ | direct_declarator '(' ')' { - Declarator *d = (Declarator *)$1; - if (d != NULL) - d->isFunction = true; + if ($1 != NULL) { + Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @3)); + d->child = $1; + $$ = d; + } + else + $$ = NULL; + } + ; + + +pointer + : '*' + { + $$ = new Declarator(DK_POINTER, @1); + } + | '*' type_qualifier_list + { + Declarator *d = new Declarator(DK_POINTER, Union(@1, @2)); + d->typeQualifiers = $2; + $$ = d; + } + | '*' pointer + { + Declarator *d = new Declarator(DK_POINTER, Union(@1, @2)); + d->child = $2; + $$ = d; + } + | '*' type_qualifier_list pointer + { + Declarator *d = new Declarator(DK_POINTER, Union(@1, @3)); + d->typeQualifiers = $2; + d->child = $3; $$ = d; } ; @@ -976,7 +1031,7 @@ parameter_declaration } | declaration_specifiers abstract_declarator { - UNIMPLEMENTED; + $$ = new Declaration($1, $2); } | declaration_specifiers { @@ -994,25 +1049,85 @@ identifier_list type_name : specifier_qualifier_list | specifier_qualifier_list abstract_declarator + { + $$ = $2->GetType($1, NULL); + } ; abstract_declarator -/* : pointer + : pointer + { + Declarator *d = new Declarator(DK_POINTER, @1); + $$ = d; + } | direct_abstract_declarator - | pointer direct_abstract_declarator */ - : direct_abstract_declarator { UNIMPLEMENTED; } + | pointer direct_abstract_declarator + { + Declarator *d = new Declarator(DK_POINTER, Union(@1, @2)); + d->child = $2; + $$ = d; + } ; direct_abstract_declarator : '(' abstract_declarator ')' -/* | '[' ']' */ + { $$ = $2; } + | '[' ']' + { + Declarator *d = new Declarator(DK_ARRAY, Union(@1, @2)); + d->arraySize = 0; + $$ = d; + } | '[' constant_expression ']' -/* | direct_abstract_declarator '[' ']' */ + { + int size; + if (lGetConstantInt($2, &size, @2, "Array dimension")) { + Declarator *d = new Declarator(DK_ARRAY, Union(@1, @3)); + d->arraySize = size; + $$ = d; + } + else + $$ = NULL; + } + | direct_abstract_declarator '[' ']' + { + Declarator *d = new Declarator(DK_ARRAY, Union(@1, @3)); + d->arraySize = 0; + d->child = $1; + $$ = d; + } | direct_abstract_declarator '[' constant_expression ']' + { + int size; + if (lGetConstantInt($3, &size, @3, "Array dimension")) { + Declarator *d = new Declarator(DK_ARRAY, Union(@1, @4)); + d->arraySize = size; + d->child = $1; + $$ = d; + } + else + $$ = NULL; + } | '(' ')' + { $$ = new Declarator(DK_FUNCTION, Union(@1, @2)); } | '(' parameter_type_list ')' + { + Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @3)); + d->functionArgs = *$2; + } | direct_abstract_declarator '(' ')' + { + Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @3)); + d->child = $1; + $$ = d; + } | direct_abstract_declarator '(' parameter_type_list ')' + { + Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @4)); + d->child = $1; + d->functionArgs = *$3; + $$ = d; + } ; initializer @@ -1250,7 +1365,7 @@ function_definition lAddDeclaration($1, $2); lAddFunctionParams($2); lAddMaskToSymbolTable(@2); - if ($1->typeQualifier & TYPEQUAL_TASK) + if ($1->typeQualifiers & TYPEQUAL_TASK) lAddThreadIndexCountToSymbolTable(@2); } compound_statement @@ -1281,38 +1396,26 @@ lAddDeclaration(DeclSpecs *ds, Declarator *decl) { return; if (ds->storageClass == SC_TYPEDEF) - m->AddTypeDef(decl->sym); - else if (decl->isFunction) { + m->AddTypeDef(decl->GetSymbol()); + else if (decl->kind == DK_FUNCTION) { // function declaration const Type *t = decl->GetType(ds); + if (t == NULL) + return; 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); + Symbol *funSym = decl->GetSymbol(); + assert(funSym != NULL); + funSym->type = ft; 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); + bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE); + m->AddFunctionDeclaration(funSym, isInline); } else - m->AddGlobalVariable(decl->sym, decl->initExpr, - (ds->typeQualifier & TYPEQUAL_CONST) != 0); + m->AddGlobalVariable(decl->GetSymbol(), decl->initExpr, + (ds->typeQualifiers & TYPEQUAL_CONST) != 0); } @@ -1324,20 +1427,18 @@ lAddFunctionParams(Declarator *decl) { m->symbolTable->PushScope(); // wire up arguments - if (decl->functionArgs) { - for (unsigned int i = 0; i < decl->functionArgs->size(); ++i) { - Declaration *pdecl = (*decl->functionArgs)[i]; - if (pdecl == NULL) - continue; - assert(pdecl->declarators.size() == 1); - Symbol *sym = pdecl->declarators[0]->sym; + for (unsigned int i = 0; i < decl->functionArgs.size(); ++i) { + Declaration *pdecl = decl->functionArgs[i]; + if (pdecl == NULL) + continue; + assert(pdecl->declarators.size() == 1); + Symbol *sym = pdecl->declarators[0]->GetSymbol(); #ifndef NDEBUG - bool ok = m->symbolTable->AddVariable(sym); - assert(ok); // or error message? + bool ok = m->symbolTable->AddVariable(sym); + assert(ok); // or error message? #else - m->symbolTable->AddVariable(sym); + m->symbolTable->AddVariable(sym); #endif - } } // The corresponding pop scope happens in function_definition rules diff --git a/tests/funcptr-null-1.ispc b/tests/funcptr-null-1.ispc index c07e7910..05798918 100644 --- a/tests/funcptr-null-1.ispc +++ b/tests/funcptr-null-1.ispc @@ -8,7 +8,7 @@ float foo(float a, float b) { } static float bar(float a, float b) { - return min(a, b); + return aGetString(); + std::string ret = baseType->GetString(); + + ret += std::string(" *"); + if (isConst) ret += " const"; + if (isUniform) ret += " uniform"; + return ret; } @@ -820,9 +822,10 @@ PointerType::GetCDeclaration(const std::string &name) const { if (baseType == NULL) return ""; - std::string ret; - if (isConst) ret += "const "; - return ret + std::string("*") + baseType->GetCDeclaration(name); + std::string ret = baseType->GetCDeclaration(name); + ret += std::string(" *"); + if (isConst) ret += " const"; + return ret; } @@ -956,6 +959,14 @@ ArrayType::GetAsUniformType() const { } +const ArrayType * +ArrayType::GetAsUnsignedType() const { + if (child == NULL) + return NULL; + return new ArrayType(child->GetAsUnsignedType(), numElements); +} + + const Type * ArrayType::GetSOAType(int width) const { if (child == NULL) @@ -1850,10 +1861,26 @@ ReferenceType::GetDIType(llvm::DIDescriptor scope) const { // FunctionType FunctionType::FunctionType(const Type *r, const std::vector &a, - SourcePos p, const std::vector *an, + SourcePos p) + : isTask(false), isExported(false), isExternC(false), returnType(r), + argTypes(a), argNames(std::vector(a.size(), "")), + argDefaults(std::vector(a.size(), NULL)), + argPos(std::vector(a.size(), p)), + pos(p) { + assert(returnType != NULL); +} + + +FunctionType::FunctionType(const Type *r, const std::vector &a, + SourcePos p, const std::vector &an, + const std::vector &ad, + const std::vector &ap, bool it, bool is, bool ec) : isTask(it), isExported(is), isExternC(ec), returnType(r), argTypes(a), - argNames(an ? *an : std::vector()), pos(p) { + argNames(an), argDefaults(ad), argPos(ap), pos(p) { + assert(argTypes.size() == argNames.size() && + argNames.size() == argDefaults.size() && + argDefaults.size() == argPos.size()); assert(returnType != NULL); } @@ -1969,7 +1996,7 @@ FunctionType::GetCDeclaration(const std::string &fname) const { ret += fname; ret += "("; for (unsigned int i = 0; i < argTypes.size(); ++i) { - if (argNames.size()) + if (argNames[i] != "") ret += argTypes[i]->GetCDeclaration(argNames[i]); else ret += argTypes[i]->GetString(); @@ -2042,20 +2069,10 @@ FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const { } -void -FunctionType::SetArgumentDefaults(const std::vector &d) const { - assert(argDefaults.size() == 0); - assert(d.size() == argTypes.size()); - argDefaults = d; -} - - std::string FunctionType::GetArgumentName(int i) const { - if (i >= (int)argNames.size()) - return ""; - else - return argNames[i]; + assert(i < (int)argNames.size()); + return argNames[i]; } diff --git a/type.h b/type.h index 2c6f6ba4..7ff579ce 100644 --- a/type.h +++ b/type.h @@ -406,6 +406,7 @@ public: const Type *GetBaseType() const; const ArrayType *GetAsVaryingType() const; const ArrayType *GetAsUniformType() const; + const ArrayType *GetAsUnsignedType() const; const Type *GetSOAType(int width) const; const ArrayType *GetAsConstType() const; const ArrayType *GetAsNonConstType() const; @@ -673,11 +674,14 @@ private: */ class FunctionType : public Type { public: + FunctionType(const Type *returnType, + const std::vector &argTypes, SourcePos pos); FunctionType(const Type *returnType, const std::vector &argTypes, SourcePos pos, - const std::vector *argNames = NULL, - bool isTask = false, bool isExported = false, - bool isExternC = false); + const std::vector &argNames, + const std::vector &argDefaults, + const std::vector &argPos, + bool isTask, bool isExported, bool isExternC); bool IsUniformType() const; bool IsBoolType() const; @@ -709,14 +713,12 @@ public: LLVM_TYPE_CONST llvm::FunctionType *LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask = false) const; + int GetNumParameters() const { return (int)argTypes.size(); } const std::vector &GetArgumentTypes() const { return argTypes; } const std::vector &GetArgumentDefaults() const { return argDefaults; } - std::string GetArgumentName(int i) const; + const std::vector &GetArgumentSourcePos() const { return argPos; } - /** @todo It would be nice to pull this information together and pass - it when the constructor is called; it's kind of ugly to set it like - this later. */ - void SetArgumentDefaults(const std::vector &d) const; + std::string GetArgumentName(int i) const; /** This value is true if the function had a 'task' qualifier in the source program. */ @@ -733,6 +735,7 @@ public: private: const Type * const returnType; const std::vector argTypes; + const std::vector argNames; /** Default values of the functions arguments. For arguments without default values provided, NULL is stored; this means that the length of this array is the same as the argTypes member, and the i'th @@ -742,7 +745,7 @@ private: function's signature. These should only be used for error messages and the like and shouldn't affect testing function types for equality, etc. */ - const std::vector argNames; + const std::vector argPos; const SourcePos pos; };