Substantial rewrite (again) of decl handling.

The decl.* code now no longer interacts with Symbols, but just returns
names, types, initializer expressions, etc., as needed.  This makes the
code a bit more understandable.

Fixes issues #171 and #130.
This commit is contained in:
Matt Pharr
2012-04-12 17:28:30 -07:00
parent d88dbf3612
commit 5ece6fec04
15 changed files with 396 additions and 423 deletions

View File

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

5
ast.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -84,8 +84,7 @@ class AST {
public: public:
/** Add the AST for a function described by the given declaration /** Add the AST for a function described by the given declaration
information and source code. */ information and source code. */
void AddFunction(Symbol *sym, const std::vector<Symbol *> &args, void AddFunction(Symbol *sym, Stmt *code);
Stmt *code);
/** Generate LLVM IR for all of the functions into the current /** Generate LLVM IR for all of the functions into the current
module. */ module. */

409
decl.cpp
View File

@@ -33,7 +33,7 @@
/** @file decl.cpp /** @file decl.cpp
@brief Implementations of classes related to turning declarations into @brief Implementations of classes related to turning declarations into
symbols and types. symbol names and types.
*/ */
#include "decl.h" #include "decl.h"
@@ -218,50 +218,44 @@ Declarator::Declarator(DeclaratorKind dk, SourcePos p)
: pos(p), kind(dk) { : pos(p), kind(dk) {
child = NULL; child = NULL;
typeQualifiers = 0; typeQualifiers = 0;
storageClass = SC_NONE;
arraySize = -1; arraySize = -1;
sym = NULL; type = NULL;
initExpr = NULL; initExpr = NULL;
} }
void void
Declarator::InitFromDeclSpecs(DeclSpecs *ds) { Declarator::InitFromDeclSpecs(DeclSpecs *ds) {
const Type *t = GetType(ds); const Type *baseType = ds->GetBaseType(pos);
if (t == NULL) { InitFromType(baseType, ds);
if (type == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return; return;
} }
Symbol *sym = GetSymbol(); storageClass = ds->storageClass;
if (sym != NULL) {
sym->type = t; if (ds->declSpecList.size() > 0 &&
sym->storageClass = ds->storageClass; dynamic_cast<const FunctionType *>(type) == NULL) {
Error(pos, "__declspec specifiers for non-function type \"%s\" are "
"not used.", type->GetString().c_str());
} }
} }
Symbol *
Declarator::GetSymbol() const {
// The symbol lives at the last child in the chain, so walk down there
// and return the one there.
const Declarator *d = this;
while (d->child != NULL)
d = d->child;
return d->sym;
}
void void
Declarator::Print(int indent) const { Declarator::Print(int indent) const {
printf("%*cdeclarator: [", indent, ' '); printf("%*cdeclarator: [", indent, ' ');
pos.Print(); pos.Print();
lPrintTypeQualifiers(typeQualifiers); lPrintTypeQualifiers(typeQualifiers);
Symbol *sym = GetSymbol(); printf("%s ", lGetStorageClassName(storageClass));
if (sym != NULL) if (name.size() > 0)
printf("%s", sym->name.c_str()); printf("%s", name.c_str());
else else
printf("(null symbol)"); printf("(unnamed)");
printf(", array size = %d", arraySize); printf(", array size = %d", arraySize);
@@ -295,55 +289,8 @@ Declarator::Print(int indent) const {
} }
Symbol * void
Declarator::GetFunctionInfo(DeclSpecs *ds, std::vector<Symbol *> *funArgs) { Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
const FunctionType *type =
dynamic_cast<const FunctionType *>(GetType(ds));
if (type == NULL)
return NULL;
Symbol *declSym = GetSymbol();
Assert(declSym != NULL);
// 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.)
Symbol *funSym = m->symbolTable->LookupFunction(declSym->name.c_str(), type);
if (funSym == NULL)
// May be NULL due to error earlier in compilation
Assert(m->errorCount > 0);
else
funSym->pos = pos;
// Walk down to the declarator for the function. (We have to get past
// the stuff that specifies the function's return type before we get to
// the function's declarator.)
Declarator *d = this;
while (d != NULL && d->kind != DK_FUNCTION)
d = d->child;
Assert(d != NULL);
for (unsigned int i = 0; i < d->functionParams.size(); ++i) {
Symbol *sym = d->GetSymbolForFunctionParameter(i);
if (sym->type == NULL) {
Assert(m->errorCount > 0);
continue;
}
else
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
funArgs->push_back(sym);
}
if (funSym != NULL)
funSym->type = funSym->type->ResolveUnboundVariability(Variability::Varying);
return funSym;
}
const Type *
Declarator::GetType(const Type *base, DeclSpecs *ds) const {
bool hasUniformQual = ((typeQualifiers & TYPEQUAL_UNIFORM) != 0); bool hasUniformQual = ((typeQualifiers & TYPEQUAL_UNIFORM) != 0);
bool hasVaryingQual = ((typeQualifiers & TYPEQUAL_VARYING) != 0); bool hasVaryingQual = ((typeQualifiers & TYPEQUAL_VARYING) != 0);
bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0); bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0);
@@ -352,12 +299,16 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
if (hasUniformQual && hasVaryingQual) { if (hasUniformQual && hasVaryingQual) {
Error(pos, "Can't provide both \"uniform\" and \"varying\" qualifiers."); Error(pos, "Can't provide both \"uniform\" and \"varying\" qualifiers.");
return NULL; return;
} }
if (kind != DK_FUNCTION && isTask) if (kind != DK_FUNCTION && isTask) {
Error(pos, "\"task\" qualifier illegal in variable declaration."); Error(pos, "\"task\" qualifier illegal in variable declaration.");
if (kind != DK_FUNCTION && isExported) return;
}
if (kind != DK_FUNCTION && isExported) {
Error(pos, "\"export\" qualifier illegal in variable declaration."); Error(pos, "\"export\" qualifier illegal in variable declaration.");
return;
}
Variability variability(Variability::Unbound); Variability variability(Variability::Unbound);
if (hasUniformQual) if (hasUniformQual)
@@ -365,66 +316,76 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
else if (hasVaryingQual) else if (hasVaryingQual)
variability = Variability::Varying; variability = Variability::Varying;
const Type *type = base; if (kind == DK_BASE) {
switch (kind) {
case DK_BASE:
// All of the type qualifiers should be in the DeclSpecs for the // All of the type qualifiers should be in the DeclSpecs for the
// base declarator // base declarator
Assert(typeQualifiers == 0); Assert(typeQualifiers == 0);
Assert(child == NULL); Assert(child == NULL);
return type; type = baseType;
}
case DK_POINTER: else if (kind == DK_POINTER) {
/* For now, any pointer to an SOA type gets the slice property; if /* For now, any pointer to an SOA type gets the slice property; if
we add the capability to declare pointers as slices or not, we add the capability to declare pointers as slices or not,
we'll want to set this based on a type qualifier here. */ we'll want to set this based on a type qualifier here. */
type = new PointerType(type, variability, isConst, type->IsSOAType()); const Type *ptrType = new PointerType(baseType, variability, isConst,
if (child != NULL) baseType->IsSOAType());
return child->GetType(type, ds); if (child != NULL) {
child->InitFromType(ptrType, ds);
type = child->type;
name = child->name;
}
else else
return type; type = ptrType;
break; }
else if (kind == DK_REFERENCE) {
case DK_REFERENCE: if (hasUniformQual) {
if (hasUniformQual)
Error(pos, "\"uniform\" qualifier is illegal to apply to references."); Error(pos, "\"uniform\" qualifier is illegal to apply to references.");
if (hasVaryingQual) return;
}
if (hasVaryingQual) {
Error(pos, "\"varying\" qualifier is illegal to apply to references."); Error(pos, "\"varying\" qualifier is illegal to apply to references.");
if (isConst) return;
}
if (isConst) {
Error(pos, "\"const\" qualifier is to illegal apply to references."); Error(pos, "\"const\" qualifier is to illegal apply to references.");
return;
}
// The parser should disallow this already, but double check. // The parser should disallow this already, but double check.
if (dynamic_cast<const ReferenceType *>(type) != NULL) { if (dynamic_cast<const ReferenceType *>(baseType) != NULL) {
Error(pos, "References to references are illegal."); Error(pos, "References to references are illegal.");
return NULL; return;
} }
type = new ReferenceType(type); const Type *refType = new ReferenceType(baseType);
if (child != NULL) if (child != NULL) {
return child->GetType(type, ds); child->InitFromType(refType, ds);
type = child->type;
name = child->name;
}
else else
return type; type = refType;
break; }
else if (kind == DK_ARRAY) {
case DK_ARRAY: if (Type::Equal(baseType, AtomicType::Void)) {
if (Type::Equal(type, AtomicType::Void)) {
Error(pos, "Arrays of \"void\" type are illegal."); Error(pos, "Arrays of \"void\" type are illegal.");
return NULL; return;
} }
if (dynamic_cast<const ReferenceType *>(type)) { if (dynamic_cast<const ReferenceType *>(baseType)) {
Error(pos, "Arrays of references (type \"%s\") are illegal.", Error(pos, "Arrays of references (type \"%s\") are illegal.",
type->GetString().c_str()); baseType->GetString().c_str());
return NULL; return;
} }
type = new ArrayType(type, arraySize); const Type *arrayType = new ArrayType(baseType, arraySize);
if (child) if (child != NULL) {
return child->GetType(type, ds); child->InitFromType(arrayType, ds);
type = child->type;
name = child->name;
}
else else
return type; type = arrayType;
break; }
else if (kind == DK_FUNCTION) {
case DK_FUNCTION: {
std::vector<const Type *> args; std::vector<const Type *> args;
std::vector<std::string> argNames; std::vector<std::string> argNames;
std::vector<Expr *> argDefaults; std::vector<Expr *> argDefaults;
@@ -436,20 +397,40 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
for (unsigned int i = 0; i < functionParams.size(); ++i) { for (unsigned int i = 0; i < functionParams.size(); ++i) {
Declaration *d = functionParams[i]; Declaration *d = functionParams[i];
Symbol *sym = GetSymbolForFunctionParameter(i); if (d == NULL) {
Assert(m->errorCount > 0);
if (d->declSpecs->storageClass != SC_NONE) continue;
Error(sym->pos, "Storage class \"%s\" is illegal in " }
"function parameter declaration for parameter \"%s\".", if (d->declarators.size() == 0) {
lGetStorageClassName(d->declSpecs->storageClass), // function declaration like foo(float), w/o a name for the
sym->name.c_str()); // parameter; wire up a placeholder Declarator for it
if (Type::Equal(sym->type, AtomicType::Void)) { d->declarators.push_back(new Declarator(DK_BASE, pos));
Error(sym->pos, "Parameter with type \"void\" illegal in function " d->declarators[0]->InitFromDeclSpecs(d->declSpecs);
"parameter list.");
sym->type = NULL;
} }
const ArrayType *at = dynamic_cast<const ArrayType *>(sym->type); Assert(d->declarators.size() == 1);
Declarator *decl = d->declarators[0];
if (decl->name == "") {
// Give a name to any anonymous parameter declarations
char buf[32];
sprintf(buf, "__anon_parameter_%d", i);
decl->name = buf;
}
decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
if (d->declSpecs->storageClass != SC_NONE)
Error(decl->pos, "Storage class \"%s\" is illegal in "
"function parameter declaration for parameter \"%s\".",
lGetStorageClassName(d->declSpecs->storageClass),
decl->name.c_str());
if (Type::Equal(decl->type, AtomicType::Void)) {
Error(decl->pos, "Parameter with type \"void\" illegal in function "
"parameter list.");
decl->type = NULL;
}
const ArrayType *at = dynamic_cast<const ArrayType *>(decl->type);
if (at != NULL) { if (at != NULL) {
// As in C, arrays are passed to functions as pointers to // As in C, arrays are passed to functions as pointers to
// their element type. We'll just immediately make this // their element type. We'll just immediately make this
@@ -459,69 +440,66 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
// report this differently than it was originally declared // report this differently than it was originally declared
// in the function, but it's not clear that this is a // in the function, but it's not clear that this is a
// significant problem.) // significant problem.)
if (at->GetElementType() == NULL) { const Type *targetType = at->GetElementType();
if (targetType == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return;
} }
const Type *targetType = at->GetElementType(); decl->type = PointerType::GetUniform(targetType);
targetType =
targetType->ResolveUnboundVariability(Variability::Varying);
sym->type = PointerType::GetUniform(targetType);
// Make sure there are no unsized arrays (other than the // Make sure there are no unsized arrays (other than the
// first dimension) in function parameter lists. // first dimension) in function parameter lists.
at = dynamic_cast<const ArrayType *>(at->GetElementType()); at = dynamic_cast<const ArrayType *>(targetType);
while (at != NULL) { while (at != NULL) {
if (at->GetElementCount() == 0) if (at->GetElementCount() == 0)
Error(sym->pos, "Arrays with unsized dimensions in " Error(decl->pos, "Arrays with unsized dimensions in "
"dimensions after the first one are illegal in " "dimensions after the first one are illegal in "
"function parameter lists."); "function parameter lists.");
at = dynamic_cast<const ArrayType *>(at->GetElementType()); at = dynamic_cast<const ArrayType *>(at->GetElementType());
} }
} }
args.push_back(sym->type); args.push_back(decl->type);
argNames.push_back(sym->name); argNames.push_back(decl->name);
argPos.push_back(sym->pos); argPos.push_back(decl->pos);
Expr *init = NULL; Expr *init = NULL;
if (d->declarators.size()) { // Try to find an initializer expression.
// Try to find an initializer expression. while (decl != NULL) {
Declarator *decl = d->declarators[0]; if (decl->initExpr != NULL) {
while (decl != NULL) { decl->initExpr = TypeCheck(decl->initExpr);
decl->initExpr = Optimize(decl->initExpr);
if (decl->initExpr != NULL) { if (decl->initExpr != NULL) {
decl->initExpr = TypeCheck(decl->initExpr); init = dynamic_cast<ConstExpr *>(decl->initExpr);
decl->initExpr = Optimize(decl->initExpr); if (init == NULL)
if (decl->initExpr != NULL) { init = dynamic_cast<NullPointerExpr *>(decl->initExpr);
init = dynamic_cast<ConstExpr *>(decl->initExpr); if (init == NULL)
if (init == NULL) Error(decl->initExpr->pos, "Default value for parameter "
init = dynamic_cast<NullPointerExpr *>(decl->initExpr); "\"%s\" must be a compile-time constant.",
if (init == NULL) decl->name.c_str());
Error(decl->initExpr->pos, "Default value for parameter "
"\"%s\" must be a compile-time constant.",
sym->name.c_str());
}
break;
} }
else break;
decl = decl->child;
} }
else
decl = decl->child;
} }
argDefaults.push_back(init); argDefaults.push_back(init);
} }
const Type *returnType = type; const Type *returnType = baseType;
if (returnType == NULL) { if (returnType == NULL) {
Error(pos, "No return type provided in function declaration."); Error(pos, "No return type provided in function declaration.");
return NULL; return;
} }
if (dynamic_cast<const FunctionType *>(returnType) != NULL) { if (dynamic_cast<const FunctionType *>(returnType) != NULL) {
Error(pos, "Illegal to return function type from function."); Error(pos, "Illegal to return function type from function.");
return NULL; return;
} }
returnType = returnType->ResolveUnboundVariability(Variability::Varying);
bool isExternC = ds && (ds->storageClass == SC_EXTERN_C); bool isExternC = ds && (ds->storageClass == SC_EXTERN_C);
bool isExported = ds && ((ds->typeQualifiers & TYPEQUAL_EXPORT) != 0); bool isExported = ds && ((ds->typeQualifiers & TYPEQUAL_EXPORT) != 0);
bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0); bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0);
@@ -529,28 +507,27 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
if (isExported && isTask) { if (isExported && isTask) {
Error(pos, "Function can't have both \"task\" and \"export\" " Error(pos, "Function can't have both \"task\" and \"export\" "
"qualifiers"); "qualifiers");
return NULL; return;
} }
if (isExternC && isTask) { if (isExternC && isTask) {
Error(pos, "Function can't have both \"extern \"C\"\" and \"task\" " Error(pos, "Function can't have both \"extern \"C\"\" and \"task\" "
"qualifiers"); "qualifiers");
return NULL; return;
} }
if (isExternC && isExported) { if (isExternC && isExported) {
Error(pos, "Function can't have both \"extern \"C\"\" and \"export\" " Error(pos, "Function can't have both \"extern \"C\"\" and \"export\" "
"qualifiers"); "qualifiers");
return NULL; return;
} }
if (child == NULL) { if (child == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return NULL; return;
} }
const FunctionType *functionType = const FunctionType *functionType =
new FunctionType(returnType, args, argNames, argDefaults, new FunctionType(returnType, args, argNames, argDefaults,
argPos, isTask, isExported, isExternC); argPos, isTask, isExported, isExternC);
functionType = functionType->ResolveUnboundVariability(Variability::Varying);
// handle any explicit __declspecs on the function // handle any explicit __declspecs on the function
if (ds != NULL) { if (ds != NULL) {
@@ -572,60 +549,12 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
} }
} }
return child->GetType(functionType, ds); child->InitFromType(functionType, ds);
} type = child->type;
default: name = child->name;
FATAL("Unexpected decl kind");
return NULL;
} }
} }
const Type *
Declarator::GetType(DeclSpecs *ds) const {
const Type *baseType = ds->GetBaseType(pos);
const Type *type = GetType(baseType, ds);
if (ds->declSpecList.size() > 0 &&
type != NULL &&
dynamic_cast<const FunctionType *>(type) == NULL) {
Error(pos, "__declspec specifiers for non-function type \"%s\" are "
"not used.", type->GetString().c_str());
}
return type;
}
Symbol *
Declarator::GetSymbolForFunctionParameter(int paramNum) const {
Assert(paramNum < (int)functionParams.size());
Declaration *d = functionParams[paramNum];
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", paramNum);
sym = new Symbol(buf, pos);
sym->type = d->declSpecs->GetBaseType(pos);
}
else {
Assert(d->declarators.size() == 1);
sym = d->declarators[0]->GetSymbol();
if (sym == NULL) {
// Handle more complex anonymous declarations like
// float (float **).
sprintf(buf, "__anon_parameter_%d", paramNum);
sym = new Symbol(buf, d->declarators[0]->pos);
sym->type = d->declarators[0]->GetType(d->declSpecs);
}
}
return sym;
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Declaration // Declaration
@@ -655,27 +584,23 @@ Declaration::GetVariableDeclarations() const {
for (unsigned int i = 0; i < declarators.size(); ++i) { for (unsigned int i = 0; i < declarators.size(); ++i) {
Declarator *decl = declarators[i]; Declarator *decl = declarators[i];
if (decl == NULL) { if (decl == NULL || decl->type == NULL) {
// Ignore earlier errors // Ignore earlier errors
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
continue; continue;
} }
Symbol *sym = decl->GetSymbol(); if (Type::Equal(decl->type, AtomicType::Void))
if (sym == NULL || sym->type == NULL) { Error(decl->pos, "\"void\" type variable illegal in declaration.");
// Ignore errors else if (dynamic_cast<const FunctionType *>(decl->type) == NULL) {
Assert(m->errorCount > 0); decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
continue; Symbol *sym = new Symbol(decl->name, decl->pos, decl->type,
} decl->storageClass);
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
if (Type::Equal(sym->type, AtomicType::Void))
Error(sym->pos, "\"void\" type variable illegal in declaration.");
else if (dynamic_cast<const FunctionType *>(sym->type) == NULL) {
m->symbolTable->AddVariable(sym); m->symbolTable->AddVariable(sym);
vars.push_back(VariableDeclaration(sym, decl->initExpr)); vars.push_back(VariableDeclaration(sym, decl->initExpr));
} }
} }
return vars; return vars;
} }
@@ -686,25 +611,20 @@ Declaration::DeclareFunctions() {
for (unsigned int i = 0; i < declarators.size(); ++i) { for (unsigned int i = 0; i < declarators.size(); ++i) {
Declarator *decl = declarators[i]; Declarator *decl = declarators[i];
if (decl == NULL) { if (decl == NULL || decl->type == NULL) {
// Ignore earlier errors // Ignore earlier errors
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
continue; continue;
} }
Symbol *sym = decl->GetSymbol(); const FunctionType *ftype =
if (sym == NULL || sym->type == NULL) { dynamic_cast<const FunctionType *>(decl->type);
// Ignore errors if (ftype == NULL)
Assert(m->errorCount > 0);
continue;
}
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
if (dynamic_cast<const FunctionType *>(sym->type) == NULL)
continue; continue;
bool isInline = (declSpecs->typeQualifiers & TYPEQUAL_INLINE); bool isInline = (declSpecs->typeQualifiers & TYPEQUAL_INLINE);
m->AddFunctionDeclaration(sym, isInline); m->AddFunctionDeclaration(decl->name, ftype, decl->storageClass,
isInline, decl->pos);
} }
} }
@@ -718,6 +638,7 @@ Declaration::Print(int indent) const {
declarators[i]->Print(indent+4); declarators[i]->Print(indent+4);
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
void void
@@ -748,21 +669,19 @@ GetStructTypesNamesPositions(const std::vector<StructDeclaration *> &sd,
Declarator *d = (*sd[i]->declarators)[j]; Declarator *d = (*sd[i]->declarators)[j];
d->InitFromDeclSpecs(&ds); d->InitFromDeclSpecs(&ds);
Symbol *sym = d->GetSymbol(); if (Type::Equal(d->type, AtomicType::Void))
if (Type::Equal(sym->type, AtomicType::Void))
Error(d->pos, "\"void\" type illegal for struct member."); Error(d->pos, "\"void\" type illegal for struct member.");
elementTypes->push_back(sym->type); elementTypes->push_back(d->type);
if (seenNames.find(sym->name) != seenNames.end()) if (seenNames.find(d->name) != seenNames.end())
Error(d->pos, "Struct member \"%s\" has same name as a " Error(d->pos, "Struct member \"%s\" has same name as a "
"previously-declared member.", sym->name.c_str()); "previously-declared member.", d->name.c_str());
else else
seenNames.insert(sym->name); seenNames.insert(d->name);
elementNames->push_back(sym->name); elementNames->push_back(d->name);
elementPositions->push_back(sym->pos); elementPositions->push_back(d->pos);
} }
} }

45
decl.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,8 @@
variables--here, that the declaration has the 'static' and 'uniform' variables--here, that the declaration has the 'static' and 'uniform'
qualifiers, and that it's basic type is 'int'. Then for each variable qualifiers, and that it's basic type is 'int'. Then for each variable
declaration, the Declaraiton class holds an instance of a Declarator, declaration, the Declaraiton class holds an instance of a Declarator,
which in turn records the per-variable information like the symbol which in turn records the per-variable information like the name, array
name, array size (if any), initializer expression, etc. size (if any), initializer expression, etc.
*/ */
#ifndef ISPC_DECL_H #ifndef ISPC_DECL_H
@@ -61,15 +61,6 @@ struct VariableDeclaration;
class Declaration; class Declaration;
class Declarator; class Declarator;
enum StorageClass {
SC_NONE,
SC_EXTERN,
SC_STATIC,
SC_TYPEDEF,
SC_EXTERN_C
};
/* Multiple qualifiers can be provided with types in declarations; /* Multiple qualifiers can be provided with types in declarations;
therefore, they are set up so that they can be ANDed together into an therefore, they are set up so that they can be ANDed together into an
int. */ int. */
@@ -141,25 +132,11 @@ public:
Declarator(DeclaratorKind dk, SourcePos p); Declarator(DeclaratorKind dk, SourcePos p);
/** Once a DeclSpecs instance is available, this method completes the /** Once a DeclSpecs instance is available, this method completes the
initialization of the Symbol, setting its Type accordingly. initialization of the type member.
*/ */
void InitFromDeclSpecs(DeclSpecs *ds); void InitFromDeclSpecs(DeclSpecs *ds);
/** Get the actual type of the combination of Declarator and the given void InitFromType(const Type *base, DeclSpecs *ds);
DeclSpecs. If an explicit base type is provided, the declarator is
applied to that type; otherwise the base type from the DeclSpecs is
used. */
const Type *GetType(DeclSpecs *ds) const;
const Type *GetType(const Type *base, DeclSpecs *ds) const;
/** Returns the symbol corresponding to the function declared by this
declarator and symbols for its arguments in *args. */
Symbol *GetFunctionInfo(DeclSpecs *ds, std::vector<Symbol *> *args);
Symbol *GetSymbolForFunctionParameter(int paramNum) const;
/** Returns the symbol associated with the declarator. */
Symbol *GetSymbol() const;
void Print(int indent) const; void Print(int indent) const;
@@ -180,18 +157,24 @@ public:
/** Type qualifiers provided with the declarator. */ /** Type qualifiers provided with the declarator. */
int typeQualifiers; int typeQualifiers;
StorageClass storageClass;
/** For array declarators, this gives the declared size of the array. /** For array declarators, this gives the declared size of the array.
Unsized arrays have arraySize == 0. */ Unsized arrays have arraySize == 0. */
int arraySize; int arraySize;
/** Symbol associated with the declarator. */ /** Name associated with the declarator. */
Symbol *sym; std::string name;
/** Initialization expression for the variable. May be NULL. */ /** Initialization expression for the variable. May be NULL. */
Expr *initExpr; Expr *initExpr;
/** Type of the declarator. This is NULL until InitFromDeclSpecs() or
InitFromType() is called. */
const Type *type;
/** For function declarations, this holds the Declaration *s for the /** For function declarations, this holds the Declaration *s for the
funciton's parameters. */ function's parameters. */
std::vector<Declaration *> functionParams; std::vector<Declaration *> functionParams;
}; };

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -66,9 +66,8 @@
#include <llvm/Support/ToolOutputFile.h> #include <llvm/Support/ToolOutputFile.h>
#include <llvm/Assembly/PrintModulePass.h> #include <llvm/Assembly/PrintModulePass.h>
Function::Function(Symbol *s, const std::vector<Symbol *> &a, Stmt *c) { Function::Function(Symbol *s, Stmt *c) {
sym = s; sym = s;
args = a;
code = c; code = c;
maskSymbol = m->symbolTable->LookupVariable("__mask"); maskSymbol = m->symbolTable->LookupVariable("__mask");
@@ -104,9 +103,17 @@ Function::Function(Symbol *s, const std::vector<Symbol *> &a, Stmt *c) {
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type); const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
Assert(type != NULL); Assert(type != NULL);
for (unsigned int i = 0; i < args.size(); ++i) for (int i = 0; i < type->GetNumParameters(); ++i) {
if (dynamic_cast<const ReferenceType *>(args[i]->type) == NULL) const char *paramName = type->GetParameterName(i).c_str();
args[i]->parentFunction = this; Symbol *sym = m->symbolTable->LookupVariable(paramName);
if (sym == NULL)
Assert(strncmp(paramName, "__anon_parameter_", 17) == 0);
args.push_back(sym);
const Type *t = type->GetParameterType(i);
if (sym != NULL && dynamic_cast<const ReferenceType *>(t) == NULL)
sym->parentFunction = this;
}
if (type->isTask) { if (type->isTask) {
threadIndexSym = m->symbolTable->LookupVariable("threadIndex"); threadIndexSym = m->symbolTable->LookupVariable("threadIndex");
@@ -145,7 +152,8 @@ Function::GetType() const {
'mem2reg' pass will in turn promote to SSA registers.. 'mem2reg' pass will in turn promote to SSA registers..
*/ */
static void static void
lCopyInTaskParameter(int i, llvm::Value *structArgPtr, const std::vector<Symbol *> &args, lCopyInTaskParameter(int i, llvm::Value *structArgPtr, const
std::vector<Symbol *> &args,
FunctionEmitContext *ctx) { FunctionEmitContext *ctx) {
// We expect the argument structure to come in as a poitner to a // We expect the argument structure to come in as a poitner to a
// structure. Confirm and figure out its type here. // structure. Confirm and figure out its type here.
@@ -160,6 +168,10 @@ lCopyInTaskParameter(int i, llvm::Value *structArgPtr, const std::vector<Symbol
LLVM_TYPE_CONST llvm::Type *argType = argStructType->getElementType(i); LLVM_TYPE_CONST llvm::Type *argType = argStructType->getElementType(i);
Symbol *sym = args[i]; Symbol *sym = args[i];
if (sym == NULL)
// anonymous parameter, so don't worry about it
return;
// allocate space to copy the parameter in to // allocate space to copy the parameter in to
sym->storagePtr = ctx->AllocaInst(argType, sym->name.c_str()); sym->storagePtr = ctx->AllocaInst(argType, sym->name.c_str());
@@ -240,6 +252,10 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
llvm::Function::arg_iterator argIter = function->arg_begin(); llvm::Function::arg_iterator argIter = function->arg_begin();
for (unsigned int i = 0; i < args.size(); ++i, ++argIter) { for (unsigned int i = 0; i < args.size(); ++i, ++argIter) {
Symbol *sym = args[i]; Symbol *sym = args[i];
if (sym == NULL)
// anonymous function parameter
continue;
argIter->setName(sym->name.c_str()); argIter->setName(sym->name.c_str());
// Allocate stack storage for the parameter and emit code // Allocate stack storage for the parameter and emit code

4
func.h
View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2011, Intel Corporation Copyright (c) 2011-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
class Function { class Function {
public: public:
Function(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code); Function(Symbol *sym, Stmt *code);
const Type *GetReturnType() const; const Type *GetReturnType() const;
const FunctionType *GetType() const; const FunctionType *GetType() const;

9
ispc.h
View File

@@ -116,6 +116,15 @@ class SymbolTable;
class Type; class Type;
struct VariableDeclaration; struct VariableDeclaration;
enum StorageClass {
SC_NONE,
SC_EXTERN,
SC_STATIC,
SC_TYPEDEF,
SC_EXTERN_C
};
/** @brief Representation of a range of positions in a source file. /** @brief Representation of a range of positions in a source file.
This class represents a range of characters in a source file This class represents a range of characters in a source file

View File

@@ -231,64 +231,65 @@ Module::CompileFile() {
void void
Module::AddTypeDef(Symbol *sym) { Module::AddTypeDef(const std::string &name, const Type *type,
SourcePos pos) {
// Typedefs are easy; just add the mapping between the given name and // Typedefs are easy; just add the mapping between the given name and
// the given type. // the given type.
symbolTable->AddType(sym->name.c_str(), sym->type, sym->pos); symbolTable->AddType(name.c_str(), type, pos);
} }
void void
Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) { Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initExpr,
bool isConst, StorageClass storageClass, SourcePos pos) {
// These may be NULL due to errors in parsing; just gracefully return // These may be NULL due to errors in parsing; just gracefully return
// here if so. // here if so.
if (sym == NULL || sym->type == NULL) { if (name == "" || type == NULL) {
// But if these are NULL and there haven't been any previous
// errors, something surprising is going on
Assert(errorCount > 0); Assert(errorCount > 0);
return; return;
} }
if (symbolTable->LookupFunction(sym->name.c_str())) { if (symbolTable->LookupFunction(name.c_str())) {
Error(sym->pos, "Global variable \"%s\" shadows previously-declared " Error(pos, "Global variable \"%s\" shadows previously-declared "
"function.", sym->name.c_str()); "function.", name.c_str());
return; return;
} }
if (sym->storageClass == SC_EXTERN_C) { if (storageClass == SC_EXTERN_C) {
Error(sym->pos, "extern \"C\" qualifier can only be used for " Error(pos, "extern \"C\" qualifier can only be used for "
"functions."); "functions.");
return; return;
} }
if (Type::Equal(sym->type, AtomicType::Void)) { if (Type::Equal(type, AtomicType::Void)) {
Error(sym->pos, "\"void\" type global variable is illegal."); Error(pos, "\"void\" type global variable is illegal.");
return; return;
} }
sym->type = ArrayType::SizeUnsizedArrays(sym->type, initExpr); type = ArrayType::SizeUnsizedArrays(type, initExpr);
if (sym->type == NULL) if (type == NULL)
return; return;
const ArrayType *at = dynamic_cast<const ArrayType *>(sym->type); const ArrayType *at = dynamic_cast<const ArrayType *>(type);
if (at != NULL && at->TotalElementCount() == 0) { if (at != NULL && at->TotalElementCount() == 0) {
Error(sym->pos, "Illegal to declare a global variable with unsized " Error(pos, "Illegal to declare a global variable with unsized "
"array dimensions that aren't set with an initializer " "array dimensions that aren't set with an initializer "
"expression."); "expression.");
return; return;
} }
LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx); LLVM_TYPE_CONST llvm::Type *llvmType = type->LLVMType(g->ctx);
if (llvmType == NULL) if (llvmType == NULL)
return; return;
// See if we have an initializer expression for the global. If so, // See if we have an initializer expression for the global. If so,
// make sure it's a compile-time constant! // make sure it's a compile-time constant!
llvm::Constant *llvmInitializer = NULL; llvm::Constant *llvmInitializer = NULL;
if (sym->storageClass == SC_EXTERN || sym->storageClass == SC_EXTERN_C) { ConstExpr *constValue = NULL;
if (storageClass == SC_EXTERN || storageClass == SC_EXTERN_C) {
if (initExpr != NULL) if (initExpr != NULL)
Error(sym->pos, "Initializer can't be provided with \"extern\" " Error(pos, "Initializer can't be provided with \"extern\" "
"global variable \"%s\".", sym->name.c_str()); "global variable \"%s\".", name.c_str());
} }
else { else {
if (initExpr != NULL) { if (initExpr != NULL) {
@@ -299,27 +300,26 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
// ExprList; they don't have types per se / can't type // ExprList; they don't have types per se / can't type
// convert themselves anyway.) // convert themselves anyway.)
if (dynamic_cast<ExprList *>(initExpr) == NULL) if (dynamic_cast<ExprList *>(initExpr) == NULL)
initExpr = TypeConvertExpr(initExpr, sym->type, "initializer"); initExpr = TypeConvertExpr(initExpr, type, "initializer");
if (initExpr != NULL) { if (initExpr != NULL) {
initExpr = Optimize(initExpr); initExpr = Optimize(initExpr);
// Fingers crossed, now let's see if we've got a // Fingers crossed, now let's see if we've got a
// constant value.. // constant value..
llvmInitializer = initExpr->GetConstant(sym->type); llvmInitializer = initExpr->GetConstant(type);
if (llvmInitializer != NULL) { if (llvmInitializer != NULL) {
if (sym->type->IsConstType()) if (type->IsConstType())
// Try to get a ConstExpr associated with // Try to get a ConstExpr associated with
// the symbol. This dynamic_cast can // the symbol. This dynamic_cast can
// validly fail, for example for types like // validly fail, for example for types like
// StructTypes where a ConstExpr can't // StructTypes where a ConstExpr can't
// represent their values. // represent their values.
sym->constValue = constValue = dynamic_cast<ConstExpr *>(initExpr);
dynamic_cast<ConstExpr *>(initExpr);
} }
else else
Error(initExpr->pos, "Initializer for global variable \"%s\" " Error(initExpr->pos, "Initializer for global variable \"%s\" "
"must be a constant.", sym->name.c_str()); "must be a constant.", name.c_str());
} }
} }
} }
@@ -330,30 +330,33 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
llvmInitializer = llvm::Constant::getNullValue(llvmType); llvmInitializer = llvm::Constant::getNullValue(llvmType);
} }
Symbol *stSym = symbolTable->LookupVariable(sym->name.c_str()); Symbol *sym = symbolTable->LookupVariable(name.c_str());
llvm::GlobalVariable *oldGV = NULL; llvm::GlobalVariable *oldGV = NULL;
if (stSym != NULL) { if (sym != NULL) {
// We've already seen either a declaration or a definition of this // We've already seen either a declaration or a definition of this
// global. // global.
// If the type doesn't match with the previous one, issue an error. // If the type doesn't match with the previous one, issue an error.
if (!Type::Equal(sym->type, stSym->type)) { if (!Type::Equal(sym->type, type) ||
Error(sym->pos, "Definition of variable \"%s\" conflicts with " (sym->storageClass != SC_EXTERN &&
"definition at %s:%d.", sym->name.c_str(), sym->storageClass != SC_EXTERN_C &&
stSym->pos.name, stSym->pos.first_line); sym->storageClass != storageClass)) {
Error(pos, "Definition of variable \"%s\" conflicts with "
"definition at %s:%d.", name.c_str(),
sym->pos.name, sym->pos.first_line);
return; return;
} }
llvm::GlobalVariable *gv = llvm::GlobalVariable *gv =
llvm::dyn_cast<llvm::GlobalVariable>(stSym->storagePtr); llvm::dyn_cast<llvm::GlobalVariable>(sym->storagePtr);
Assert(gv != NULL); Assert(gv != NULL);
// And issue an error if this is a redefinition of a variable // And issue an error if this is a redefinition of a variable
if (gv->hasInitializer() && if (gv->hasInitializer() &&
sym->storageClass != SC_EXTERN && sym->storageClass != SC_EXTERN_C) { sym->storageClass != SC_EXTERN && sym->storageClass != SC_EXTERN_C) {
Error(sym->pos, "Redefinition of variable \"%s\" is illegal. " Error(pos, "Redefinition of variable \"%s\" is illegal. "
"(Previous definition at %s:%d.)", sym->name.c_str(), "(Previous definition at %s:%d.)", sym->name.c_str(),
stSym->pos.name, stSym->pos.first_line); sym->pos.name, sym->pos.first_line);
return; return;
} }
@@ -361,17 +364,12 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
// of a previously-declared global. First, save the pointer to the // of a previously-declared global. First, save the pointer to the
// previous llvm::GlobalVariable // previous llvm::GlobalVariable
oldGV = gv; oldGV = gv;
// Now copy over all of the members of the current Symbol to the
// symbol in the symbol table.
*stSym = *sym;
// And copy the pointer of the one in the symbol table to sym, so
// that the operations below update storagePtr for the Symbol
// already in the symbol table.
sym = stSym;
} }
else else {
sym = new Symbol(name, pos, type, storageClass);
symbolTable->AddVariable(sym); symbolTable->AddVariable(sym);
}
sym->constValue = constValue;
llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::LinkageTypes linkage =
(sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage : (sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage :
@@ -393,10 +391,10 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
} }
if (diBuilder) { if (diBuilder) {
llvm::DIFile file = sym->pos.GetDIFile(); llvm::DIFile file = pos.GetDIFile();
diBuilder->createGlobalVariable(sym->name, diBuilder->createGlobalVariable(name,
file, file,
sym->pos.first_line, pos.first_line,
sym->type->GetDIType(file), sym->type->GetDIType(file),
(sym->storageClass == SC_STATIC), (sym->storageClass == SC_STATIC),
sym->storagePtr); sym->storagePtr);
@@ -487,22 +485,23 @@ lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
false if any errors were encountered. false if any errors were encountered.
*/ */
void void
Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) { Module::AddFunctionDeclaration(const std::string &name,
const FunctionType *functionType = const FunctionType *functionType,
dynamic_cast<const FunctionType *>(funSym->type); StorageClass storageClass, bool isInline,
SourcePos pos) {
Assert(functionType != NULL); Assert(functionType != NULL);
// If a global variable with the same name has already been declared // If a global variable with the same name has already been declared
// issue an error. // issue an error.
if (symbolTable->LookupVariable(funSym->name.c_str()) != NULL) { if (symbolTable->LookupVariable(name.c_str()) != NULL) {
Error(funSym->pos, "Function \"%s\" shadows previously-declared global variable. " Error(pos, "Function \"%s\" shadows previously-declared global variable. "
"Ignoring this definition.", "Ignoring this definition.",
funSym->name.c_str()); name.c_str());
return; return;
} }
std::vector<Symbol *> overloadFuncs; std::vector<Symbol *> overloadFuncs;
symbolTable->LookupFunction(funSym->name.c_str(), &overloadFuncs); symbolTable->LookupFunction(name.c_str(), &overloadFuncs);
if (overloadFuncs.size() > 0) { if (overloadFuncs.size() > 0) {
for (unsigned int i = 0; i < overloadFuncs.size(); ++i) { for (unsigned int i = 0; i < overloadFuncs.size(); ++i) {
Symbol *overloadFunc = overloadFuncs[i]; Symbol *overloadFunc = overloadFuncs[i];
@@ -528,7 +527,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
if (i == functionType->GetNumParameters()) { if (i == functionType->GetNumParameters()) {
std::string thisRetType = functionType->GetReturnTypeString(); std::string thisRetType = functionType->GetReturnTypeString();
std::string otherRetType = ofType->GetReturnTypeString(); std::string otherRetType = ofType->GetReturnTypeString();
Error(funSym->pos, "Illegal to overload function by return " Error(pos, "Illegal to overload function by return "
"type only. This function returns \"%s\" while " "type only. This function returns \"%s\" while "
"previous declaration at %s:%d returns \"%s\".", "previous declaration at %s:%d returns \"%s\".",
thisRetType.c_str(), overloadFunc->pos.name, thisRetType.c_str(), overloadFunc->pos.name,
@@ -539,55 +538,54 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
} }
} }
if (funSym->storageClass == SC_EXTERN_C) { if (storageClass == SC_EXTERN_C) {
// Make sure the user hasn't supplied both an 'extern "C"' and a // Make sure the user hasn't supplied both an 'extern "C"' and a
// 'task' qualifier with the function // 'task' qualifier with the function
if (functionType->isTask) { if (functionType->isTask) {
Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern " Error(pos, "\"task\" qualifier is illegal with C-linkage extern "
"function \"%s\". Ignoring this function.", funSym->name.c_str()); "function \"%s\". Ignoring this function.", name.c_str());
return; return;
} }
std::vector<Symbol *> funcs; std::vector<Symbol *> funcs;
symbolTable->LookupFunction(funSym->name.c_str(), &funcs); symbolTable->LookupFunction(name.c_str(), &funcs);
if (funcs.size() > 0) { if (funcs.size() > 0) {
if (funcs.size() > 1) { if (funcs.size() > 1) {
// Multiple functions with this name have already been declared; // Multiple functions with this name have already been declared;
// can't overload here // can't overload here
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; " Error(pos, "Can't overload extern \"C\" function \"%s\"; "
"%d functions with the same name have already been declared.", "%d functions with the same name have already been declared.",
funSym->name.c_str(), (int)funcs.size()); name.c_str(), (int)funcs.size());
return; return;
} }
// One function with the same name has been declared; see if it // 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. // has the same type as this one, in which case it's ok.
if (Type::Equal(funcs[0]->type, funSym->type)) if (Type::Equal(funcs[0]->type, functionType))
return; return;
else { else {
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".", Error(pos, "Can't overload extern \"C\" function \"%s\".",
funSym->name.c_str()); name.c_str());
return; return;
} }
} }
} }
// Get the LLVM FunctionType // Get the LLVM FunctionType
bool includeMask = (funSym->storageClass != SC_EXTERN_C); bool includeMask = (storageClass != SC_EXTERN_C);
LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType = LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType =
functionType->LLVMFunctionType(g->ctx, includeMask); functionType->LLVMFunctionType(g->ctx, includeMask);
if (llvmFunctionType == NULL) if (llvmFunctionType == NULL)
return; return;
// And create the llvm::Function // And create the llvm::Function
llvm::GlobalValue::LinkageTypes linkage = (funSym->storageClass == SC_STATIC || llvm::GlobalValue::LinkageTypes linkage = (storageClass == SC_STATIC ||
isInline) ? isInline) ?
llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage; llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
std::string functionName;
if (funSym->storageClass == SC_EXTERN_C) std::string functionName = name;
functionName = funSym->name; if (storageClass != SC_EXTERN_C) {
else { functionName += functionType->Mangle();
functionName = funSym->MangledName();
if (g->mangleFunctionsWithTarget) if (g->mangleFunctionsWithTarget)
functionName += g->target.GetISAString(); functionName += g->target.GetISAString();
} }
@@ -597,7 +595,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
// Set function attributes: we never throw exceptions // Set function attributes: we never throw exceptions
function->setDoesNotThrow(true); function->setDoesNotThrow(true);
if (!(funSym->storageClass == SC_EXTERN_C) && if (storageClass != SC_EXTERN_C &&
!g->generateDebuggingSymbols && !g->generateDebuggingSymbols &&
isInline) isInline)
function->addFnAttr(llvm::Attribute::AlwaysInline); function->addFnAttr(llvm::Attribute::AlwaysInline);
@@ -609,15 +607,15 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
// 'export'ed. // 'export'ed.
if (functionType->isExported && if (functionType->isExported &&
lRecursiveCheckValidParamType(functionType->GetReturnType())) lRecursiveCheckValidParamType(functionType->GetReturnType()))
Error(funSym->pos, "Illegal to return a \"varying\" type from exported " Error(pos, "Illegal to return a \"varying\" type from exported "
"function \"%s\"", funSym->name.c_str()); "function \"%s\"", name.c_str());
if (functionType->isTask && if (functionType->isTask &&
Type::Equal(functionType->GetReturnType(), AtomicType::Void) == false) Type::Equal(functionType->GetReturnType(), AtomicType::Void) == false)
Error(funSym->pos, "Task-qualified functions must have void return type."); Error(pos, "Task-qualified functions must have void return type.");
if (functionType->isExported || functionType->isExternC) if (functionType->isExported || functionType->isExternC)
lCheckForStructParameters(functionType, funSym->pos); lCheckForStructParameters(functionType, pos);
// Loop over all of the arguments; process default values if present // Loop over all of the arguments; process default values if present
// and do other checks and parameter attribute setting. // and do other checks and parameter attribute setting.
@@ -675,19 +673,33 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
function->eraseFromParent(); function->eraseFromParent();
function = module->getFunction(functionName); function = module->getFunction(functionName);
} }
funSym->function = function;
// Finally, we know all is good and we can add the function to the // Finally, we know all is good and we can add the function to the
// symbol table // symbol table
Symbol *funSym = new Symbol(name, pos, functionType, storageClass);
funSym->function = function;
bool ok = symbolTable->AddFunction(funSym); bool ok = symbolTable->AddFunction(funSym);
Assert(ok); Assert(ok);
} }
void void
Module::AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args, Module::AddFunctionDefinition(const std::string &name, const FunctionType *type,
Stmt *code) { Stmt *code) {
ast->AddFunction(sym, args, code); Symbol *sym = symbolTable->LookupFunction(name.c_str(), type);
if (sym == NULL) {
Assert(m->errorCount > 0);
return;
}
// FIXME: because we encode the parameter names in the function type,
// we need to override the function type here in case the function had
// earlier been declared with anonymous parameter names but is now
// defined with actual names. This is yet another reason we shouldn't
// include the names in FunctionType...
sym->type = type;
ast->AddFunction(sym, code);
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2010-2011, Intel Corporation Copyright (c) 2010-2012, Intel Corporation
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -59,21 +59,26 @@ public:
int CompileFile(); int CompileFile();
/** Add a named type definition to the module. */ /** Add a named type definition to the module. */
void AddTypeDef(Symbol *sym); void AddTypeDef(const std::string &name, const Type *type,
SourcePos pos);
/** Add a new global variable corresponding to the given Symbol to the /** Add a new global variable corresponding to the given Symbol to the
module. If non-NULL, initExpr gives the initiailizer expression module. If non-NULL, initExpr gives the initiailizer expression
for the global's inital value. */ for the global's inital value. */
void AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst); void AddGlobalVariable(const std::string &name, const Type *type,
Expr *initExpr, bool isConst,
StorageClass storageClass, SourcePos pos);
/** Add a declaration of the function defined by the given function /** Add a declaration of the function defined by the given function
symbol to the module. */ symbol to the module. */
void AddFunctionDeclaration(Symbol *funSym, bool isInline); void AddFunctionDeclaration(const std::string &name,
const FunctionType *ftype,
StorageClass sc, bool isInline, SourcePos pos);
/** Adds the function described by the declaration information and the /** Adds the function described by the declaration information and the
provided statements to the module. */ provided statements to the module. */
void AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args, void AddFunctionDefinition(const std::string &name,
Stmt *code); const FunctionType *ftype, Stmt *code);
/** After a source file has been compiled, output can be generated in a /** After a source file has been compiled, output can be generated in a
number of different formats. */ number of different formats. */

View File

@@ -631,7 +631,9 @@ declaration_statement
if ($1->declarators[i] == NULL) if ($1->declarators[i] == NULL)
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
else else
m->AddTypeDef($1->declarators[i]->GetSymbol()); m->AddTypeDef($1->declarators[i]->name,
$1->declarators[i]->type,
$1->declarators[i]->pos);
} }
$$ = NULL; $$ = NULL;
} }
@@ -1174,7 +1176,7 @@ direct_declarator
: TOKEN_IDENTIFIER : TOKEN_IDENTIFIER
{ {
Declarator *d = new Declarator(DK_BASE, @1); Declarator *d = new Declarator(DK_BASE, @1);
d->sym = new Symbol(yytext, @1); d->name = yytext;
$$ = d; $$ = d;
} }
| '(' declarator ')' | '(' declarator ')'
@@ -1349,8 +1351,10 @@ type_name
{ {
if ($1 == NULL || $2 == NULL) if ($1 == NULL || $2 == NULL)
$$ = NULL; $$ = NULL;
else else {
$$ = $2->GetType($1, NULL); $2->InitFromType($1, NULL);
$$ = $2->type;
}
} }
; ;
@@ -1854,11 +1858,14 @@ function_definition
} }
compound_statement compound_statement
{ {
std::vector<Symbol *> args;
if ($2 != NULL) { if ($2 != NULL) {
Symbol *sym = $2->GetFunctionInfo($1, &args); $2->InitFromDeclSpecs($1);
if (sym != NULL) const FunctionType *funcType =
m->AddFunctionDefinition(sym, args, $4); dynamic_cast<const FunctionType *>($2->type);
if (funcType == NULL)
Assert(m->errorCount > 0);
else
m->AddFunctionDefinition($2->name, funcType, $4);
} }
m->symbolTable->PopScope(); // push in lAddFunctionParams(); m->symbolTable->PopScope(); // push in lAddFunctionParams();
} }
@@ -1968,35 +1975,27 @@ lAddDeclaration(DeclSpecs *ds, Declarator *decl) {
// Error happened earlier during parsing // Error happened earlier during parsing
return; return;
decl->InitFromDeclSpecs(ds);
if (ds->storageClass == SC_TYPEDEF) if (ds->storageClass == SC_TYPEDEF)
m->AddTypeDef(decl->GetSymbol()); m->AddTypeDef(decl->name, decl->type, decl->pos);
else { else {
const Type *t = decl->GetType(ds); if (decl->type == NULL) {
if (t == NULL) {
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
return; return;
} }
Symbol *sym = decl->GetSymbol(); decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
if (sym == NULL) {
Assert(m->errorCount > 0); const FunctionType *ft = dynamic_cast<const FunctionType *>(decl->type);
return;
}
const FunctionType *ft = dynamic_cast<const FunctionType *>(t);
if (ft != NULL) { if (ft != NULL) {
sym->type = ft;
sym->storageClass = ds->storageClass;
bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE); bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE);
m->AddFunctionDeclaration(sym, isInline); m->AddFunctionDeclaration(decl->name, ft, ds->storageClass,
isInline, decl->pos);
} }
else { else {
if (sym->type == NULL)
Assert(m->errorCount > 0);
else
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
bool isConst = (ds->typeQualifiers & TYPEQUAL_CONST) != 0; bool isConst = (ds->typeQualifiers & TYPEQUAL_CONST) != 0;
m->AddGlobalVariable(sym, decl->initExpr, isConst); m->AddGlobalVariable(decl->name, decl->type, decl->initExpr,
isConst, decl->storageClass, decl->pos);
} }
} }
} }
@@ -2025,16 +2024,13 @@ lAddFunctionParams(Declarator *decl) {
// now loop over its parameters and add them to the symbol table // now loop over its parameters and add them to the symbol table
for (unsigned int i = 0; i < decl->functionParams.size(); ++i) { for (unsigned int i = 0; i < decl->functionParams.size(); ++i) {
Declaration *pdecl = decl->functionParams[i]; Declaration *pdecl = decl->functionParams[i];
if (pdecl == NULL || pdecl->declarators.size() == 0) Assert(pdecl != NULL && pdecl->declarators.size() == 1);
// zero size declarators array corresponds to an anonymous Declarator *declarator = pdecl->declarators[0];
// parameter if (declarator == NULL)
continue;
Assert(pdecl->declarators.size() == 1);
Symbol *sym = pdecl->declarators[0]->GetSymbol();
if (sym == NULL || sym->type == NULL)
Assert(m->errorCount > 0); Assert(m->errorCount > 0);
else { else {
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying); Symbol *sym = new Symbol(declarator->name, declarator->pos,
declarator->type, declarator->storageClass);
#ifndef NDEBUG #ifndef NDEBUG
bool ok = m->symbolTable->AddVariable(sym); bool ok = m->symbolTable->AddVariable(sym);
if (ok == false) if (ok == false)

View File

@@ -56,12 +56,6 @@ Symbol::Symbol(const std::string &n, SourcePos p, const Type *t,
} }
std::string
Symbol::MangledName() const {
return name + type->Mangle();
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// SymbolTable // SymbolTable

7
sym.h
View File

@@ -67,13 +67,6 @@ public:
Symbol(const std::string &name, SourcePos pos, const Type *t = NULL, Symbol(const std::string &name, SourcePos pos, const Type *t = NULL,
StorageClass sc = SC_NONE); StorageClass sc = SC_NONE);
/** This method should only be called for function symbols; for them,
it returns a mangled version of the function name with the argument
types encoded into the returned name. This is used to generate
unique symbols in object files for overloaded functions.
*/
std::string MangledName() const;
SourcePos pos; /*!< Source file position where the symbol was defined */ SourcePos pos; /*!< Source file position where the symbol was defined */
std::string name; /*!< Symbol's name */ std::string name; /*!< Symbol's name */
llvm::Value *storagePtr; /*!< For symbols with storage associated with llvm::Value *storagePtr; /*!< For symbols with storage associated with

View File

@@ -0,0 +1,15 @@
export uniform int width() { return programCount; }
float foo(float &) { return 1; }
float bar(uniform float []) { return 2; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
float x = 0;
RET[programIndex] = foo(x) + bar(aFOO);
}
export void result(uniform float RET[]) {
RET[programIndex] = 3;
}

View File

@@ -0,0 +1,14 @@
export uniform int width() { return programCount; }
extern int foo;
int foo = 1;
export void f_f(uniform float RET[], uniform float aFOO[]) {
RET[programIndex] = foo;
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

View File

@@ -0,0 +1,18 @@
export uniform int width() { return programCount; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
uniform int x[2][10];
for (uniform int i = 0; i < 2; ++i) {
for (uniform int j = 0; j < 10; ++j) {
x[i][j] = 10*i+j;
}
}
uniform int (* varying y)[10] = x;
RET[programIndex] = y[1][programIndex % 5];
}
export void result(uniform float RET[]) {
RET[programIndex] = 10+ (programIndex % 5);
}