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.)
This commit is contained in:
Matt Pharr
2011-11-07 17:46:59 -08:00
parent 79684a0bed
commit 7290f7b16b
12 changed files with 511 additions and 370 deletions

View File

@@ -51,6 +51,8 @@ ASTNode::~ASTNode() {
void
AST::AddFunction(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code) {
if (sym == NULL)
return;
functions.push_back(new Function(sym, args, code));
}

View File

@@ -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<ConstExpr *> 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<const Type *> argTypes;
argTypes.push_back(AtomicType::VaryingBool);
std::vector<ConstExpr *> 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;

386
decl.cpp
View File

@@ -46,18 +46,72 @@
#include <stdio.h>
#include <llvm/Module.h>
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<const FunctionType *>(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<const StructType *>(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<const AtomicType *>(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<const FunctionType *>(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;
}
}
Symbol *
Declarator::GetSymbol() {
Declarator *d = this;
while (d->child != NULL)
d = d->child;
return d->sym;
}
@@ -137,146 +189,87 @@ Declarator::GetFunctionInfo(DeclSpecs *ds, Symbol **funSym,
// time we get here.)
const FunctionType *type =
dynamic_cast<const FunctionType *>(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];
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<int>::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<const AtomicType *>(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<const StructType *>(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<n>" 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<const StructType *>(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);
}
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<const Type *> args;
std::vector<std::string> argNames;
if (functionArgs) {
std::vector<ConstExpr *> argDefaults;
std::vector<SourcePos> 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];
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
char buf[32];
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->declSpecs->GetBaseType(pos);
}
else {
assert(d->declarators.size() == 1);
sym = d->declarators[0]->sym;
sym = d->declarators[0]->GetSymbol();
if (sym == NULL) {
sprintf(buf, "__anon_parameter_%d", i);
sym = new Symbol(buf, pos);
sym->type = d->declarators[0]->GetType(d->declSpecs);
}
}
// Arrays are passed by reference, so convert array
@@ -286,13 +279,26 @@ Declarator::GetType(DeclSpecs *ds) const {
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 (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;
if (decl->initExpr != NULL &&
(decl->initExpr = decl->initExpr->TypeCheck()) != NULL &&
(decl->initExpr = decl->initExpr->Optimize()) != NULL &&
(init = dynamic_cast<ConstExpr *>(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());
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 (type != NULL && isReference) {
bool hasConstQual = ((ds->typeQualifier & TYPEQUAL_CONST) != 0);
#if 0
// Make sure we actually have an array of structs ..
const StructType *childStructType =
dynamic_cast<const StructType *>(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<StructDeclaration *> &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<StructDeclaration *> &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<const ArrayType *>(d->sym->type);
Symbol *sym = d->GetSymbol();
const ArrayType *at = dynamic_cast<const ArrayType *>(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);
}
}
}

41
decl.h
View File

@@ -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<Symbol *> *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<int> arraySize;
/** Initialization expression for the variable. May be NULL. */
Expr *initExpr;
bool isFunction;
int pointerCount;
std::vector<Declaration *> *functionArgs;
std::vector<Declaration *> functionArgs;
};

View File

@@ -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;

View File

@@ -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<const StructType *>(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<VariableDeclaration> &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<const FunctionType *>(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<ConstExpr *> 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<const ReferenceType *>(argSym->type) != NULL) {
dynamic_cast<const ReferenceType *>(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<ConstExpr *>(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<ConstExpr *>(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

View File

@@ -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<VariableDeclaration> &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. */

225
parse.yy
View File

@@ -183,7 +183,8 @@ static const char *lParamListTokens[] = {
%type <declaration> declaration parameter_declaration
%type <declarators> init_declarator_list
%type <declarationList> parameter_list parameter_type_list
%type <declarator> declarator init_declarator direct_declarator struct_declarator
%type <declarator> declarator pointer init_declarator direct_declarator struct_declarator
%type <declarator> abstract_declarator direct_abstract_declarator
%type <structDeclaratorList> struct_declarator_list
%type <structDeclaration> struct_declaration
@@ -198,7 +199,7 @@ static const char *lParamListTokens[] = {
%type <type> short_vec_specifier
%type <atomicType> atomic_var_type_specifier
%type <typeQualifier> type_qualifier
%type <typeQualifier> type_qualifier type_qualifier_list
%type <storageClass> storage_class_specifier
%type <declSpecs> 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;
}
/* K&R? | direct_declarator '(' identifier_list ')' */
else
$$ = NULL;
}
| 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<const FunctionType *>(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<VariableDeclaration> 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,13 +1427,12 @@ 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];
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;
Symbol *sym = pdecl->declarators[0]->GetSymbol();
#ifndef NDEBUG
bool ok = m->symbolTable->AddVariable(sym);
assert(ok); // or error message?
@@ -1338,7 +1440,6 @@ lAddFunctionParams(Declarator *decl) {
m->symbolTable->AddVariable(sym);
#endif
}
}
// The corresponding pop scope happens in function_definition rules
// above...

View File

@@ -8,7 +8,7 @@ float foo(float a, float b) {
}
static float bar(float a, float b) {
return min(a, b);
return a<b?a:b;
}
export void f_f(uniform float RET[], uniform float aFOO[]) {

View File

@@ -5,6 +5,6 @@ export uniform int width() { return programCount; }
export void f_v(uniform float RET[]) { RET[programIndex] = 1.; }
export void f_v(uniform float RET[]) { RET[programIndex] = 2.; }
export result(uniform float RET[]) {
export void result(uniform float RET[]) {
RET[programIndex] = 1.000000;
}

View File

@@ -799,10 +799,12 @@ PointerType::GetString() const {
if (baseType == NULL)
return "";
std::string ret;
if (isConst) ret += "const ";
if (isUniform) ret += "uniform ";
return ret + std::string("*") + baseType->GetString();
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<const Type *> &a,
SourcePos p, const std::vector<std::string> *an,
SourcePos p)
: isTask(false), isExported(false), isExternC(false), returnType(r),
argTypes(a), argNames(std::vector<std::string>(a.size(), "")),
argDefaults(std::vector<ConstExpr *>(a.size(), NULL)),
argPos(std::vector<SourcePos>(a.size(), p)),
pos(p) {
assert(returnType != NULL);
}
FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
SourcePos p, const std::vector<std::string> &an,
const std::vector<ConstExpr *> &ad,
const std::vector<SourcePos> &ap,
bool it, bool is, bool ec)
: isTask(it), isExported(is), isExternC(ec), returnType(r), argTypes(a),
argNames(an ? *an : std::vector<std::string>()), 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,19 +2069,9 @@ FunctionType::LLVMFunctionType(llvm::LLVMContext *ctx, bool includeMask) const {
}
void
FunctionType::SetArgumentDefaults(const std::vector<ConstExpr *> &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
assert(i < (int)argNames.size());
return argNames[i];
}

21
type.h
View File

@@ -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<const Type *> &argTypes, SourcePos pos);
FunctionType(const Type *returnType,
const std::vector<const Type *> &argTypes, SourcePos pos,
const std::vector<std::string> *argNames = NULL,
bool isTask = false, bool isExported = false,
bool isExternC = false);
const std::vector<std::string> &argNames,
const std::vector<ConstExpr *> &argDefaults,
const std::vector<SourcePos> &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<const Type *> &GetArgumentTypes() const { return argTypes; }
const std::vector<ConstExpr *> &GetArgumentDefaults() const { return argDefaults; }
std::string GetArgumentName(int i) const;
const std::vector<SourcePos> &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<ConstExpr *> &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<const Type *> argTypes;
const std::vector<std::string> 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<std::string> argNames;
const std::vector<SourcePos> argPos;
const SourcePos pos;
};