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
|
// 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
5
ast.h
@@ -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
409
decl.cpp
@@ -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
45
decl.h
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
30
func.cpp
30
func.cpp
@@ -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
4
func.h
@@ -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
9
ispc.h
@@ -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
|
||||||
|
|||||||
172
module.cpp
172
module.cpp
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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.
|
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. */
|
||||||
|
|||||||
64
parse.yy
64
parse.yy
@@ -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)
|
||||||
|
|||||||
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
|
// SymbolTable
|
||||||
|
|
||||||
|
|||||||
7
sym.h
7
sym.h
@@ -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
|
||||||
|
|||||||
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