Significantly reduce the tendrils of DeclSpecs/Declarator/Declaration code
The stuff in decl.h/decl.cpp is messy, largely due to its close mapping to C-style variable declarations. This checkin has updated code throughout all of the declaration statement, variable, and function code that operates on symbols and types directly. Thus, Decl* related stuff is now localized to decl.h/decl.cpp and the parser. Issue #13.
This commit is contained in:
6
ast.cpp
6
ast.cpp
@@ -36,9 +36,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "decl.h"
|
|
||||||
#include "func.h"
|
#include "func.h"
|
||||||
#include "type.h"
|
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@@ -52,8 +50,8 @@ ASTNode::~ASTNode() {
|
|||||||
// AST
|
// AST
|
||||||
|
|
||||||
void
|
void
|
||||||
AST::AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code) {
|
AST::AddFunction(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code) {
|
||||||
functions.push_back(new Function(ds, decl, code));
|
functions.push_back(new Function(sym, args, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
ast.h
3
ast.h
@@ -80,7 +80,8 @@ 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(DeclSpecs *ds, Declarator *decl, Stmt *code);
|
void AddFunction(Symbol *sym, const std::vector<Symbol *> &args,
|
||||||
|
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. */
|
||||||
|
|||||||
69
decl.cpp
69
decl.cpp
@@ -38,10 +38,13 @@
|
|||||||
|
|
||||||
#include "decl.h"
|
#include "decl.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "module.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
|
#include "stmt.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <llvm/Module.h>
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// DeclSpecs
|
// DeclSpecs
|
||||||
@@ -117,6 +120,30 @@ Declarator::Print() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Declarator::GetFunctionInfo(DeclSpecs *ds, Symbol **funSym,
|
||||||
|
std::vector<Symbol *> *funArgs) {
|
||||||
|
// 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.)
|
||||||
|
const FunctionType *type =
|
||||||
|
dynamic_cast<const FunctionType *>(GetType(ds));
|
||||||
|
assert(type != NULL);
|
||||||
|
*funSym = m->symbolTable->LookupFunction(sym->name.c_str(), type);
|
||||||
|
if (*funSym != NULL)
|
||||||
|
// May be NULL due to error earlier in compilation
|
||||||
|
(*funSym)->pos = pos;
|
||||||
|
|
||||||
|
if (functionArgs != NULL) {
|
||||||
|
for (unsigned int i = 0; i < functionArgs->size(); ++i) {
|
||||||
|
Declaration *pdecl = (*functionArgs)[i];
|
||||||
|
assert(pdecl->declarators.size() == 1);
|
||||||
|
funArgs->push_back(pdecl->declarators[0]->sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const Type *
|
static const Type *
|
||||||
lGetType(const Declarator *decl, DeclSpecs *ds,
|
lGetType(const Declarator *decl, DeclSpecs *ds,
|
||||||
std::vector<int>::const_iterator arrayIter) {
|
std::vector<int>::const_iterator arrayIter) {
|
||||||
@@ -292,13 +319,43 @@ Declarator::GetType(DeclSpecs *ds) const {
|
|||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Declaration
|
// Declaration
|
||||||
|
|
||||||
void
|
Declaration::Declaration(DeclSpecs *ds, std::vector<Declarator *> *dlist) {
|
||||||
Declaration::AddSymbols(SymbolTable *st) const {
|
declSpecs = ds;
|
||||||
assert(declSpecs->storageClass != SC_TYPEDEF);
|
if (dlist != NULL)
|
||||||
|
declarators = *dlist;
|
||||||
for (unsigned int i = 0; i < declarators.size(); ++i)
|
for (unsigned int i = 0; i < declarators.size(); ++i)
|
||||||
if (declarators[i])
|
if (declarators[i] != NULL)
|
||||||
st->AddVariable(declarators[i]->sym);
|
declarators[i]->InitFromDeclSpecs(declSpecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Declaration::Declaration(DeclSpecs *ds, Declarator *d) {
|
||||||
|
declSpecs = ds;
|
||||||
|
if (d) {
|
||||||
|
d->InitFromDeclSpecs(ds);
|
||||||
|
declarators.push_back(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<VariableDeclaration>
|
||||||
|
Declaration::GetVariableDeclarations() const {
|
||||||
|
assert(declSpecs->storageClass != SC_TYPEDEF);
|
||||||
|
std::vector<VariableDeclaration> vars;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < declarators.size(); ++i) {
|
||||||
|
if (declarators[i] == NULL)
|
||||||
|
continue;
|
||||||
|
Declarator *decl = declarators[i];
|
||||||
|
if (!decl || decl->isFunction)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m->symbolTable->AddVariable(declarators[i]->sym);
|
||||||
|
|
||||||
|
vars.push_back(VariableDeclaration(declarators[i]->sym,
|
||||||
|
declarators[i]->initExpr));
|
||||||
|
}
|
||||||
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
30
decl.h
30
decl.h
@@ -56,6 +56,11 @@
|
|||||||
|
|
||||||
#include "ispc.h"
|
#include "ispc.h"
|
||||||
|
|
||||||
|
struct VariableDeclaration;
|
||||||
|
|
||||||
|
class Declaration;
|
||||||
|
class Declarator;
|
||||||
|
|
||||||
enum StorageClass {
|
enum StorageClass {
|
||||||
SC_NONE,
|
SC_NONE,
|
||||||
SC_EXTERN,
|
SC_EXTERN,
|
||||||
@@ -137,6 +142,9 @@ public:
|
|||||||
DeclSpecs */
|
DeclSpecs */
|
||||||
const Type *GetType(DeclSpecs *ds) const;
|
const Type *GetType(DeclSpecs *ds) const;
|
||||||
|
|
||||||
|
void GetFunctionInfo(DeclSpecs *ds, Symbol **sym,
|
||||||
|
std::vector<Symbol *> *args);
|
||||||
|
|
||||||
void Print() const;
|
void Print() const;
|
||||||
|
|
||||||
const SourcePos pos;
|
const SourcePos pos;
|
||||||
@@ -157,27 +165,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
class Declaration {
|
class Declaration {
|
||||||
public:
|
public:
|
||||||
Declaration(DeclSpecs *ds, std::vector<Declarator *> *dlist = NULL) {
|
Declaration(DeclSpecs *ds, std::vector<Declarator *> *dlist = NULL);
|
||||||
declSpecs = ds;
|
Declaration(DeclSpecs *ds, Declarator *d);
|
||||||
if (dlist != NULL)
|
|
||||||
declarators = *dlist;
|
|
||||||
for (unsigned int i = 0; i < declarators.size(); ++i)
|
|
||||||
if (declarators[i] != NULL)
|
|
||||||
declarators[i]->InitFromDeclSpecs(declSpecs);
|
|
||||||
}
|
|
||||||
Declaration(DeclSpecs *ds, Declarator *d) {
|
|
||||||
declSpecs = ds;
|
|
||||||
if (d) {
|
|
||||||
d->InitFromDeclSpecs(ds);
|
|
||||||
declarators.push_back(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds the symbols for the variables in the declaration to the symbol
|
|
||||||
table. */
|
|
||||||
void AddSymbols(SymbolTable *st) const;
|
|
||||||
void Print() const;
|
void Print() const;
|
||||||
|
|
||||||
|
std::vector<VariableDeclaration> GetVariableDeclarations() const;
|
||||||
|
|
||||||
DeclSpecs *declSpecs;
|
DeclSpecs *declSpecs;
|
||||||
std::vector<Declarator *> declarators;
|
std::vector<Declarator *> declarators;
|
||||||
};
|
};
|
||||||
|
|||||||
295
func.cpp
295
func.cpp
@@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
#include "func.h"
|
#include "func.h"
|
||||||
#include "ctx.h"
|
#include "ctx.h"
|
||||||
#include "decl.h"
|
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "llvmutil.h"
|
#include "llvmutil.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
@@ -67,7 +66,9 @@
|
|||||||
#include <llvm/Support/ToolOutputFile.h>
|
#include <llvm/Support/ToolOutputFile.h>
|
||||||
#include <llvm/Assembly/PrintModulePass.h>
|
#include <llvm/Assembly/PrintModulePass.h>
|
||||||
|
|
||||||
Function::Function(DeclSpecs *ds, Declarator *decl, Stmt *c) {
|
Function::Function(Symbol *s, const std::vector<Symbol *> &a, Stmt *c) {
|
||||||
|
sym = s;
|
||||||
|
args = a;
|
||||||
code = c;
|
code = c;
|
||||||
|
|
||||||
maskSymbol = m->symbolTable->LookupVariable("__mask");
|
maskSymbol = m->symbolTable->LookupVariable("__mask");
|
||||||
@@ -80,37 +81,17 @@ Function::Function(DeclSpecs *ds, Declarator *decl, Stmt *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (g->debugPrint) {
|
if (g->debugPrint) {
|
||||||
printf("Add Function\n");
|
printf("Add Function %s\n", sym->name.c_str());
|
||||||
ds->Print();
|
|
||||||
printf("\n");
|
|
||||||
decl->Print();
|
|
||||||
printf("\n");
|
|
||||||
code->Print(0);
|
code->Print(0);
|
||||||
printf("\n\n\n");
|
printf("\n\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the symbol for the function from the symbol table. (It should
|
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
|
||||||
// already have been added to the symbol table by AddGlobal() by the
|
|
||||||
// time we get here.)
|
|
||||||
type = dynamic_cast<const FunctionType *>(decl->GetType(ds));
|
|
||||||
assert(type != NULL);
|
assert(type != NULL);
|
||||||
sym = m->symbolTable->LookupFunction(decl->sym->name.c_str(), type);
|
|
||||||
if (sym != NULL)
|
|
||||||
// May be NULL due to error earlier in compilation
|
|
||||||
sym->pos = decl->pos;
|
|
||||||
|
|
||||||
isExported = (ds->storageClass == SC_EXPORT);
|
for (unsigned int i = 0; i < args.size(); ++i)
|
||||||
|
if (dynamic_cast<const ReferenceType *>(args[i]->type) == NULL)
|
||||||
if (decl->functionArgs != NULL) {
|
args[i]->parentFunction = this;
|
||||||
for (unsigned int i = 0; i < decl->functionArgs->size(); ++i) {
|
|
||||||
Declaration *pdecl = (*decl->functionArgs)[i];
|
|
||||||
assert(pdecl->declarators.size() == 1);
|
|
||||||
Symbol *sym = pdecl->declarators[0]->sym;
|
|
||||||
if (dynamic_cast<const ReferenceType *>(sym->type) == NULL)
|
|
||||||
sym->parentFunction = this;
|
|
||||||
args.push_back(sym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type->isTask) {
|
if (type->isTask) {
|
||||||
threadIndexSym = m->symbolTable->LookupVariable("threadIndex");
|
threadIndexSym = m->symbolTable->LookupVariable("threadIndex");
|
||||||
@@ -127,264 +108,18 @@ Function::Function(DeclSpecs *ds, Declarator *decl, Stmt *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Given an arbitrary type, see if it or any of the types contained in it
|
|
||||||
are varying. Returns true if so, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
lRecursiveCheckVarying(const Type *t) {
|
|
||||||
t = t->GetBaseType();
|
|
||||||
if (t->IsVaryingType()) return true;
|
|
||||||
|
|
||||||
const StructType *st = dynamic_cast<const StructType *>(t);
|
|
||||||
if (st) {
|
|
||||||
for (int i = 0; i < st->GetElementCount(); ++i)
|
|
||||||
if (lRecursiveCheckVarying(st->GetElementType(i)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Given a Symbol representing a function parameter, see if it or any
|
|
||||||
contained types are varying. If so, issue an error. (This function
|
|
||||||
should only be called for parameters to 'export'ed functions, where
|
|
||||||
varying parameters is illegal.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
lCheckForVaryingParameter(Symbol *sym) {
|
|
||||||
if (lRecursiveCheckVarying(sym->type)) {
|
|
||||||
const Type *t = sym->type->GetBaseType();
|
|
||||||
if (dynamic_cast<const StructType *>(t))
|
|
||||||
Error(sym->pos, "Struct parameter \"%s\" with varying member(s) is illegal "
|
|
||||||
"in an exported function.",
|
|
||||||
sym->name.c_str());
|
|
||||||
else
|
|
||||||
Error(sym->pos, "Varying parameter \"%s\" is illegal in an exported function.",
|
|
||||||
sym->name.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Given a function type, loop through the function parameters and see if
|
|
||||||
any are StructTypes. If so, issue an error (this seems to be broken
|
|
||||||
currently).
|
|
||||||
|
|
||||||
@todo Fix passing structs from C/C++ to ispc functions.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
|
|
||||||
const std::vector<const Type *> &argTypes = ftype->GetArgumentTypes();
|
|
||||||
for (unsigned int i = 0; i < argTypes.size(); ++i) {
|
|
||||||
const Type *type = argTypes[i];
|
|
||||||
if (dynamic_cast<const StructType *>(type) != NULL) {
|
|
||||||
Error(pos, "Passing structs to/from application functions is currently broken. "
|
|
||||||
"Use a reference or const reference instead for now.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** We've got a declaration for a function to process. This function does
|
|
||||||
all the work of creating the corresponding llvm::Function instance,
|
|
||||||
adding the symbol for the function to the symbol table and doing
|
|
||||||
various sanity checks. This function returns true upon success and
|
|
||||||
false if any errors were encountered.
|
|
||||||
*/
|
|
||||||
Symbol *
|
|
||||||
Function::InitFunctionSymbol(DeclSpecs *ds, Declarator *decl) {
|
|
||||||
// Make sure that we've got what we expect here
|
|
||||||
Symbol *funSym = decl->sym;
|
|
||||||
assert(decl->isFunction);
|
|
||||||
assert(decl->arraySize.size() == 0);
|
|
||||||
|
|
||||||
// So far, so good. Go ahead and set the type of the function symbol
|
|
||||||
funSym->type = decl->GetType(ds);
|
|
||||||
|
|
||||||
// If a global variable with the same name has already been declared
|
|
||||||
// issue an error.
|
|
||||||
if (m->symbolTable->LookupVariable(funSym->name.c_str()) != NULL) {
|
|
||||||
Error(decl->pos, "Function \"%s\" shadows previously-declared global variable. "
|
|
||||||
"Ignoring this definition.",
|
|
||||||
funSym->name.c_str());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds->storageClass == SC_EXTERN_C) {
|
|
||||||
// Make sure the user hasn't supplied both an 'extern "C"' and a
|
|
||||||
// 'task' qualifier with the function
|
|
||||||
if (ds->typeQualifier & TYPEQUAL_TASK) {
|
|
||||||
Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern "
|
|
||||||
"function \"%s\". Ignoring this function.", funSym->name.c_str());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
std::vector<Symbol *> *funcs;
|
|
||||||
funcs = m->symbolTable->LookupFunction(decl->sym->name.c_str());
|
|
||||||
if (funcs != NULL) {
|
|
||||||
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\"; "
|
|
||||||
"%d functions with the same name have already been declared.",
|
|
||||||
funSym->name.c_str(), (int)funcs->size());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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))
|
|
||||||
return (*funcs)[0];
|
|
||||||
else {
|
|
||||||
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".",
|
|
||||||
funSym->name.c_str());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should have gotten a FunctionType back from the GetType() call above.
|
|
||||||
const FunctionType *functionType =
|
|
||||||
dynamic_cast<const FunctionType *>(funSym->type);
|
|
||||||
assert(functionType != NULL);
|
|
||||||
|
|
||||||
// Get the LLVM FunctionType
|
|
||||||
bool includeMask = (ds->storageClass != SC_EXTERN_C);
|
|
||||||
LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType =
|
|
||||||
functionType->LLVMFunctionType(g->ctx, includeMask);
|
|
||||||
if (llvmFunctionType == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// And create the llvm::Function
|
|
||||||
llvm::GlobalValue::LinkageTypes linkage = (ds->storageClass == SC_STATIC ||
|
|
||||||
(ds->typeQualifier & TYPEQUAL_INLINE)) ?
|
|
||||||
llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
|
|
||||||
std::string functionName = ((ds->storageClass == SC_EXTERN_C) ?
|
|
||||||
funSym->name : funSym->MangledName());
|
|
||||||
if (g->mangleFunctionsWithTarget)
|
|
||||||
functionName += g->target.GetISAString();
|
|
||||||
llvm::Function *function =
|
|
||||||
llvm::Function::Create(llvmFunctionType, linkage, functionName.c_str(), m->module);
|
|
||||||
|
|
||||||
// Set function attributes: we never throw exceptions, and want to
|
|
||||||
// inline everything we can
|
|
||||||
function->setDoesNotThrow(true);
|
|
||||||
if (!(ds->storageClass == SC_EXTERN_C) && !g->generateDebuggingSymbols &&
|
|
||||||
(ds->typeQualifier & TYPEQUAL_INLINE))
|
|
||||||
function->addFnAttr(llvm::Attribute::AlwaysInline);
|
|
||||||
if (functionType->isTask)
|
|
||||||
// This also applies transitively to members I think?
|
|
||||||
function->setDoesNotAlias(1, true);
|
|
||||||
|
|
||||||
// Make sure that the return type isn't 'varying' if the function is
|
|
||||||
// 'export'ed.
|
|
||||||
if (ds->storageClass == SC_EXPORT &&
|
|
||||||
lRecursiveCheckVarying(functionType->GetReturnType()))
|
|
||||||
Error(decl->pos, "Illegal to return a \"varying\" type from exported function \"%s\"",
|
|
||||||
funSym->name.c_str());
|
|
||||||
|
|
||||||
if (functionType->isTask && (functionType->GetReturnType() != AtomicType::Void))
|
|
||||||
Error(funSym->pos, "Task-qualified functions must have void return type.");
|
|
||||||
|
|
||||||
if (functionType->isExported || functionType->isExternC)
|
|
||||||
lCheckForStructParameters(functionType, funSym->pos);
|
|
||||||
|
|
||||||
// Loop over all of the arguments; process default values if present
|
|
||||||
// and do other checks and parameter attribute setting.
|
|
||||||
bool seenDefaultArg = false;
|
|
||||||
std::vector<ConstExpr *> argDefaults;
|
|
||||||
int nArgs = decl->functionArgs ? decl->functionArgs->size() : 0;
|
|
||||||
for (int i = 0; i < nArgs; ++i) {
|
|
||||||
Declaration *pdecl = (*decl->functionArgs)[i];
|
|
||||||
assert(pdecl->declarators.size() == 1);
|
|
||||||
Symbol *sym = pdecl->declarators[0]->sym;
|
|
||||||
|
|
||||||
// If the function is exported, make sure that the parameter
|
|
||||||
// doesn't have any varying stuff going on in it.
|
|
||||||
if (ds->storageClass == SC_EXPORT)
|
|
||||||
lCheckForVaryingParameter(sym);
|
|
||||||
|
|
||||||
// ISPC assumes that all memory passed in is aligned to the native
|
|
||||||
// width and that no pointers alias. (It should be possible to
|
|
||||||
// specify when this is not the case, but this should be the
|
|
||||||
// default.) Set parameter attributes accordingly.
|
|
||||||
if (!functionType->isTask && dynamic_cast<const ReferenceType *>(sym->type) != NULL) {
|
|
||||||
// NOTE: LLVM indexes function parameters starting from 1.
|
|
||||||
// This is unintuitive.
|
|
||||||
function->setDoesNotAlias(i+1, true);
|
|
||||||
int align = 4 * RoundUpPow2(g->target.nativeVectorWidth);
|
|
||||||
function->addAttribute(i+1, llvm::Attribute::constructAlignmentFromInt(align));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m->symbolTable->LookupFunction(sym->name.c_str()) != NULL)
|
|
||||||
Warning(sym->pos, "Function parameter \"%s\" shadows a function "
|
|
||||||
"declared in global scope.", sym->name.c_str());
|
|
||||||
|
|
||||||
// See if a default argument value was provided with the parameter
|
|
||||||
Expr *defaultValue = pdecl->declarators[0]->initExpr;
|
|
||||||
if (defaultValue != NULL) {
|
|
||||||
// If we have one, make sure it's a compile-time constant
|
|
||||||
seenDefaultArg = true;
|
|
||||||
defaultValue = defaultValue->TypeCheck();
|
|
||||||
defaultValue = defaultValue->Optimize();
|
|
||||||
defaultValue = dynamic_cast<ConstExpr *>(defaultValue);
|
|
||||||
if (!defaultValue) {
|
|
||||||
Error(sym->pos, "Default value for parameter \"%s\" must be "
|
|
||||||
"a compile-time constant.", sym->name.c_str());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (seenDefaultArg) {
|
|
||||||
// Once one parameter has provided a default value, then all of
|
|
||||||
// the following ones must have them as well.
|
|
||||||
Error(sym->pos, "Parameter \"%s\" is missing default: all parameters after "
|
|
||||||
"the first parameter with a default value must have default values "
|
|
||||||
"as well.", sym->name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the default value to argDefaults. Note that we make this
|
|
||||||
// call for all parameters, even those where no default value was
|
|
||||||
// provided. In that case, a NULL value is stored here. This
|
|
||||||
// approach means that we can always just look at the i'th entry of
|
|
||||||
// argDefaults to find the default value for the i'th parameter.
|
|
||||||
argDefaults.push_back(dynamic_cast<ConstExpr *>(defaultValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
// And only now can we set the default values in the FunctionType
|
|
||||||
functionType->SetArgumentDefaults(argDefaults);
|
|
||||||
|
|
||||||
// If llvm gave us back a Function * with a different name than the one
|
|
||||||
// we asked for, then there's already a function with that same
|
|
||||||
// (mangled) name in the llvm::Module. In that case, erase the one we
|
|
||||||
// tried to add and just work with the one it already had.
|
|
||||||
if (function->getName() != functionName) {
|
|
||||||
function->eraseFromParent();
|
|
||||||
function = m->module->getFunction(functionName);
|
|
||||||
}
|
|
||||||
funSym->function = function;
|
|
||||||
|
|
||||||
// But if that function has a definition, we don't want to redefine it.
|
|
||||||
if (!function->empty()) {
|
|
||||||
Warning(funSym->pos, "Ignoring redefinition of function \"%s\".",
|
|
||||||
funSym->name.c_str());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, we know all is good and we can add the function to the
|
|
||||||
// symbol table
|
|
||||||
bool ok = m->symbolTable->AddFunction(funSym);
|
|
||||||
assert(ok);
|
|
||||||
return funSym;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Type *
|
const Type *
|
||||||
Function::GetReturnType() const {
|
Function::GetReturnType() const {
|
||||||
|
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
|
||||||
|
assert(type != NULL);
|
||||||
return type->GetReturnType();
|
return type->GetReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const FunctionType *
|
const FunctionType *
|
||||||
Function::GetType() const {
|
Function::GetType() const {
|
||||||
|
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
|
||||||
|
assert(type != NULL);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,6 +179,8 @@ Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function,
|
|||||||
#if 0
|
#if 0
|
||||||
llvm::BasicBlock *entryBBlock = ctx->GetCurrentBasicBlock();
|
llvm::BasicBlock *entryBBlock = ctx->GetCurrentBasicBlock();
|
||||||
#endif
|
#endif
|
||||||
|
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
|
||||||
|
assert(type != NULL);
|
||||||
if (type->isTask == true) {
|
if (type->isTask == true) {
|
||||||
// For tasks, we there should always be three parmeters: the
|
// For tasks, we there should always be three parmeters: the
|
||||||
// pointer to the structure that holds all of the arguments, the
|
// pointer to the structure that holds all of the arguments, the
|
||||||
@@ -612,7 +349,9 @@ Function::GenerateIR() {
|
|||||||
// If the function is 'export'-qualified, emit a second version of
|
// If the function is 'export'-qualified, emit a second version of
|
||||||
// it without a mask parameter and without name mangling so that
|
// it without a mask parameter and without name mangling so that
|
||||||
// the application can call it
|
// the application can call it
|
||||||
if (isExported) {
|
const FunctionType *type = dynamic_cast<const FunctionType *>(sym->type);
|
||||||
|
assert(type != NULL);
|
||||||
|
if (type->isExported) {
|
||||||
if (!type->isTask) {
|
if (!type->isTask) {
|
||||||
LLVM_TYPE_CONST llvm::FunctionType *ftype =
|
LLVM_TYPE_CONST llvm::FunctionType *ftype =
|
||||||
type->LLVMFunctionType(g->ctx);
|
type->LLVMFunctionType(g->ctx);
|
||||||
|
|||||||
6
func.h
6
func.h
@@ -43,9 +43,7 @@
|
|||||||
|
|
||||||
class Function {
|
class Function {
|
||||||
public:
|
public:
|
||||||
Function(DeclSpecs *ds, Declarator *decl, Stmt *code);
|
Function(Symbol *sym, const std::vector<Symbol *> &args, Stmt *code);
|
||||||
|
|
||||||
static Symbol *InitFunctionSymbol(DeclSpecs *ds, Declarator *decl);
|
|
||||||
|
|
||||||
const Type *GetReturnType() const;
|
const Type *GetReturnType() const;
|
||||||
const FunctionType *GetType() const;
|
const FunctionType *GetType() const;
|
||||||
@@ -58,10 +56,8 @@ private:
|
|||||||
SourcePos firstStmtPos);
|
SourcePos firstStmtPos);
|
||||||
|
|
||||||
Symbol *sym;
|
Symbol *sym;
|
||||||
const FunctionType *type;
|
|
||||||
std::vector<Symbol *> args;
|
std::vector<Symbol *> args;
|
||||||
Stmt *code;
|
Stmt *code;
|
||||||
bool isExported;
|
|
||||||
Symbol *maskSymbol;
|
Symbol *maskSymbol;
|
||||||
Symbol *threadIndexSym, *threadCountSym;
|
Symbol *threadIndexSym, *threadCountSym;
|
||||||
Symbol *taskIndexSym, *taskCountSym;
|
Symbol *taskIndexSym, *taskCountSym;
|
||||||
|
|||||||
4
ispc.h
4
ispc.h
@@ -84,9 +84,6 @@ namespace llvm {
|
|||||||
|
|
||||||
class ArrayType;
|
class ArrayType;
|
||||||
class AtomicType;
|
class AtomicType;
|
||||||
class DeclSpecs;
|
|
||||||
class Declaration;
|
|
||||||
class Declarator;
|
|
||||||
class FunctionEmitContext;
|
class FunctionEmitContext;
|
||||||
class Expr;
|
class Expr;
|
||||||
class ExprList;
|
class ExprList;
|
||||||
@@ -97,6 +94,7 @@ class Stmt;
|
|||||||
class Symbol;
|
class Symbol;
|
||||||
class SymbolTable;
|
class SymbolTable;
|
||||||
class Type;
|
class Type;
|
||||||
|
struct VariableDeclaration;
|
||||||
|
|
||||||
/** @brief Representation of a range of positions in a source file.
|
/** @brief Representation of a range of positions in a source file.
|
||||||
|
|
||||||
|
|||||||
2
lex.ll
2
lex.ll
@@ -34,13 +34,13 @@
|
|||||||
%{
|
%{
|
||||||
|
|
||||||
#include "ispc.h"
|
#include "ispc.h"
|
||||||
#include "decl.h"
|
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "parse.hh"
|
#include "parse.hh"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
static uint64_t lParseBinary(const char *ptr, SourcePos pos);
|
static uint64_t lParseBinary(const char *ptr, SourcePos pos);
|
||||||
static void lCComment(SourcePos *);
|
static void lCComment(SourcePos *);
|
||||||
|
|||||||
462
module.cpp
462
module.cpp
@@ -41,7 +41,6 @@
|
|||||||
#include "ctx.h"
|
#include "ctx.h"
|
||||||
#include "func.h"
|
#include "func.h"
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
#include "decl.h"
|
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
@@ -95,9 +94,10 @@
|
|||||||
// Module
|
// Module
|
||||||
|
|
||||||
Module::Module(const char *fn) {
|
Module::Module(const char *fn) {
|
||||||
// FIXME: It's a hack to do this here, but it must be done after the
|
// It's a hack to do this here, but it must be done after the target
|
||||||
// target information has been set (so e.g. the vector width is
|
// information has been set (so e.g. the vector width is known...) In
|
||||||
// known...)
|
// particular, if we're compiling to multiple targets with different
|
||||||
|
// vector widths, this needs to be redone each time through.
|
||||||
InitLLVMUtil(g->ctx, g->target);
|
InitLLVMUtil(g->ctx, g->target);
|
||||||
|
|
||||||
filename = fn;
|
filename = fn;
|
||||||
@@ -209,130 +209,358 @@ Module::CompileFile() {
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Module::AddGlobal(DeclSpecs *ds, Declarator *decl) {
|
Module::AddTypeDef(Symbol *sym) {
|
||||||
// This function is called for a number of cases: function
|
// Typedefs are easy; just add the mapping between the given name and
|
||||||
// declarations, typedefs, and global variables declarations /
|
// the given type.
|
||||||
// definitions. Figure out what we've got and take care of it.
|
symbolTable->AddType(sym->name.c_str(), sym->type, sym->pos);
|
||||||
|
}
|
||||||
|
|
||||||
if (ds == NULL || decl == NULL)
|
|
||||||
// Error happened earlier during parsing
|
void
|
||||||
|
Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||||
|
// 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
|
||||||
|
assert(errorCount > 0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (decl->isFunction) {
|
|
||||||
// function declaration
|
|
||||||
const Type *t = decl->GetType(ds);
|
|
||||||
const FunctionType *ft = dynamic_cast<const FunctionType *>(t);
|
|
||||||
assert(ft != NULL);
|
|
||||||
if (m->symbolTable->LookupFunction(decl->sym->name.c_str(), ft) != NULL)
|
|
||||||
// Ignore redeclaration of a function with the same name and type
|
|
||||||
return;
|
|
||||||
// Otherwise do all of the llvm Module and SymbolTable work..
|
|
||||||
Function::InitFunctionSymbol(ds, decl);
|
|
||||||
}
|
}
|
||||||
else if (ds->storageClass == SC_TYPEDEF) {
|
|
||||||
// Typedefs are easy; just add the mapping between the given name
|
if (symbolTable->LookupFunction(sym->name.c_str()) != NULL) {
|
||||||
// and the given type.
|
Error(sym->pos, "Global variable \"%s\" shadows previously-declared function.",
|
||||||
m->symbolTable->AddType(decl->sym->name.c_str(), decl->sym->type,
|
sym->name.c_str());
|
||||||
decl->sym->pos);
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// global variable
|
|
||||||
if (m->symbolTable->LookupFunction(decl->sym->name.c_str()) != NULL) {
|
|
||||||
Error(decl->pos, "Global variable \"%s\" shadows previously-declared function.",
|
|
||||||
decl->sym->name.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These may be NULL due to errors in parsing; just gracefully
|
if (sym->storageClass == SC_EXTERN_C) {
|
||||||
// return here if so.
|
Error(sym->pos, "extern \"C\" qualifier can only be used for functions.");
|
||||||
if (!decl->sym || !decl->sym->type) {
|
return;
|
||||||
// But if these are NULL and there haven't been any previous
|
}
|
||||||
// errors, something surprising is going on
|
|
||||||
assert(errorCount > 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds->storageClass == SC_EXTERN_C) {
|
LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx);
|
||||||
Error(decl->pos, "extern \"C\" qualifier can only be used for functions.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLVM_TYPE_CONST llvm::Type *llvmType = decl->sym->type->LLVMType(g->ctx);
|
// 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) {
|
||||||
|
if (initExpr != NULL)
|
||||||
|
Error(sym->pos, "Initializer can't be provided with \"extern\" "
|
||||||
|
"global variable \"%s\".", sym->name.c_str());
|
||||||
|
}
|
||||||
|
else if (initExpr != NULL) {
|
||||||
|
initExpr = initExpr->TypeCheck();
|
||||||
|
if (initExpr != NULL) {
|
||||||
|
// We need to make sure the initializer expression is
|
||||||
|
// the same type as the global. (But not if it's an
|
||||||
|
// ExprList; they don't have types per se / can't type
|
||||||
|
// convert themselves anyway.)
|
||||||
|
if (dynamic_cast<ExprList *>(initExpr) == NULL)
|
||||||
|
initExpr = initExpr->TypeConv(sym->type, "initializer");
|
||||||
|
|
||||||
// See if we have an initializer expression for the global. If so,
|
if (initExpr != NULL) {
|
||||||
// make sure it's a compile-time constant!
|
initExpr = initExpr->Optimize();
|
||||||
llvm::Constant *llvmInitializer = NULL;
|
// Fingers crossed, now let's see if we've got a
|
||||||
if (ds->storageClass == SC_EXTERN || ds->storageClass == SC_EXTERN_C) {
|
// constant value..
|
||||||
if (decl->initExpr != NULL)
|
llvmInitializer = initExpr->GetConstant(sym->type);
|
||||||
Error(decl->pos, "Initializer can't be provided with \"extern\" "
|
|
||||||
"global variable \"%s\".", decl->sym->name.c_str());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (decl->initExpr != NULL) {
|
|
||||||
decl->initExpr = decl->initExpr->TypeCheck();
|
|
||||||
if (decl->initExpr != NULL) {
|
|
||||||
// We need to make sure the initializer expression is
|
|
||||||
// the same type as the global. (But not if it's an
|
|
||||||
// ExprList; they don't have types per se / can't type
|
|
||||||
// convert themselves anyway.)
|
|
||||||
if (dynamic_cast<ExprList *>(decl->initExpr) == NULL)
|
|
||||||
decl->initExpr =
|
|
||||||
decl->initExpr->TypeConv(decl->sym->type, "initializer");
|
|
||||||
|
|
||||||
if (decl->initExpr != NULL) {
|
if (llvmInitializer != NULL) {
|
||||||
decl->initExpr = decl->initExpr->Optimize();
|
if (sym->type->IsConstType())
|
||||||
// Fingers crossed, now let's see if we've got a
|
// Try to get a ConstExpr associated with
|
||||||
// constant value..
|
// the symbol. This dynamic_cast can
|
||||||
llvmInitializer = decl->initExpr->GetConstant(decl->sym->type);
|
// validly fail, for example for types like
|
||||||
|
// StructTypes where a ConstExpr can't
|
||||||
if (llvmInitializer != NULL) {
|
// represent their values.
|
||||||
if (decl->sym->type->IsConstType())
|
sym->constValue =
|
||||||
// Try to get a ConstExpr associated with
|
dynamic_cast<ConstExpr *>(initExpr);
|
||||||
// the symbol. This dynamic_cast can
|
|
||||||
// validly fail, for example for types like
|
|
||||||
// StructTypes where a ConstExpr can't
|
|
||||||
// represent their values.
|
|
||||||
decl->sym->constValue =
|
|
||||||
dynamic_cast<ConstExpr *>(decl->initExpr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Error(decl->pos, "Initializer for global variable \"%s\" "
|
|
||||||
"must be a constant.", decl->sym->name.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
Error(sym->pos, "Initializer for global variable \"%s\" "
|
||||||
|
"must be a constant.", sym->name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no initializer was provided or if we couldn't get a value
|
|
||||||
// above, initialize it with zeros..
|
|
||||||
if (llvmInitializer == NULL)
|
|
||||||
llvmInitializer = llvm::Constant::getNullValue(llvmType);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isConst = (ds->typeQualifier & TYPEQUAL_CONST) != 0;
|
// If no initializer was provided or if we couldn't get a value
|
||||||
llvm::GlobalValue::LinkageTypes linkage =
|
// above, initialize it with zeros..
|
||||||
(ds->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage :
|
if (llvmInitializer == NULL)
|
||||||
llvm::GlobalValue::ExternalLinkage;
|
llvmInitializer = llvm::Constant::getNullValue(llvmType);
|
||||||
decl->sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst,
|
|
||||||
linkage, llvmInitializer,
|
|
||||||
decl->sym->name.c_str());
|
|
||||||
m->symbolTable->AddVariable(decl->sym);
|
|
||||||
|
|
||||||
if (diBuilder && (ds->storageClass != SC_EXTERN)) {
|
llvm::GlobalValue::LinkageTypes linkage =
|
||||||
llvm::DIFile file = decl->pos.GetDIFile();
|
(sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage :
|
||||||
diBuilder->createGlobalVariable(decl->sym->name,
|
llvm::GlobalValue::ExternalLinkage;
|
||||||
file,
|
sym->storagePtr = new llvm::GlobalVariable(*module, llvmType, isConst,
|
||||||
decl->pos.first_line,
|
linkage, llvmInitializer,
|
||||||
decl->sym->type->GetDIType(file),
|
sym->name.c_str());
|
||||||
(ds->storageClass == SC_STATIC),
|
symbolTable->AddVariable(sym);
|
||||||
decl->sym->storagePtr);
|
|
||||||
|
if (diBuilder && (sym->storageClass != SC_EXTERN)) {
|
||||||
|
llvm::DIFile file = sym->pos.GetDIFile();
|
||||||
|
diBuilder->createGlobalVariable(sym->name,
|
||||||
|
file,
|
||||||
|
sym->pos.first_line,
|
||||||
|
sym->type->GetDIType(file),
|
||||||
|
(sym->storageClass == SC_STATIC),
|
||||||
|
sym->storagePtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Given an arbitrary type, see if it or any of the types contained in it
|
||||||
|
are varying. Returns true if so, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
lRecursiveCheckVarying(const Type *t) {
|
||||||
|
t = t->GetBaseType();
|
||||||
|
if (t->IsVaryingType()) return true;
|
||||||
|
|
||||||
|
const StructType *st = dynamic_cast<const StructType *>(t);
|
||||||
|
if (st) {
|
||||||
|
for (int i = 0; i < st->GetElementCount(); ++i)
|
||||||
|
if (lRecursiveCheckVarying(st->GetElementType(i)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Given a Symbol representing a function parameter, see if it or any
|
||||||
|
contained types are varying. If so, issue an error. (This function
|
||||||
|
should only be called for parameters to 'export'ed functions, where
|
||||||
|
varying parameters is illegal.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lCheckForVaryingParameter(Symbol *sym) {
|
||||||
|
if (lRecursiveCheckVarying(sym->type)) {
|
||||||
|
const Type *t = sym->type->GetBaseType();
|
||||||
|
if (dynamic_cast<const StructType *>(t))
|
||||||
|
Error(sym->pos, "Struct parameter \"%s\" with varying member(s) is illegal "
|
||||||
|
"in an exported function.",
|
||||||
|
sym->name.c_str());
|
||||||
|
else
|
||||||
|
Error(sym->pos, "Varying parameter \"%s\" is illegal in an exported function.",
|
||||||
|
sym->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Given a function type, loop through the function parameters and see if
|
||||||
|
any are StructTypes. If so, issue an error (this seems to be broken
|
||||||
|
currently).
|
||||||
|
|
||||||
|
@todo Fix passing structs from C/C++ to ispc functions.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
|
||||||
|
const std::vector<const Type *> &argTypes = ftype->GetArgumentTypes();
|
||||||
|
for (unsigned int i = 0; i < argTypes.size(); ++i) {
|
||||||
|
const Type *type = argTypes[i];
|
||||||
|
if (dynamic_cast<const StructType *>(type) != NULL) {
|
||||||
|
Error(pos, "Passing structs to/from application functions is currently broken. "
|
||||||
|
"Use a reference or const reference instead for now.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** We've got a declaration for a function to process. This function does
|
||||||
|
all the work of creating the corresponding llvm::Function instance,
|
||||||
|
adding the symbol for the function to the symbol table and doing
|
||||||
|
various sanity checks. This function returns true upon success and
|
||||||
|
false if any errors were encountered.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
Module::AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code) {
|
Module::AddFunctionDeclaration(Symbol *funSym,
|
||||||
ast->AddFunction(ds, decl, code);
|
const std::vector<VariableDeclaration> &args,
|
||||||
|
bool isInline) {
|
||||||
|
// We should have gotten a FunctionType back from the GetType() call above.
|
||||||
|
const FunctionType *functionType =
|
||||||
|
dynamic_cast<const FunctionType *>(funSym->type);
|
||||||
|
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. "
|
||||||
|
"Ignoring this definition.",
|
||||||
|
funSym->name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolTable->LookupFunction(funSym->name.c_str(),
|
||||||
|
functionType) != NULL)
|
||||||
|
// Ignore redeclaration of a function with the same name and type
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (funSym->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());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Symbol *> *funcs =
|
||||||
|
symbolTable->LookupFunction(funSym->name.c_str());
|
||||||
|
if (funcs != NULL) {
|
||||||
|
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\"; "
|
||||||
|
"%d functions with the same name have already been declared.",
|
||||||
|
funSym->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))
|
||||||
|
return;
|
||||||
|
else {
|
||||||
|
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".",
|
||||||
|
funSym->name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the LLVM FunctionType
|
||||||
|
bool includeMask = (funSym->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 ||
|
||||||
|
isInline) ?
|
||||||
|
llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
|
||||||
|
std::string functionName = ((funSym->storageClass == SC_EXTERN_C) ?
|
||||||
|
funSym->name : funSym->MangledName());
|
||||||
|
if (g->mangleFunctionsWithTarget)
|
||||||
|
functionName += g->target.GetISAString();
|
||||||
|
llvm::Function *function =
|
||||||
|
llvm::Function::Create(llvmFunctionType, linkage, functionName.c_str(),
|
||||||
|
module);
|
||||||
|
|
||||||
|
// Set function attributes: we never throw exceptions, and want to
|
||||||
|
// inline everything we can
|
||||||
|
function->setDoesNotThrow(true);
|
||||||
|
if (!(funSym->storageClass == SC_EXTERN_C) &&
|
||||||
|
!g->generateDebuggingSymbols &&
|
||||||
|
isInline)
|
||||||
|
function->addFnAttr(llvm::Attribute::AlwaysInline);
|
||||||
|
if (functionType->isTask)
|
||||||
|
// This also applies transitively to members I think?
|
||||||
|
function->setDoesNotAlias(1, true);
|
||||||
|
|
||||||
|
// Make sure that the return type isn't 'varying' if the function is
|
||||||
|
// 'export'ed.
|
||||||
|
if (funSym->storageClass == SC_EXPORT &&
|
||||||
|
lRecursiveCheckVarying(functionType->GetReturnType()))
|
||||||
|
Error(funSym->pos, "Illegal to return a \"varying\" type from exported "
|
||||||
|
"function \"%s\"", funSym->name.c_str());
|
||||||
|
|
||||||
|
if (functionType->isTask && (functionType->GetReturnType() != AtomicType::Void))
|
||||||
|
Error(funSym->pos, "Task-qualified functions must have void return type.");
|
||||||
|
|
||||||
|
if (functionType->isExported || functionType->isExternC)
|
||||||
|
lCheckForStructParameters(functionType, funSym->pos);
|
||||||
|
|
||||||
|
// Loop over all of the arguments; process default values if present
|
||||||
|
// and do other checks and parameter attribute setting.
|
||||||
|
bool seenDefaultArg = false;
|
||||||
|
std::vector<ConstExpr *> argDefaults;
|
||||||
|
for (unsigned int i = 0; i < args.size(); ++i) {
|
||||||
|
Symbol *argSym = args[i].sym;
|
||||||
|
|
||||||
|
// If the function is exported, make sure that the parameter
|
||||||
|
// doesn't have any varying stuff going on in it.
|
||||||
|
if (funSym->storageClass == SC_EXPORT)
|
||||||
|
lCheckForVaryingParameter(argSym);
|
||||||
|
|
||||||
|
// ISPC assumes that all memory passed in is aligned to the native
|
||||||
|
// width and that no pointers alias. (It should be possible to
|
||||||
|
// specify when this is not the case, but this should be the
|
||||||
|
// default.) Set parameter attributes accordingly.
|
||||||
|
if (!functionType->isTask &&
|
||||||
|
dynamic_cast<const ReferenceType *>(argSym->type) != NULL) {
|
||||||
|
// NOTE: LLVM indexes function parameters starting from 1.
|
||||||
|
// This is unintuitive.
|
||||||
|
function->setDoesNotAlias(i+1, true);
|
||||||
|
int align = 4 * RoundUpPow2(g->target.nativeVectorWidth);
|
||||||
|
function->addAttribute(i+1, llvm::Attribute::constructAlignmentFromInt(align));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolTable->LookupFunction(argSym->name.c_str()) != NULL)
|
||||||
|
Warning(argSym->pos, "Function parameter \"%s\" shadows a function "
|
||||||
|
"declared in global scope.", argSym->name.c_str());
|
||||||
|
|
||||||
|
// See if a default argument value was provided with the parameter
|
||||||
|
Expr *defaultValue = args[i].init;
|
||||||
|
if (defaultValue != NULL) {
|
||||||
|
// If we have one, make sure it's a compile-time constant
|
||||||
|
seenDefaultArg = true;
|
||||||
|
defaultValue = defaultValue->TypeCheck();
|
||||||
|
defaultValue = defaultValue->Optimize();
|
||||||
|
defaultValue = dynamic_cast<ConstExpr *>(defaultValue);
|
||||||
|
if (!defaultValue) {
|
||||||
|
Error(argSym->pos, "Default value for parameter \"%s\" must be "
|
||||||
|
"a compile-time constant.", argSym->name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (seenDefaultArg) {
|
||||||
|
// Once one parameter has provided a default value, then all of
|
||||||
|
// the following ones must have them as well.
|
||||||
|
Error(argSym->pos, "Parameter \"%s\" is missing default: all "
|
||||||
|
"parameters after the first parameter with a default value "
|
||||||
|
"must have default values as well.", argSym->name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the default value to argDefaults. Note that we make this
|
||||||
|
// call for all parameters, even those where no default value was
|
||||||
|
// provided. In that case, a NULL value is stored here. This
|
||||||
|
// approach means that we can always just look at the i'th entry of
|
||||||
|
// argDefaults to find the default value for the i'th parameter.
|
||||||
|
argDefaults.push_back(dynamic_cast<ConstExpr *>(defaultValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
// And only now can we set the default values in the FunctionType
|
||||||
|
functionType->SetArgumentDefaults(argDefaults);
|
||||||
|
|
||||||
|
// If llvm gave us back a Function * with a different name than the one
|
||||||
|
// we asked for, then there's already a function with that same
|
||||||
|
// (mangled) name in the llvm::Module. In that case, erase the one we
|
||||||
|
// tried to add and just work with the one it already had.
|
||||||
|
if (function->getName() != functionName) {
|
||||||
|
function->eraseFromParent();
|
||||||
|
function = module->getFunction(functionName);
|
||||||
|
}
|
||||||
|
funSym->function = function;
|
||||||
|
|
||||||
|
// But if that function has a definition, we don't want to redefine it.
|
||||||
|
if (!function->empty()) {
|
||||||
|
Warning(funSym->pos, "Ignoring redefinition of function \"%s\".",
|
||||||
|
funSym->name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we know all is good and we can add the function to the
|
||||||
|
// symbol table
|
||||||
|
bool ok = symbolTable->AddFunction(funSym);
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Module::AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args,
|
||||||
|
Stmt *code) {
|
||||||
|
ast->AddFunction(sym, args, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -725,24 +953,6 @@ lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Given an arbitrary type, see if it or any of the types contained in it
|
|
||||||
are varying. Returns true if so, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
lRecursiveCheckVarying(const Type *t) {
|
|
||||||
t = t->GetBaseType();
|
|
||||||
if (t->IsVaryingType()) return true;
|
|
||||||
|
|
||||||
const StructType *st = dynamic_cast<const StructType *>(t);
|
|
||||||
if (st) {
|
|
||||||
for (int i = 0; i < st->GetElementCount(); ++i)
|
|
||||||
if (lRecursiveCheckVarying(st->GetElementType(i)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lPrintExternGlobals(FILE *file, const std::vector<Symbol *> &externGlobals) {
|
lPrintExternGlobals(FILE *file, const std::vector<Symbol *> &externGlobals) {
|
||||||
for (unsigned int i = 0; i < externGlobals.size(); ++i) {
|
for (unsigned int i = 0; i < externGlobals.size(); ++i) {
|
||||||
|
|||||||
19
module.h
19
module.h
@@ -58,13 +58,24 @@ public:
|
|||||||
SymbolTable. Returns the number of errors during compilation. */
|
SymbolTable. Returns the number of errors during compilation. */
|
||||||
int CompileFile();
|
int CompileFile();
|
||||||
|
|
||||||
/** Adds the global variable described by the declaration information to
|
/** Add a named type definition to the module. */
|
||||||
the module. */
|
void AddTypeDef(Symbol *sym);
|
||||||
void AddGlobal(DeclSpecs *ds, Declarator *decl);
|
|
||||||
|
/** 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);
|
||||||
|
|
||||||
|
/** Add a declaration of the function defined by the given function
|
||||||
|
symbol with given arguments to the module. */
|
||||||
|
void AddFunctionDeclaration(Symbol *funSym,
|
||||||
|
const std::vector<VariableDeclaration> &args,
|
||||||
|
bool isInline);
|
||||||
|
|
||||||
/** 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 AddFunction(DeclSpecs *ds, Declarator *decl, Stmt *code);
|
void AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args,
|
||||||
|
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. */
|
||||||
|
|||||||
60
parse.yy
60
parse.yy
@@ -89,6 +89,7 @@ extern char *yytext;
|
|||||||
|
|
||||||
void yyerror(const char *s) { fprintf(stderr, "Parse error: %s\n", s); }
|
void yyerror(const char *s) { fprintf(stderr, "Parse error: %s\n", s); }
|
||||||
|
|
||||||
|
static void lAddDeclaration(DeclSpecs *ds, Declarator *decl);
|
||||||
static void lAddFunctionParams(Declarator *decl);
|
static void lAddFunctionParams(Declarator *decl);
|
||||||
static void lAddMaskToSymbolTable(SourcePos pos);
|
static void lAddMaskToSymbolTable(SourcePos pos);
|
||||||
static void lAddThreadIndexCountToSymbolTable(SourcePos pos);
|
static void lAddThreadIndexCountToSymbolTable(SourcePos pos);
|
||||||
@@ -460,7 +461,11 @@ constant_expression
|
|||||||
;
|
;
|
||||||
|
|
||||||
declaration_statement
|
declaration_statement
|
||||||
: declaration { $$ = new DeclStmt(@1, $1, m->symbolTable); }
|
: declaration
|
||||||
|
{
|
||||||
|
std::vector<VariableDeclaration> vars = $1->GetVariableDeclarations();
|
||||||
|
$$ = new DeclStmt(vars, @1);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
declaration
|
declaration
|
||||||
@@ -1224,14 +1229,14 @@ external_declaration
|
|||||||
{
|
{
|
||||||
if ($1 != NULL)
|
if ($1 != NULL)
|
||||||
for (unsigned int i = 0; i < $1->declarators.size(); ++i)
|
for (unsigned int i = 0; i < $1->declarators.size(); ++i)
|
||||||
m->AddGlobal($1->declSpecs, $1->declarators[i]);
|
lAddDeclaration($1->declSpecs, $1->declarators[i]);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
function_definition
|
function_definition
|
||||||
: declaration_specifiers declarator
|
: declaration_specifiers declarator
|
||||||
{
|
{
|
||||||
m->AddGlobal($1, $2);
|
lAddDeclaration($1, $2);
|
||||||
lAddFunctionParams($2);
|
lAddFunctionParams($2);
|
||||||
lAddMaskToSymbolTable(@2);
|
lAddMaskToSymbolTable(@2);
|
||||||
if ($1->typeQualifier & TYPEQUAL_TASK)
|
if ($1->typeQualifier & TYPEQUAL_TASK)
|
||||||
@@ -1239,14 +1244,17 @@ function_definition
|
|||||||
}
|
}
|
||||||
compound_statement
|
compound_statement
|
||||||
{
|
{
|
||||||
m->AddFunction($1, $2, $4);
|
Symbol *sym;
|
||||||
|
std::vector<Symbol *> args;
|
||||||
|
$2->GetFunctionInfo($1, &sym, &args);
|
||||||
|
m->AddFunctionDefinition(sym, args, $4);
|
||||||
m->symbolTable->PopScope(); // push in lAddFunctionParams();
|
m->symbolTable->PopScope(); // push in lAddFunctionParams();
|
||||||
}
|
}
|
||||||
/* function with no declared return type??
|
/* function with no declared return type??
|
||||||
func(...)
|
func(...)
|
||||||
| declarator { lAddFunctionParams($1); } compound_statement
|
| declarator { lAddFunctionParams($1); } compound_statement
|
||||||
{
|
{
|
||||||
m->AddFunction(new DeclSpecs(, $1, $3);
|
m->AddFunction(new DeclSpecs(XXX, $1, $3);
|
||||||
m->symbolTable->PopScope(); // push in lAddFunctionParams();
|
m->symbolTable->PopScope(); // push in lAddFunctionParams();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -1255,6 +1263,48 @@ func(...)
|
|||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
lAddDeclaration(DeclSpecs *ds, Declarator *decl) {
|
||||||
|
if (ds == NULL || decl == NULL)
|
||||||
|
// Error happened earlier during parsing
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (decl->isFunction) {
|
||||||
|
// function declaration
|
||||||
|
const Type *t = decl->GetType(ds);
|
||||||
|
const FunctionType *ft = dynamic_cast<const FunctionType *>(t);
|
||||||
|
assert(ft != NULL);
|
||||||
|
|
||||||
|
// Make sure that we've got what we expect here
|
||||||
|
Symbol *funSym = decl->sym;
|
||||||
|
assert(decl->isFunction);
|
||||||
|
assert(decl->arraySize.size() == 0);
|
||||||
|
|
||||||
|
// So far, so good. Go ahead and set the type of the function symbol
|
||||||
|
funSym->type = decl->GetType(ds);
|
||||||
|
funSym->storageClass = ds->storageClass;
|
||||||
|
|
||||||
|
std::vector<VariableDeclaration> args;
|
||||||
|
int nArgs = decl->functionArgs ? decl->functionArgs->size() : 0;
|
||||||
|
for (int i = 0; i < nArgs; ++i) {
|
||||||
|
Declaration *pdecl = (*decl->functionArgs)[i];
|
||||||
|
assert(pdecl->declarators.size() == 1);
|
||||||
|
Symbol *sym = pdecl->declarators[0]->sym;
|
||||||
|
Expr *defaultExpr = pdecl->declarators[0]->initExpr;
|
||||||
|
args.push_back(VariableDeclaration(sym, defaultExpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInline = (ds->typeQualifier & TYPEQUAL_INLINE);
|
||||||
|
m->AddFunctionDeclaration(funSym, args, isInline);
|
||||||
|
}
|
||||||
|
else if (ds->storageClass == SC_TYPEDEF)
|
||||||
|
m->AddTypeDef(decl->sym);
|
||||||
|
else
|
||||||
|
m->AddGlobalVariable(decl->sym, decl->initExpr,
|
||||||
|
(ds->typeQualifier & TYPEQUAL_CONST) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** We're about to start parsing the body of a function; add all of the
|
/** We're about to start parsing the body of a function; add all of the
|
||||||
parameters to the symbol table so that they're available.
|
parameters to the symbol table so that they're available.
|
||||||
*/
|
*/
|
||||||
|
|||||||
92
stmt.cpp
92
stmt.cpp
@@ -40,7 +40,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "decl.h"
|
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "llvmutil.h"
|
#include "llvmutil.h"
|
||||||
@@ -116,9 +115,8 @@ ExprStmt::EstimateCost() const {
|
|||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// DeclStmt
|
// DeclStmt
|
||||||
|
|
||||||
DeclStmt::DeclStmt(SourcePos p, Declaration *d, SymbolTable *s)
|
DeclStmt::DeclStmt(const std::vector<VariableDeclaration> &v, SourcePos p)
|
||||||
: Stmt(p), declaration(d) {
|
: Stmt(p), vars(v) {
|
||||||
declaration->AddSymbols(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -240,16 +238,13 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
if (!ctx->GetCurrentBasicBlock())
|
if (!ctx->GetCurrentBasicBlock())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < declaration->declarators.size(); ++i) {
|
for (unsigned int i = 0; i < vars.size(); ++i) {
|
||||||
Declarator *decl = declaration->declarators[i];
|
Symbol *sym = vars[i].sym;
|
||||||
if (!decl || decl->isFunction)
|
assert(sym != NULL);
|
||||||
continue;
|
|
||||||
|
|
||||||
Symbol *sym = decl->sym;
|
|
||||||
assert(decl->sym != NULL);
|
|
||||||
const Type *type = sym->type;
|
const Type *type = sym->type;
|
||||||
if (!type)
|
if (type == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
Expr *initExpr = vars[i].init;
|
||||||
|
|
||||||
// Now that we're in the thick of emitting code, it's easy for us
|
// Now that we're in the thick of emitting code, it's easy for us
|
||||||
// to find out the level of nesting of varying control flow we're
|
// to find out the level of nesting of varying control flow we're
|
||||||
@@ -265,7 +260,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
// initializer list to finally set the array's size.
|
// initializer list to finally set the array's size.
|
||||||
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
|
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
|
||||||
if (at && at->GetElementCount() == 0) {
|
if (at && at->GetElementCount() == 0) {
|
||||||
ExprList *exprList = dynamic_cast<ExprList *>(decl->initExpr);
|
ExprList *exprList = dynamic_cast<ExprList *>(initExpr);
|
||||||
if (exprList) {
|
if (exprList) {
|
||||||
ArrayType *t = at->GetSizedArray(exprList->exprs.size());
|
ArrayType *t = at->GetSizedArray(exprList->exprs.size());
|
||||||
assert(t != NULL);
|
assert(t != NULL);
|
||||||
@@ -280,7 +275,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// References must have initializer expressions as well.
|
// References must have initializer expressions as well.
|
||||||
if (dynamic_cast<const ReferenceType *>(type) && decl->initExpr == NULL) {
|
if (dynamic_cast<const ReferenceType *>(type) && initExpr == NULL) {
|
||||||
Error(sym->pos,
|
Error(sym->pos,
|
||||||
"Must provide initializer for reference-type variable \"%s\".",
|
"Must provide initializer for reference-type variable \"%s\".",
|
||||||
sym->name.c_str());
|
sym->name.c_str());
|
||||||
@@ -290,18 +285,18 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
LLVM_TYPE_CONST llvm::Type *llvmType = type->LLVMType(g->ctx);
|
LLVM_TYPE_CONST llvm::Type *llvmType = type->LLVMType(g->ctx);
|
||||||
assert(llvmType != NULL);
|
assert(llvmType != NULL);
|
||||||
|
|
||||||
if (declaration->declSpecs->storageClass == SC_STATIC) {
|
if (sym->storageClass == SC_STATIC) {
|
||||||
// For static variables, we need a compile-time constant value
|
// For static variables, we need a compile-time constant value
|
||||||
// for its initializer; if there's no initializer, we use a
|
// for its initializer; if there's no initializer, we use a
|
||||||
// zero value.
|
// zero value.
|
||||||
llvm::Constant *cinit = NULL;
|
llvm::Constant *cinit = NULL;
|
||||||
if (decl->initExpr) {
|
if (initExpr != NULL) {
|
||||||
cinit = decl->initExpr->GetConstant(type);
|
cinit = initExpr->GetConstant(type);
|
||||||
if (!cinit)
|
if (cinit == NULL)
|
||||||
Error(sym->pos, "Initializer for static variable \"%s\" must be a constant.",
|
Error(sym->pos, "Initializer for static variable \"%s\" must be a constant.",
|
||||||
sym->name.c_str());
|
sym->name.c_str());
|
||||||
}
|
}
|
||||||
if (!cinit)
|
if (cinit == NULL)
|
||||||
cinit = llvm::Constant::getNullValue(llvmType);
|
cinit = llvm::Constant::getNullValue(llvmType);
|
||||||
|
|
||||||
// Allocate space for the static variable in global scope, so
|
// Allocate space for the static variable in global scope, so
|
||||||
@@ -323,7 +318,7 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
ctx->EmitVariableDebugInfo(sym);
|
ctx->EmitVariableDebugInfo(sym);
|
||||||
// And then get it initialized...
|
// And then get it initialized...
|
||||||
sym->parentFunction = ctx->GetFunction();
|
sym->parentFunction = ctx->GetFunction();
|
||||||
lInitSymbol(sym->storagePtr, sym->name.c_str(), type, decl->initExpr,
|
lInitSymbol(sym->storagePtr, sym->name.c_str(), type, initExpr,
|
||||||
ctx, sym->pos);
|
ctx, sym->pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,10 +327,10 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
|
|
||||||
Stmt *
|
Stmt *
|
||||||
DeclStmt::Optimize() {
|
DeclStmt::Optimize() {
|
||||||
for (unsigned int i = 0; i < declaration->declarators.size(); ++i) {
|
for (unsigned int i = 0; i < vars.size(); ++i) {
|
||||||
Declarator *decl = declaration->declarators[i];
|
if (vars[i].init != NULL) {
|
||||||
if (decl && decl->initExpr) {
|
vars[i].init = vars[i].init->Optimize();
|
||||||
decl->initExpr = decl->initExpr->Optimize();
|
Expr *init = vars[i].init;
|
||||||
|
|
||||||
// If the variable is const-qualified, after we've optimized
|
// If the variable is const-qualified, after we've optimized
|
||||||
// the initializer expression, see if we have a ConstExpr. If
|
// the initializer expression, see if we have a ConstExpr. If
|
||||||
@@ -352,11 +347,11 @@ DeclStmt::Optimize() {
|
|||||||
// is definitely a compile-time constant for things like
|
// is definitely a compile-time constant for things like
|
||||||
// computing array sizes from non-trivial expressions is
|
// computing array sizes from non-trivial expressions is
|
||||||
// consequently limited.
|
// consequently limited.
|
||||||
Symbol *sym = decl->sym;
|
Symbol *sym = vars[i].sym;
|
||||||
if (sym->type && sym->type->IsConstType() && decl->initExpr &&
|
if (sym->type && sym->type->IsConstType() && init != NULL &&
|
||||||
dynamic_cast<ExprList *>(decl->initExpr) == NULL &&
|
dynamic_cast<ExprList *>(init) == NULL &&
|
||||||
Type::Equal(decl->initExpr->GetType(), sym->type))
|
Type::Equal(init->GetType(), sym->type))
|
||||||
sym->constValue = dynamic_cast<ConstExpr *>(decl->initExpr);
|
sym->constValue = dynamic_cast<ConstExpr *>(init);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@@ -366,30 +361,29 @@ DeclStmt::Optimize() {
|
|||||||
Stmt *
|
Stmt *
|
||||||
DeclStmt::TypeCheck() {
|
DeclStmt::TypeCheck() {
|
||||||
bool encounteredError = false;
|
bool encounteredError = false;
|
||||||
for (unsigned int i = 0; i < declaration->declarators.size(); ++i) {
|
for (unsigned int i = 0; i < vars.size(); ++i) {
|
||||||
Declarator *decl = declaration->declarators[i];
|
if (!vars[i].sym) {
|
||||||
if (!decl) {
|
|
||||||
encounteredError = true;
|
encounteredError = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decl->initExpr)
|
if (vars[i].init == NULL)
|
||||||
continue;
|
continue;
|
||||||
decl->initExpr = decl->initExpr->TypeCheck();
|
vars[i].init = vars[i].init->TypeCheck();
|
||||||
if (!decl->initExpr)
|
if (vars[i].init == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// get the right type for stuff like const float foo = 2; so that
|
// get the right type for stuff like const float foo = 2; so that
|
||||||
// the int->float type conversion is in there and we don't return
|
// the int->float type conversion is in there and we don't return
|
||||||
// an int as the constValue later...
|
// an int as the constValue later...
|
||||||
const Type *type = decl->sym->type;
|
const Type *type = vars[i].sym->type;
|
||||||
if (dynamic_cast<const AtomicType *>(type) != NULL ||
|
if (dynamic_cast<const AtomicType *>(type) != NULL ||
|
||||||
dynamic_cast<const EnumType *>(type) != NULL) {
|
dynamic_cast<const EnumType *>(type) != NULL) {
|
||||||
// If it's an expr list with an atomic type, we'll later issue
|
// If it's an expr list with an atomic type, we'll later issue
|
||||||
// an error. Need to leave decl->initExpr as is in that case so it
|
// an error. Need to leave decl->initExpr as is in that case so it
|
||||||
// is in fact caught later, though.
|
// is in fact caught later, though.
|
||||||
if (dynamic_cast<ExprList *>(decl->initExpr) == NULL)
|
if (dynamic_cast<ExprList *>(vars[i].init) == NULL)
|
||||||
decl->initExpr = decl->initExpr->TypeConv(type, "initializer");
|
vars[i].init = vars[i].init->TypeConv(type, "initializer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return encounteredError ? NULL : this;
|
return encounteredError ? NULL : this;
|
||||||
@@ -400,8 +394,16 @@ void
|
|||||||
DeclStmt::Print(int indent) const {
|
DeclStmt::Print(int indent) const {
|
||||||
printf("%*cDecl Stmt:", indent, ' ');
|
printf("%*cDecl Stmt:", indent, ' ');
|
||||||
pos.Print();
|
pos.Print();
|
||||||
if (declaration)
|
for (unsigned int i = 0; i < vars.size(); ++i) {
|
||||||
declaration->Print();
|
printf("%*cVariable %s (%s)", indent+4, ' ',
|
||||||
|
vars[i].sym->name.c_str(),
|
||||||
|
vars[i].sym->type->GetString().c_str());
|
||||||
|
if (vars[i].init != NULL) {
|
||||||
|
printf(" = ");
|
||||||
|
vars[i].init->Print();
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,9 +411,9 @@ DeclStmt::Print(int indent) const {
|
|||||||
int
|
int
|
||||||
DeclStmt::EstimateCost() const {
|
DeclStmt::EstimateCost() const {
|
||||||
int cost = 0;
|
int cost = 0;
|
||||||
for (unsigned int i = 0; i < declaration->declarators.size(); ++i)
|
for (unsigned int i = 0; i < vars.size(); ++i)
|
||||||
if (declaration->declarators[i]->initExpr)
|
if (vars[i].init != NULL)
|
||||||
cost += declaration->declarators[i]->initExpr->EstimateCost();
|
cost += vars[i].init->EstimateCost();
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,8 +718,8 @@ lSafeToRunWithAllLanesOff(Stmt *stmt) {
|
|||||||
|
|
||||||
DeclStmt *ds;
|
DeclStmt *ds;
|
||||||
if ((ds = dynamic_cast<DeclStmt *>(stmt)) != NULL) {
|
if ((ds = dynamic_cast<DeclStmt *>(stmt)) != NULL) {
|
||||||
for (unsigned int i = 0; i < ds->declaration->declarators.size(); ++i)
|
for (unsigned int i = 0; i < ds->vars.size(); ++i)
|
||||||
if (!lSafeToRunWithAllLanesOff(ds->declaration->declarators[i]->initExpr))
|
if (!lSafeToRunWithAllLanesOff(ds->vars[i].init))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
12
stmt.h
12
stmt.h
@@ -82,11 +82,19 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VariableDeclaration {
|
||||||
|
VariableDeclaration(Symbol *s = NULL, Expr *i = NULL) {
|
||||||
|
sym = s; init = i;
|
||||||
|
}
|
||||||
|
Symbol *sym;
|
||||||
|
Expr *init;
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief Statement representing a single declaration (which in turn may declare
|
/** @brief Statement representing a single declaration (which in turn may declare
|
||||||
a number of variables. */
|
a number of variables. */
|
||||||
class DeclStmt : public Stmt {
|
class DeclStmt : public Stmt {
|
||||||
public:
|
public:
|
||||||
DeclStmt(SourcePos pos, Declaration *declaration, SymbolTable *symbolTable);
|
DeclStmt(const std::vector<VariableDeclaration> &v, SourcePos pos);
|
||||||
|
|
||||||
void EmitCode(FunctionEmitContext *ctx) const;
|
void EmitCode(FunctionEmitContext *ctx) const;
|
||||||
void Print(int indent) const;
|
void Print(int indent) const;
|
||||||
@@ -95,7 +103,7 @@ public:
|
|||||||
Stmt *TypeCheck();
|
Stmt *TypeCheck();
|
||||||
int EstimateCost() const;
|
int EstimateCost() const;
|
||||||
|
|
||||||
Declaration *declaration;
|
std::vector<VariableDeclaration> vars;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user