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:
4
ast.cpp
4
ast.cpp
@@ -55,10 +55,10 @@ ASTNode::~ASTNode() {
|
||||
// AST
|
||||
|
||||
void
|
||||
AST::AddFunction(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code) {
|
||||
AST::AddFunction(Symbol *sym, Stmt *code) {
|
||||
if (sym == NULL)
|
||||
return;
|
||||
functions.push_back(new Function(sym, args, code));
|
||||
functions.push_back(new Function(sym, code));
|
||||
}
|
||||
|
||||
|
||||
|
||||
5
ast.h
5
ast.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011, Intel Corporation
|
||||
Copyright (c) 2011-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -84,8 +84,7 @@ class AST {
|
||||
public:
|
||||
/** Add the AST for a function described by the given declaration
|
||||
information and source code. */
|
||||
void AddFunction(Symbol *sym, const std::vector<Symbol *> &args,
|
||||
Stmt *code);
|
||||
void AddFunction(Symbol *sym, Stmt *code);
|
||||
|
||||
/** Generate LLVM IR for all of the functions into the current
|
||||
module. */
|
||||
|
||||
409
decl.cpp
409
decl.cpp
@@ -33,7 +33,7 @@
|
||||
|
||||
/** @file decl.cpp
|
||||
@brief Implementations of classes related to turning declarations into
|
||||
symbols and types.
|
||||
symbol names and types.
|
||||
*/
|
||||
|
||||
#include "decl.h"
|
||||
@@ -218,50 +218,44 @@ Declarator::Declarator(DeclaratorKind dk, SourcePos p)
|
||||
: pos(p), kind(dk) {
|
||||
child = NULL;
|
||||
typeQualifiers = 0;
|
||||
storageClass = SC_NONE;
|
||||
arraySize = -1;
|
||||
sym = NULL;
|
||||
type = NULL;
|
||||
initExpr = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Declarator::InitFromDeclSpecs(DeclSpecs *ds) {
|
||||
const Type *t = GetType(ds);
|
||||
if (t == NULL) {
|
||||
const Type *baseType = ds->GetBaseType(pos);
|
||||
InitFromType(baseType, ds);
|
||||
|
||||
if (type == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Symbol *sym = GetSymbol();
|
||||
if (sym != NULL) {
|
||||
sym->type = t;
|
||||
sym->storageClass = ds->storageClass;
|
||||
storageClass = ds->storageClass;
|
||||
|
||||
if (ds->declSpecList.size() > 0 &&
|
||||
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
|
||||
Declarator::Print(int indent) const {
|
||||
printf("%*cdeclarator: [", indent, ' ');
|
||||
pos.Print();
|
||||
|
||||
lPrintTypeQualifiers(typeQualifiers);
|
||||
Symbol *sym = GetSymbol();
|
||||
if (sym != NULL)
|
||||
printf("%s", sym->name.c_str());
|
||||
printf("%s ", lGetStorageClassName(storageClass));
|
||||
if (name.size() > 0)
|
||||
printf("%s", name.c_str());
|
||||
else
|
||||
printf("(null symbol)");
|
||||
printf("(unnamed)");
|
||||
|
||||
printf(", array size = %d", arraySize);
|
||||
|
||||
@@ -295,55 +289,8 @@ Declarator::Print(int indent) const {
|
||||
}
|
||||
|
||||
|
||||
Symbol *
|
||||
Declarator::GetFunctionInfo(DeclSpecs *ds, std::vector<Symbol *> *funArgs) {
|
||||
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 {
|
||||
void
|
||||
Declarator::InitFromType(const Type *baseType, DeclSpecs *ds) {
|
||||
bool hasUniformQual = ((typeQualifiers & TYPEQUAL_UNIFORM) != 0);
|
||||
bool hasVaryingQual = ((typeQualifiers & TYPEQUAL_VARYING) != 0);
|
||||
bool isTask = ((typeQualifiers & TYPEQUAL_TASK) != 0);
|
||||
@@ -352,12 +299,16 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
|
||||
|
||||
if (hasUniformQual && hasVaryingQual) {
|
||||
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.");
|
||||
if (kind != DK_FUNCTION && isExported)
|
||||
return;
|
||||
}
|
||||
if (kind != DK_FUNCTION && isExported) {
|
||||
Error(pos, "\"export\" qualifier illegal in variable declaration.");
|
||||
return;
|
||||
}
|
||||
|
||||
Variability variability(Variability::Unbound);
|
||||
if (hasUniformQual)
|
||||
@@ -365,66 +316,76 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
|
||||
else if (hasVaryingQual)
|
||||
variability = Variability::Varying;
|
||||
|
||||
const Type *type = base;
|
||||
switch (kind) {
|
||||
case DK_BASE:
|
||||
if (kind == DK_BASE) {
|
||||
// All of the type qualifiers should be in the DeclSpecs for the
|
||||
// base declarator
|
||||
Assert(typeQualifiers == 0);
|
||||
Assert(child == NULL);
|
||||
return type;
|
||||
|
||||
case DK_POINTER:
|
||||
type = baseType;
|
||||
}
|
||||
else if (kind == DK_POINTER) {
|
||||
/* 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'll want to set this based on a type qualifier here. */
|
||||
type = new PointerType(type, variability, isConst, type->IsSOAType());
|
||||
if (child != NULL)
|
||||
return child->GetType(type, ds);
|
||||
const Type *ptrType = new PointerType(baseType, variability, isConst,
|
||||
baseType->IsSOAType());
|
||||
if (child != NULL) {
|
||||
child->InitFromType(ptrType, ds);
|
||||
type = child->type;
|
||||
name = child->name;
|
||||
}
|
||||
else
|
||||
return type;
|
||||
break;
|
||||
|
||||
case DK_REFERENCE:
|
||||
if (hasUniformQual)
|
||||
type = ptrType;
|
||||
}
|
||||
else if (kind == DK_REFERENCE) {
|
||||
if (hasUniformQual) {
|
||||
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.");
|
||||
if (isConst)
|
||||
return;
|
||||
}
|
||||
if (isConst) {
|
||||
Error(pos, "\"const\" qualifier is to illegal apply to references.");
|
||||
|
||||
return;
|
||||
}
|
||||
// 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.");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
type = new ReferenceType(type);
|
||||
if (child != NULL)
|
||||
return child->GetType(type, ds);
|
||||
const Type *refType = new ReferenceType(baseType);
|
||||
if (child != NULL) {
|
||||
child->InitFromType(refType, ds);
|
||||
type = child->type;
|
||||
name = child->name;
|
||||
}
|
||||
else
|
||||
return type;
|
||||
break;
|
||||
|
||||
case DK_ARRAY:
|
||||
if (Type::Equal(type, AtomicType::Void)) {
|
||||
type = refType;
|
||||
}
|
||||
else if (kind == DK_ARRAY) {
|
||||
if (Type::Equal(baseType, AtomicType::Void)) {
|
||||
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.",
|
||||
type->GetString().c_str());
|
||||
return NULL;
|
||||
baseType->GetString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
type = new ArrayType(type, arraySize);
|
||||
if (child)
|
||||
return child->GetType(type, ds);
|
||||
const Type *arrayType = new ArrayType(baseType, arraySize);
|
||||
if (child != NULL) {
|
||||
child->InitFromType(arrayType, ds);
|
||||
type = child->type;
|
||||
name = child->name;
|
||||
}
|
||||
else
|
||||
return type;
|
||||
break;
|
||||
|
||||
case DK_FUNCTION: {
|
||||
type = arrayType;
|
||||
}
|
||||
else if (kind == DK_FUNCTION) {
|
||||
std::vector<const Type *> args;
|
||||
std::vector<std::string> argNames;
|
||||
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) {
|
||||
Declaration *d = functionParams[i];
|
||||
|
||||
Symbol *sym = GetSymbolForFunctionParameter(i);
|
||||
|
||||
if (d->declSpecs->storageClass != SC_NONE)
|
||||
Error(sym->pos, "Storage class \"%s\" is illegal in "
|
||||
"function parameter declaration for parameter \"%s\".",
|
||||
lGetStorageClassName(d->declSpecs->storageClass),
|
||||
sym->name.c_str());
|
||||
if (Type::Equal(sym->type, AtomicType::Void)) {
|
||||
Error(sym->pos, "Parameter with type \"void\" illegal in function "
|
||||
"parameter list.");
|
||||
sym->type = NULL;
|
||||
if (d == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
continue;
|
||||
}
|
||||
if (d->declarators.size() == 0) {
|
||||
// function declaration like foo(float), w/o a name for the
|
||||
// parameter; wire up a placeholder Declarator for it
|
||||
d->declarators.push_back(new Declarator(DK_BASE, pos));
|
||||
d->declarators[0]->InitFromDeclSpecs(d->declSpecs);
|
||||
}
|
||||
|
||||
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) {
|
||||
// As in C, arrays are passed to functions as pointers to
|
||||
// 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
|
||||
// in the function, but it's not clear that this is a
|
||||
// significant problem.)
|
||||
if (at->GetElementType() == NULL) {
|
||||
const Type *targetType = at->GetElementType();
|
||||
if (targetType == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
const Type *targetType = at->GetElementType();
|
||||
targetType =
|
||||
targetType->ResolveUnboundVariability(Variability::Varying);
|
||||
sym->type = PointerType::GetUniform(targetType);
|
||||
decl->type = PointerType::GetUniform(targetType);
|
||||
|
||||
// Make sure there are no unsized arrays (other than the
|
||||
// first dimension) in function parameter lists.
|
||||
at = dynamic_cast<const ArrayType *>(at->GetElementType());
|
||||
at = dynamic_cast<const ArrayType *>(targetType);
|
||||
while (at != NULL) {
|
||||
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 "
|
||||
"function parameter lists.");
|
||||
at = dynamic_cast<const ArrayType *>(at->GetElementType());
|
||||
}
|
||||
}
|
||||
|
||||
args.push_back(sym->type);
|
||||
argNames.push_back(sym->name);
|
||||
argPos.push_back(sym->pos);
|
||||
args.push_back(decl->type);
|
||||
argNames.push_back(decl->name);
|
||||
argPos.push_back(decl->pos);
|
||||
|
||||
Expr *init = NULL;
|
||||
if (d->declarators.size()) {
|
||||
// Try to find an initializer expression.
|
||||
Declarator *decl = d->declarators[0];
|
||||
while (decl != NULL) {
|
||||
// Try to find an initializer expression.
|
||||
while (decl != NULL) {
|
||||
if (decl->initExpr != NULL) {
|
||||
decl->initExpr = TypeCheck(decl->initExpr);
|
||||
decl->initExpr = Optimize(decl->initExpr);
|
||||
if (decl->initExpr != NULL) {
|
||||
decl->initExpr = TypeCheck(decl->initExpr);
|
||||
decl->initExpr = Optimize(decl->initExpr);
|
||||
if (decl->initExpr != NULL) {
|
||||
init = dynamic_cast<ConstExpr *>(decl->initExpr);
|
||||
if (init == NULL)
|
||||
init = dynamic_cast<NullPointerExpr *>(decl->initExpr);
|
||||
if (init == NULL)
|
||||
Error(decl->initExpr->pos, "Default value for parameter "
|
||||
"\"%s\" must be a compile-time constant.",
|
||||
sym->name.c_str());
|
||||
}
|
||||
break;
|
||||
init = dynamic_cast<ConstExpr *>(decl->initExpr);
|
||||
if (init == NULL)
|
||||
init = dynamic_cast<NullPointerExpr *>(decl->initExpr);
|
||||
if (init == NULL)
|
||||
Error(decl->initExpr->pos, "Default value for parameter "
|
||||
"\"%s\" must be a compile-time constant.",
|
||||
decl->name.c_str());
|
||||
}
|
||||
else
|
||||
decl = decl->child;
|
||||
break;
|
||||
}
|
||||
else
|
||||
decl = decl->child;
|
||||
}
|
||||
argDefaults.push_back(init);
|
||||
}
|
||||
|
||||
const Type *returnType = type;
|
||||
const Type *returnType = baseType;
|
||||
if (returnType == NULL) {
|
||||
Error(pos, "No return type provided in function declaration.");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dynamic_cast<const FunctionType *>(returnType) != NULL) {
|
||||
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 isExported = ds && ((ds->typeQualifiers & TYPEQUAL_EXPORT) != 0);
|
||||
bool isTask = ds && ((ds->typeQualifiers & TYPEQUAL_TASK) != 0);
|
||||
@@ -529,28 +507,27 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
|
||||
if (isExported && isTask) {
|
||||
Error(pos, "Function can't have both \"task\" and \"export\" "
|
||||
"qualifiers");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
if (isExternC && isTask) {
|
||||
Error(pos, "Function can't have both \"extern \"C\"\" and \"task\" "
|
||||
"qualifiers");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
if (isExternC && isExported) {
|
||||
Error(pos, "Function can't have both \"extern \"C\"\" and \"export\" "
|
||||
"qualifiers");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (child == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
const FunctionType *functionType =
|
||||
new FunctionType(returnType, args, argNames, argDefaults,
|
||||
argPos, isTask, isExported, isExternC);
|
||||
functionType = functionType->ResolveUnboundVariability(Variability::Varying);
|
||||
|
||||
// handle any explicit __declspecs on the function
|
||||
if (ds != NULL) {
|
||||
@@ -572,60 +549,12 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const {
|
||||
}
|
||||
}
|
||||
|
||||
return child->GetType(functionType, ds);
|
||||
}
|
||||
default:
|
||||
FATAL("Unexpected decl kind");
|
||||
return NULL;
|
||||
child->InitFromType(functionType, ds);
|
||||
type = child->type;
|
||||
name = child->name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -655,27 +584,23 @@ Declaration::GetVariableDeclarations() const {
|
||||
|
||||
for (unsigned int i = 0; i < declarators.size(); ++i) {
|
||||
Declarator *decl = declarators[i];
|
||||
if (decl == NULL) {
|
||||
if (decl == NULL || decl->type == NULL) {
|
||||
// Ignore earlier errors
|
||||
Assert(m->errorCount > 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
Symbol *sym = decl->GetSymbol();
|
||||
if (sym == NULL || sym->type == NULL) {
|
||||
// Ignore errors
|
||||
Assert(m->errorCount > 0);
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
if (Type::Equal(decl->type, AtomicType::Void))
|
||||
Error(decl->pos, "\"void\" type variable illegal in declaration.");
|
||||
else if (dynamic_cast<const FunctionType *>(decl->type) == NULL) {
|
||||
decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
|
||||
Symbol *sym = new Symbol(decl->name, decl->pos, decl->type,
|
||||
decl->storageClass);
|
||||
m->symbolTable->AddVariable(sym);
|
||||
vars.push_back(VariableDeclaration(sym, decl->initExpr));
|
||||
}
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
@@ -686,25 +611,20 @@ Declaration::DeclareFunctions() {
|
||||
|
||||
for (unsigned int i = 0; i < declarators.size(); ++i) {
|
||||
Declarator *decl = declarators[i];
|
||||
if (decl == NULL) {
|
||||
if (decl == NULL || decl->type == NULL) {
|
||||
// Ignore earlier errors
|
||||
Assert(m->errorCount > 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
Symbol *sym = decl->GetSymbol();
|
||||
if (sym == NULL || sym->type == NULL) {
|
||||
// Ignore errors
|
||||
Assert(m->errorCount > 0);
|
||||
continue;
|
||||
}
|
||||
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
|
||||
|
||||
if (dynamic_cast<const FunctionType *>(sym->type) == NULL)
|
||||
const FunctionType *ftype =
|
||||
dynamic_cast<const FunctionType *>(decl->type);
|
||||
if (ftype == NULL)
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
@@ -748,21 +669,19 @@ GetStructTypesNamesPositions(const std::vector<StructDeclaration *> &sd,
|
||||
Declarator *d = (*sd[i]->declarators)[j];
|
||||
d->InitFromDeclSpecs(&ds);
|
||||
|
||||
Symbol *sym = d->GetSymbol();
|
||||
|
||||
if (Type::Equal(sym->type, AtomicType::Void))
|
||||
if (Type::Equal(d->type, AtomicType::Void))
|
||||
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 "
|
||||
"previously-declared member.", sym->name.c_str());
|
||||
"previously-declared member.", d->name.c_str());
|
||||
else
|
||||
seenNames.insert(sym->name);
|
||||
seenNames.insert(d->name);
|
||||
|
||||
elementNames->push_back(sym->name);
|
||||
elementPositions->push_back(sym->pos);
|
||||
elementNames->push_back(d->name);
|
||||
elementPositions->push_back(d->pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
45
decl.h
45
decl.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2011, Intel Corporation
|
||||
Copyright (c) 2010-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
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'
|
||||
qualifiers, and that it's basic type is 'int'. Then for each variable
|
||||
declaration, the Declaraiton class holds an instance of a Declarator,
|
||||
which in turn records the per-variable information like the symbol
|
||||
name, array size (if any), initializer expression, etc.
|
||||
which in turn records the per-variable information like the name, array
|
||||
size (if any), initializer expression, etc.
|
||||
*/
|
||||
|
||||
#ifndef ISPC_DECL_H
|
||||
@@ -61,15 +61,6 @@ struct VariableDeclaration;
|
||||
class Declaration;
|
||||
class Declarator;
|
||||
|
||||
enum StorageClass {
|
||||
SC_NONE,
|
||||
SC_EXTERN,
|
||||
SC_STATIC,
|
||||
SC_TYPEDEF,
|
||||
SC_EXTERN_C
|
||||
};
|
||||
|
||||
|
||||
/* Multiple qualifiers can be provided with types in declarations;
|
||||
therefore, they are set up so that they can be ANDed together into an
|
||||
int. */
|
||||
@@ -141,25 +132,11 @@ public:
|
||||
Declarator(DeclaratorKind dk, SourcePos p);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Get the actual type of the combination of Declarator and the given
|
||||
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 InitFromType(const Type *base, DeclSpecs *ds);
|
||||
|
||||
void Print(int indent) const;
|
||||
|
||||
@@ -180,18 +157,24 @@ public:
|
||||
/** Type qualifiers provided with the declarator. */
|
||||
int typeQualifiers;
|
||||
|
||||
StorageClass storageClass;
|
||||
|
||||
/** For array declarators, this gives the declared size of the array.
|
||||
Unsized arrays have arraySize == 0. */
|
||||
int arraySize;
|
||||
|
||||
/** Symbol associated with the declarator. */
|
||||
Symbol *sym;
|
||||
/** Name associated with the declarator. */
|
||||
std::string name;
|
||||
|
||||
/** Initialization expression for the variable. May be NULL. */
|
||||
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
|
||||
funciton's parameters. */
|
||||
function's parameters. */
|
||||
std::vector<Declaration *> functionParams;
|
||||
};
|
||||
|
||||
|
||||
30
func.cpp
30
func.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011, Intel Corporation
|
||||
Copyright (c) 2011-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -66,9 +66,8 @@
|
||||
#include <llvm/Support/ToolOutputFile.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;
|
||||
args = a;
|
||||
code = c;
|
||||
|
||||
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);
|
||||
Assert(type != NULL);
|
||||
|
||||
for (unsigned int i = 0; i < args.size(); ++i)
|
||||
if (dynamic_cast<const ReferenceType *>(args[i]->type) == NULL)
|
||||
args[i]->parentFunction = this;
|
||||
for (int i = 0; i < type->GetNumParameters(); ++i) {
|
||||
const char *paramName = type->GetParameterName(i).c_str();
|
||||
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) {
|
||||
threadIndexSym = m->symbolTable->LookupVariable("threadIndex");
|
||||
@@ -145,7 +152,8 @@ Function::GetType() const {
|
||||
'mem2reg' pass will in turn promote to SSA registers..
|
||||
*/
|
||||
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) {
|
||||
// We expect the argument structure to come in as a poitner to a
|
||||
// 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);
|
||||
Symbol *sym = args[i];
|
||||
|
||||
if (sym == NULL)
|
||||
// anonymous parameter, so don't worry about it
|
||||
return;
|
||||
|
||||
// allocate space to copy the parameter in to
|
||||
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();
|
||||
for (unsigned int i = 0; i < args.size(); ++i, ++argIter) {
|
||||
Symbol *sym = args[i];
|
||||
if (sym == NULL)
|
||||
// anonymous function parameter
|
||||
continue;
|
||||
|
||||
argIter->setName(sym->name.c_str());
|
||||
|
||||
// Allocate stack storage for the parameter and emit code
|
||||
|
||||
4
func.h
4
func.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2011, Intel Corporation
|
||||
Copyright (c) 2011-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
class Function {
|
||||
public:
|
||||
Function(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code);
|
||||
Function(Symbol *sym, Stmt *code);
|
||||
|
||||
const Type *GetReturnType() const;
|
||||
const FunctionType *GetType() const;
|
||||
|
||||
9
ispc.h
9
ispc.h
@@ -116,6 +116,15 @@ class SymbolTable;
|
||||
class Type;
|
||||
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.
|
||||
|
||||
This class represents a range of characters in a source file
|
||||
|
||||
172
module.cpp
172
module.cpp
@@ -231,64 +231,65 @@ Module::CompileFile() {
|
||||
|
||||
|
||||
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
|
||||
// the given type.
|
||||
symbolTable->AddType(sym->name.c_str(), sym->type, sym->pos);
|
||||
symbolTable->AddType(name.c_str(), type, pos);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
// here if so.
|
||||
if (sym == NULL || sym->type == NULL) {
|
||||
// But if these are NULL and there haven't been any previous
|
||||
// errors, something surprising is going on
|
||||
if (name == "" || type == NULL) {
|
||||
Assert(errorCount > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (symbolTable->LookupFunction(sym->name.c_str())) {
|
||||
Error(sym->pos, "Global variable \"%s\" shadows previously-declared "
|
||||
"function.", sym->name.c_str());
|
||||
if (symbolTable->LookupFunction(name.c_str())) {
|
||||
Error(pos, "Global variable \"%s\" shadows previously-declared "
|
||||
"function.", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (sym->storageClass == SC_EXTERN_C) {
|
||||
Error(sym->pos, "extern \"C\" qualifier can only be used for "
|
||||
if (storageClass == SC_EXTERN_C) {
|
||||
Error(pos, "extern \"C\" qualifier can only be used for "
|
||||
"functions.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Type::Equal(sym->type, AtomicType::Void)) {
|
||||
Error(sym->pos, "\"void\" type global variable is illegal.");
|
||||
if (Type::Equal(type, AtomicType::Void)) {
|
||||
Error(pos, "\"void\" type global variable is illegal.");
|
||||
return;
|
||||
}
|
||||
|
||||
sym->type = ArrayType::SizeUnsizedArrays(sym->type, initExpr);
|
||||
if (sym->type == NULL)
|
||||
type = ArrayType::SizeUnsizedArrays(type, initExpr);
|
||||
if (type == NULL)
|
||||
return;
|
||||
|
||||
const ArrayType *at = dynamic_cast<const ArrayType *>(sym->type);
|
||||
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
|
||||
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 "
|
||||
"expression.");
|
||||
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)
|
||||
return;
|
||||
|
||||
// See if we have an initializer expression for the global. If so,
|
||||
// make sure it's a compile-time constant!
|
||||
llvm::Constant *llvmInitializer = NULL;
|
||||
if (sym->storageClass == SC_EXTERN || sym->storageClass == SC_EXTERN_C) {
|
||||
ConstExpr *constValue = NULL;
|
||||
if (storageClass == SC_EXTERN || storageClass == SC_EXTERN_C) {
|
||||
if (initExpr != NULL)
|
||||
Error(sym->pos, "Initializer can't be provided with \"extern\" "
|
||||
"global variable \"%s\".", sym->name.c_str());
|
||||
Error(pos, "Initializer can't be provided with \"extern\" "
|
||||
"global variable \"%s\".", name.c_str());
|
||||
}
|
||||
else {
|
||||
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
|
||||
// convert themselves anyway.)
|
||||
if (dynamic_cast<ExprList *>(initExpr) == NULL)
|
||||
initExpr = TypeConvertExpr(initExpr, sym->type, "initializer");
|
||||
initExpr = TypeConvertExpr(initExpr, type, "initializer");
|
||||
|
||||
if (initExpr != NULL) {
|
||||
initExpr = Optimize(initExpr);
|
||||
// Fingers crossed, now let's see if we've got a
|
||||
// constant value..
|
||||
llvmInitializer = initExpr->GetConstant(sym->type);
|
||||
llvmInitializer = initExpr->GetConstant(type);
|
||||
|
||||
if (llvmInitializer != NULL) {
|
||||
if (sym->type->IsConstType())
|
||||
if (type->IsConstType())
|
||||
// Try to get a ConstExpr associated with
|
||||
// the symbol. This dynamic_cast can
|
||||
// validly fail, for example for types like
|
||||
// StructTypes where a ConstExpr can't
|
||||
// represent their values.
|
||||
sym->constValue =
|
||||
dynamic_cast<ConstExpr *>(initExpr);
|
||||
constValue = dynamic_cast<ConstExpr *>(initExpr);
|
||||
}
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
Symbol *stSym = symbolTable->LookupVariable(sym->name.c_str());
|
||||
Symbol *sym = symbolTable->LookupVariable(name.c_str());
|
||||
llvm::GlobalVariable *oldGV = NULL;
|
||||
if (stSym != NULL) {
|
||||
if (sym != NULL) {
|
||||
// We've already seen either a declaration or a definition of this
|
||||
// global.
|
||||
|
||||
// If the type doesn't match with the previous one, issue an error.
|
||||
if (!Type::Equal(sym->type, stSym->type)) {
|
||||
Error(sym->pos, "Definition of variable \"%s\" conflicts with "
|
||||
"definition at %s:%d.", sym->name.c_str(),
|
||||
stSym->pos.name, stSym->pos.first_line);
|
||||
if (!Type::Equal(sym->type, type) ||
|
||||
(sym->storageClass != SC_EXTERN &&
|
||||
sym->storageClass != SC_EXTERN_C &&
|
||||
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;
|
||||
}
|
||||
|
||||
llvm::GlobalVariable *gv =
|
||||
llvm::dyn_cast<llvm::GlobalVariable>(stSym->storagePtr);
|
||||
llvm::dyn_cast<llvm::GlobalVariable>(sym->storagePtr);
|
||||
Assert(gv != NULL);
|
||||
|
||||
// And issue an error if this is a redefinition of a variable
|
||||
if (gv->hasInitializer() &&
|
||||
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(),
|
||||
stSym->pos.name, stSym->pos.first_line);
|
||||
sym->pos.name, sym->pos.first_line);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -361,17 +364,12 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
// of a previously-declared global. First, save the pointer to the
|
||||
// previous llvm::GlobalVariable
|
||||
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);
|
||||
}
|
||||
sym->constValue = constValue;
|
||||
|
||||
llvm::GlobalValue::LinkageTypes linkage =
|
||||
(sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage :
|
||||
@@ -393,10 +391,10 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
}
|
||||
|
||||
if (diBuilder) {
|
||||
llvm::DIFile file = sym->pos.GetDIFile();
|
||||
diBuilder->createGlobalVariable(sym->name,
|
||||
llvm::DIFile file = pos.GetDIFile();
|
||||
diBuilder->createGlobalVariable(name,
|
||||
file,
|
||||
sym->pos.first_line,
|
||||
pos.first_line,
|
||||
sym->type->GetDIType(file),
|
||||
(sym->storageClass == SC_STATIC),
|
||||
sym->storagePtr);
|
||||
@@ -487,22 +485,23 @@ lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
|
||||
false if any errors were encountered.
|
||||
*/
|
||||
void
|
||||
Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
const FunctionType *functionType =
|
||||
dynamic_cast<const FunctionType *>(funSym->type);
|
||||
Module::AddFunctionDeclaration(const std::string &name,
|
||||
const FunctionType *functionType,
|
||||
StorageClass storageClass, bool isInline,
|
||||
SourcePos pos) {
|
||||
Assert(functionType != NULL);
|
||||
|
||||
// If a global variable with the same name has already been declared
|
||||
// issue an error.
|
||||
if (symbolTable->LookupVariable(funSym->name.c_str()) != NULL) {
|
||||
Error(funSym->pos, "Function \"%s\" shadows previously-declared global variable. "
|
||||
if (symbolTable->LookupVariable(name.c_str()) != NULL) {
|
||||
Error(pos, "Function \"%s\" shadows previously-declared global variable. "
|
||||
"Ignoring this definition.",
|
||||
funSym->name.c_str());
|
||||
name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Symbol *> overloadFuncs;
|
||||
symbolTable->LookupFunction(funSym->name.c_str(), &overloadFuncs);
|
||||
symbolTable->LookupFunction(name.c_str(), &overloadFuncs);
|
||||
if (overloadFuncs.size() > 0) {
|
||||
for (unsigned int i = 0; i < overloadFuncs.size(); ++i) {
|
||||
Symbol *overloadFunc = overloadFuncs[i];
|
||||
@@ -528,7 +527,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
if (i == functionType->GetNumParameters()) {
|
||||
std::string thisRetType = functionType->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 "
|
||||
"previous declaration at %s:%d returns \"%s\".",
|
||||
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
|
||||
// 'task' qualifier with the function
|
||||
if (functionType->isTask) {
|
||||
Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern "
|
||||
"function \"%s\". Ignoring this function.", funSym->name.c_str());
|
||||
Error(pos, "\"task\" qualifier is illegal with C-linkage extern "
|
||||
"function \"%s\". Ignoring this function.", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Symbol *> funcs;
|
||||
symbolTable->LookupFunction(funSym->name.c_str(), &funcs);
|
||||
symbolTable->LookupFunction(name.c_str(), &funcs);
|
||||
if (funcs.size() > 0) {
|
||||
if (funcs.size() > 1) {
|
||||
// Multiple functions with this name have already been declared;
|
||||
// can't overload here
|
||||
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; "
|
||||
Error(pos, "Can't overload extern \"C\" function \"%s\"; "
|
||||
"%d functions with the same name have already been declared.",
|
||||
funSym->name.c_str(), (int)funcs.size());
|
||||
name.c_str(), (int)funcs.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// One function with the same name has been declared; see if it
|
||||
// has the same type as this one, in which case it's ok.
|
||||
if (Type::Equal(funcs[0]->type, funSym->type))
|
||||
if (Type::Equal(funcs[0]->type, functionType))
|
||||
return;
|
||||
else {
|
||||
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".",
|
||||
funSym->name.c_str());
|
||||
Error(pos, "Can't overload extern \"C\" function \"%s\".",
|
||||
name.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the LLVM FunctionType
|
||||
bool includeMask = (funSym->storageClass != SC_EXTERN_C);
|
||||
bool includeMask = (storageClass != SC_EXTERN_C);
|
||||
LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType =
|
||||
functionType->LLVMFunctionType(g->ctx, includeMask);
|
||||
if (llvmFunctionType == NULL)
|
||||
return;
|
||||
|
||||
// And create the llvm::Function
|
||||
llvm::GlobalValue::LinkageTypes linkage = (funSym->storageClass == SC_STATIC ||
|
||||
llvm::GlobalValue::LinkageTypes linkage = (storageClass == SC_STATIC ||
|
||||
isInline) ?
|
||||
llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
|
||||
std::string functionName;
|
||||
if (funSym->storageClass == SC_EXTERN_C)
|
||||
functionName = funSym->name;
|
||||
else {
|
||||
functionName = funSym->MangledName();
|
||||
|
||||
std::string functionName = name;
|
||||
if (storageClass != SC_EXTERN_C) {
|
||||
functionName += functionType->Mangle();
|
||||
if (g->mangleFunctionsWithTarget)
|
||||
functionName += g->target.GetISAString();
|
||||
}
|
||||
@@ -597,7 +595,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
|
||||
// Set function attributes: we never throw exceptions
|
||||
function->setDoesNotThrow(true);
|
||||
if (!(funSym->storageClass == SC_EXTERN_C) &&
|
||||
if (storageClass != SC_EXTERN_C &&
|
||||
!g->generateDebuggingSymbols &&
|
||||
isInline)
|
||||
function->addFnAttr(llvm::Attribute::AlwaysInline);
|
||||
@@ -609,15 +607,15 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
// 'export'ed.
|
||||
if (functionType->isExported &&
|
||||
lRecursiveCheckValidParamType(functionType->GetReturnType()))
|
||||
Error(funSym->pos, "Illegal to return a \"varying\" type from exported "
|
||||
"function \"%s\"", funSym->name.c_str());
|
||||
Error(pos, "Illegal to return a \"varying\" type from exported "
|
||||
"function \"%s\"", name.c_str());
|
||||
|
||||
if (functionType->isTask &&
|
||||
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)
|
||||
lCheckForStructParameters(functionType, funSym->pos);
|
||||
lCheckForStructParameters(functionType, pos);
|
||||
|
||||
// Loop over all of the arguments; process default values if present
|
||||
// and do other checks and parameter attribute setting.
|
||||
@@ -675,19 +673,33 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
function->eraseFromParent();
|
||||
function = module->getFunction(functionName);
|
||||
}
|
||||
funSym->function = function;
|
||||
|
||||
// Finally, we know all is good and we can add the function to the
|
||||
// symbol table
|
||||
Symbol *funSym = new Symbol(name, pos, functionType, storageClass);
|
||||
funSym->function = function;
|
||||
bool ok = symbolTable->AddFunction(funSym);
|
||||
Assert(ok);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Module::AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args,
|
||||
Module::AddFunctionDefinition(const std::string &name, const FunctionType *type,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
17
module.h
17
module.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2011, Intel Corporation
|
||||
Copyright (c) 2010-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -59,21 +59,26 @@ public:
|
||||
int CompileFile();
|
||||
|
||||
/** 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
|
||||
module. If non-NULL, initExpr gives the initiailizer expression
|
||||
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
|
||||
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
|
||||
provided statements to the module. */
|
||||
void AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args,
|
||||
Stmt *code);
|
||||
void AddFunctionDefinition(const std::string &name,
|
||||
const FunctionType *ftype, Stmt *code);
|
||||
|
||||
/** After a source file has been compiled, output can be generated in a
|
||||
number of different formats. */
|
||||
|
||||
64
parse.yy
64
parse.yy
@@ -631,7 +631,9 @@ declaration_statement
|
||||
if ($1->declarators[i] == NULL)
|
||||
Assert(m->errorCount > 0);
|
||||
else
|
||||
m->AddTypeDef($1->declarators[i]->GetSymbol());
|
||||
m->AddTypeDef($1->declarators[i]->name,
|
||||
$1->declarators[i]->type,
|
||||
$1->declarators[i]->pos);
|
||||
}
|
||||
$$ = NULL;
|
||||
}
|
||||
@@ -1174,7 +1176,7 @@ direct_declarator
|
||||
: TOKEN_IDENTIFIER
|
||||
{
|
||||
Declarator *d = new Declarator(DK_BASE, @1);
|
||||
d->sym = new Symbol(yytext, @1);
|
||||
d->name = yytext;
|
||||
$$ = d;
|
||||
}
|
||||
| '(' declarator ')'
|
||||
@@ -1349,8 +1351,10 @@ type_name
|
||||
{
|
||||
if ($1 == NULL || $2 == NULL)
|
||||
$$ = NULL;
|
||||
else
|
||||
$$ = $2->GetType($1, NULL);
|
||||
else {
|
||||
$2->InitFromType($1, NULL);
|
||||
$$ = $2->type;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1854,11 +1858,14 @@ function_definition
|
||||
}
|
||||
compound_statement
|
||||
{
|
||||
std::vector<Symbol *> args;
|
||||
if ($2 != NULL) {
|
||||
Symbol *sym = $2->GetFunctionInfo($1, &args);
|
||||
if (sym != NULL)
|
||||
m->AddFunctionDefinition(sym, args, $4);
|
||||
$2->InitFromDeclSpecs($1);
|
||||
const FunctionType *funcType =
|
||||
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();
|
||||
}
|
||||
@@ -1968,35 +1975,27 @@ lAddDeclaration(DeclSpecs *ds, Declarator *decl) {
|
||||
// Error happened earlier during parsing
|
||||
return;
|
||||
|
||||
decl->InitFromDeclSpecs(ds);
|
||||
if (ds->storageClass == SC_TYPEDEF)
|
||||
m->AddTypeDef(decl->GetSymbol());
|
||||
m->AddTypeDef(decl->name, decl->type, decl->pos);
|
||||
else {
|
||||
const Type *t = decl->GetType(ds);
|
||||
if (t == NULL) {
|
||||
if (decl->type == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Symbol *sym = decl->GetSymbol();
|
||||
if (sym == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const FunctionType *ft = dynamic_cast<const FunctionType *>(t);
|
||||
decl->type = decl->type->ResolveUnboundVariability(Variability::Varying);
|
||||
|
||||
const FunctionType *ft = dynamic_cast<const FunctionType *>(decl->type);
|
||||
if (ft != NULL) {
|
||||
sym->type = ft;
|
||||
sym->storageClass = ds->storageClass;
|
||||
bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE);
|
||||
m->AddFunctionDeclaration(sym, isInline);
|
||||
m->AddFunctionDeclaration(decl->name, ft, ds->storageClass,
|
||||
isInline, decl->pos);
|
||||
}
|
||||
else {
|
||||
if (sym->type == NULL)
|
||||
Assert(m->errorCount > 0);
|
||||
else
|
||||
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
|
||||
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
|
||||
for (unsigned int i = 0; i < decl->functionParams.size(); ++i) {
|
||||
Declaration *pdecl = decl->functionParams[i];
|
||||
if (pdecl == NULL || pdecl->declarators.size() == 0)
|
||||
// zero size declarators array corresponds to an anonymous
|
||||
// parameter
|
||||
continue;
|
||||
Assert(pdecl->declarators.size() == 1);
|
||||
Symbol *sym = pdecl->declarators[0]->GetSymbol();
|
||||
if (sym == NULL || sym->type == NULL)
|
||||
Assert(pdecl != NULL && pdecl->declarators.size() == 1);
|
||||
Declarator *declarator = pdecl->declarators[0];
|
||||
if (declarator == NULL)
|
||||
Assert(m->errorCount > 0);
|
||||
else {
|
||||
sym->type = sym->type->ResolveUnboundVariability(Variability::Varying);
|
||||
Symbol *sym = new Symbol(declarator->name, declarator->pos,
|
||||
declarator->type, declarator->storageClass);
|
||||
#ifndef NDEBUG
|
||||
bool ok = m->symbolTable->AddVariable(sym);
|
||||
if (ok == false)
|
||||
|
||||
6
sym.cpp
6
sym.cpp
@@ -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
|
||||
|
||||
|
||||
7
sym.h
7
sym.h
@@ -67,13 +67,6 @@ public:
|
||||
Symbol(const std::string &name, SourcePos pos, const Type *t = NULL,
|
||||
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 */
|
||||
std::string name; /*!< Symbol's name */
|
||||
llvm::Value *storagePtr; /*!< For symbols with storage associated with
|
||||
|
||||
15
tests/func-anon-param.ispc
Normal file
15
tests/func-anon-param.ispc
Normal 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;
|
||||
}
|
||||
14
tests/global-decl-define.ispc
Normal file
14
tests/global-decl-define.ispc
Normal 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;
|
||||
}
|
||||
18
tests/ptr-cast-complex.ispc
Normal file
18
tests/ptr-cast-complex.ispc
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user