Symbol table now properly handles scopes for function declarations.

Previously, they all went into one big pile that was never cleaned up;
this was the wrong thing to do in a world where one might have a 
function declaration inside another functions, say.
This commit is contained in:
Matt Pharr
2011-12-04 17:37:13 -08:00
parent 32904dfa11
commit f95504fb5e
7 changed files with 166 additions and 129 deletions

View File

@@ -824,10 +824,13 @@ llvm::Value *
FunctionEmitContext::LaneMask(llvm::Value *v) {
// Call the target-dependent movmsk function to turn the vector mask
// into an i32 value
std::vector<Symbol *> *mm = m->symbolTable->LookupFunction("__movmsk");
std::vector<Symbol *> mm;
m->symbolTable->LookupFunction("__movmsk", &mm);
// There should be one with signed int signature, one unsigned int.
assert(mm && mm->size() == 2);
llvm::Function *fmm = (*mm)[0]->function;
assert(mm.size() == 2);
// We can actually call either one, since both are i32s as far as
// LLVM's type system is concerned...
llvm::Function *fmm = mm[0]->function;
return CallInst(fmm, NULL, v, "val_movmsk");
}

View File

@@ -1537,10 +1537,10 @@ BinaryExpr::Optimize() {
Type::Equal(type1, AtomicType::UniformConstFloat) ||
Type::Equal(type1, AtomicType::VaryingConstFloat)) {
// Get the symbol for the appropriate builtin
std::vector<Symbol *> *rcpFuns =
m->symbolTable->LookupFunction("rcp");
if (rcpFuns != NULL) {
assert(rcpFuns->size() == 2);
std::vector<Symbol *> rcpFuns;
m->symbolTable->LookupFunction("rcp", &rcpFuns);
if (rcpFuns.size() > 0) {
assert(rcpFuns.size() == 2);
Expr *rcpSymExpr = new FunctionSymbolExpr("rcp", rcpFuns, pos);
ExprList *args = new ExprList(arg1, arg1->pos);
Expr *rcpCall = new FunctionCallExpr(rcpSymExpr, args,
@@ -6100,13 +6100,12 @@ SymbolExpr::Print() const {
// FunctionSymbolExpr
FunctionSymbolExpr::FunctionSymbolExpr(const char *n,
std::vector<Symbol *> *candidates,
const std::vector<Symbol *> &candidates,
SourcePos p)
: Expr(p) {
name = n;
candidateFunctions = candidates;
matchingFunc = (candidates && candidates->size() == 1) ?
(*candidates)[0] : NULL;
matchingFunc = (candidates.size() == 1) ? candidates[0] : NULL;
triedToResolve = false;
}
@@ -6457,12 +6456,12 @@ bool
FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *),
const std::vector<const Type *> &callTypes,
const std::vector<bool> *argCouldBeNULL) {
const char *funName = candidateFunctions->front()->name.c_str();
const char *funName = candidateFunctions.front()->name.c_str();
std::vector<std::pair<int, Symbol *> > matches;
std::vector<Symbol *>::iterator iter;
for (iter = candidateFunctions->begin();
iter != candidateFunctions->end(); ++iter) {
for (iter = candidateFunctions.begin();
iter != candidateFunctions.end(); ++iter) {
// Loop over the set of candidate functions and try each one
Symbol *candidateFunction = *iter;
const FunctionType *ft =
@@ -6588,10 +6587,10 @@ FunctionSymbolExpr::ResolveOverloads(const std::vector<const Type *> &argTypes,
}
// failure :-(
const char *funName = candidateFunctions->front()->name.c_str();
const char *funName = candidateFunctions.front()->name.c_str();
Error(pos, "Unable to find matching overload for call to function \"%s\"%s.",
funName, exactMatchOnly ? " only considering exact matches" : "");
lPrintFunctionOverloads(funName, *candidateFunctions);
lPrintFunctionOverloads(funName, candidateFunctions);
lPrintPassedTypes(funName, argTypes);
return false;
}

4
expr.h
View File

@@ -613,7 +613,7 @@ private:
*/
class FunctionSymbolExpr : public Expr {
public:
FunctionSymbolExpr(const char *name, std::vector<Symbol *> *candidateFunctions,
FunctionSymbolExpr(const char *name, const std::vector<Symbol *> &candFuncs,
SourcePos pos);
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
@@ -649,7 +649,7 @@ private:
/** All of the functions with the name given in the function call;
there may be more then one, in which case we need to resolve which
overload is the best match. */
std::vector<Symbol *> *candidateFunctions;
std::vector<Symbol *> candidateFunctions;
/** The actual matching function found after overload resolution. */
Symbol *matchingFunc;

View File

@@ -226,7 +226,7 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
return;
}
if (symbolTable->LookupFunction(sym->name.c_str()) != NULL) {
if (symbolTable->LookupFunction(sym->name.c_str())) {
Error(sym->pos, "Global variable \"%s\" shadows previously-declared function.",
sym->name.c_str());
return;
@@ -400,11 +400,11 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
return;
}
std::vector<Symbol *> *overloadFuncs =
symbolTable->LookupFunction(funSym->name.c_str());
if (overloadFuncs != NULL) {
for (unsigned int i = 0; i < overloadFuncs->size(); ++i) {
Symbol *overloadFunc = (*overloadFuncs)[i];
std::vector<Symbol *> overloadFuncs;
symbolTable->LookupFunction(funSym->name.c_str(), &overloadFuncs);
if (overloadFuncs.size() > 0) {
for (unsigned int i = 0; i < overloadFuncs.size(); ++i) {
Symbol *overloadFunc = overloadFuncs[i];
// Check for a redeclaration of a function with the same
// name and type
@@ -444,21 +444,21 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
return;
}
std::vector<Symbol *> *funcs =
symbolTable->LookupFunction(funSym->name.c_str());
if (funcs != NULL) {
if (funcs->size() > 1) {
std::vector<Symbol *> funcs;
symbolTable->LookupFunction(funSym->name.c_str(), &funcs);
if (funcs.size() > 0) {
if (funcs.size() > 1) {
// Multiple functions with this name have already been declared;
// can't overload here
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; "
"%d functions with the same name have already been declared.",
funSym->name.c_str(), (int)funcs->size());
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))
if (Type::Equal(funcs[0]->type, funSym->type))
return;
else {
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".",
@@ -543,7 +543,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
#endif
}
if (symbolTable->LookupFunction(argName.c_str()) != NULL)
if (symbolTable->LookupFunction(argName.c_str()))
Warning(argPos, "Function parameter \"%s\" shadows a function "
"declared in global scope.", argName.c_str());

View File

@@ -246,8 +246,9 @@ primary_expression
if (s)
$$ = new SymbolExpr(s, @1);
else {
std::vector<Symbol *> *funs = m->symbolTable->LookupFunction(name);
if (funs)
std::vector<Symbol *> funs;
m->symbolTable->LookupFunction(name, &funs);
if (funs.size() > 0)
$$ = new FunctionSymbolExpr(name, funs, @1);
}
if ($$ == NULL) {

160
sym.cpp
View File

@@ -72,23 +72,30 @@ SymbolTable::SymbolTable() {
SymbolTable::~SymbolTable() {
// Otherwise we have mismatched push/pop scopes
assert(variables.size() == 1 && types.size() == 1);
assert(variables.size() == 1 && functions.size() == 1 &&
types.size() == 1);
PopScope();
}
void
SymbolTable::PushScope() {
variables.push_back(new std::vector<Symbol *>);
variables.push_back(new SymbolMapType);
functions.push_back(new FunctionMapType);
types.push_back(new TypeMapType);
}
void
SymbolTable::PopScope() {
// FIXME: delete Symbols in variables vector<>...
assert(variables.size() > 1);
delete variables.back();
variables.pop_back();
assert(functions.size() > 1);
delete functions.back();
functions.pop_back();
assert(types.size() > 1);
delete types.back();
types.pop_back();
@@ -101,48 +108,44 @@ SymbolTable::AddVariable(Symbol *symbol) {
// Check to see if a symbol of the same name has already been declared.
for (int i = (int)variables.size() - 1; i >= 0; --i) {
std::vector<Symbol *> &sv = *(variables[i]);
for (int j = (int)sv.size() - 1; j >= 0; --j) {
if (sv[j]->name == symbol->name) {
if (i == (int)variables.size()-1) {
// If a symbol of the same name was declared in the
// same scope, it's an error.
Error(symbol->pos, "Ignoring redeclaration of symbol \"%s\".",
symbol->name.c_str());
return false;
}
else {
// Otherwise it's just shadowing something else, which
// is legal but dangerous..
Warning(symbol->pos,
"Symbol \"%s\" shadows symbol declared in outer scope.",
symbol->name.c_str());
variables.back()->push_back(symbol);
return true;
}
SymbolMapType &sm = *(variables[i]);
if (sm.find(symbol->name) != sm.end()) {
if (i == (int)variables.size()-1) {
// If a symbol of the same name was declared in the
// same scope, it's an error.
Error(symbol->pos, "Ignoring redeclaration of symbol \"%s\".",
symbol->name.c_str());
return false;
}
else {
// Otherwise it's just shadowing something else, which
// is legal but dangerous..
Warning(symbol->pos,
"Symbol \"%s\" shadows symbol declared in outer scope.",
symbol->name.c_str());
(*variables.back())[symbol->name] = symbol;
return true;
}
}
}
// No matches, so go ahead and add it...
variables.back()->push_back(symbol);
(*variables.back())[symbol->name] = symbol;
return true;
}
Symbol *
SymbolTable::LookupVariable(const char *name) {
// Note that we iterate through the variables vectors backwards, sinec
// Note that we iterate through the variables vectors backwards, since
// we want to search from the innermost scope to the outermost, so that
// we get the right symbol if we have multiple variables in different
// scopes that shadow each other.
std::vector<std::vector<Symbol *> *>::reverse_iterator liter = variables.rbegin();
while (liter != variables.rend()) {
std::vector<Symbol *> &sv = *(*liter);
for (int i = (int)sv.size() - 1; i >= 0; --i)
if (sv[i]->name == name)
return sv[i];
++liter;
for (int i = (int)variables.size() - 1; i >= 0; --i) {
SymbolMapType &sm = *(variables[i]);
SymbolMapType::iterator iter = sm.find(name);
if (iter != sm.end())
return iter->second;
}
return NULL;
}
@@ -157,28 +160,44 @@ SymbolTable::AddFunction(Symbol *symbol) {
// the symbol table
return false;
functions[symbol->name].push_back(symbol);
std::vector<Symbol *> &funOverloads = (*functions.back())[symbol->name];
funOverloads.push_back(symbol);
return true;
}
std::vector<Symbol *> *
SymbolTable::LookupFunction(const char *name) {
if (functions.find(name) != functions.end())
return &functions[name];
return NULL;
bool
SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
for (int i = (int)functions.size() - 1; i >= 0; --i) {
FunctionMapType &fm = *(functions[i]);
FunctionMapType::iterator iter = fm.find(name);
if (iter != fm.end()) {
if (matches == NULL)
return true;
else {
const std::vector<Symbol *> &funcs = iter->second;
for (int j = 0; j < (int)funcs.size(); ++j)
matches->push_back(funcs[j]);
}
}
}
return matches ? (matches->size() > 0) : false;
}
Symbol *
SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
if (functions.find(name) == functions.end())
return NULL;
std::vector<Symbol *> &funcs = functions[name];
for (unsigned int i = 0; i < funcs.size(); ++i)
if (Type::Equal(funcs[i]->type, type))
return funcs[i];
for (int i = (int)functions.size() - 1; i >= 0; --i) {
FunctionMapType &fm = *(functions[i]);
FunctionMapType::iterator iter = fm.find(name);
if (iter != fm.end()) {
std::vector<Symbol *> funcs = iter->second;
for (int j = 0; j < (int)funcs.size(); ++j) {
if (Type::Equal(funcs[j]->type, type))
return funcs[j];
}
}
}
return NULL;
}
@@ -232,19 +251,24 @@ SymbolTable::ClosestVariableOrFunctionMatch(const char *str) const {
std::vector<std::string> matches[maxDelta+1];
for (int i = 0; i < (int)variables.size(); ++i) {
std::vector<Symbol *> &sv = *(variables[i]);
for (int j = 0; j < (int)sv.size(); ++j) {
int dist = StringEditDistance(str, sv[j]->name, maxDelta+1);
const SymbolMapType &sv = *(variables[i]);
SymbolMapType::const_iterator iter;
for (iter = sv.begin(); iter != sv.end(); ++iter) {
const Symbol *sym = iter->second;
int dist = StringEditDistance(str, sym->name, maxDelta+1);
if (dist <= maxDelta)
matches[dist].push_back(sv[j]->name);
matches[dist].push_back(sym->name);
}
}
std::map<std::string, std::vector<Symbol *> >::const_iterator iter;
for (iter = functions.begin(); iter != functions.end(); ++iter) {
int dist = StringEditDistance(str, iter->first, maxDelta+1);
for (int i = 0; i < (int)functions.size(); ++i) {
const FunctionMapType &fm = *(functions[i]);
FunctionMapType::const_iterator iter;
for (iter = fm.begin(); iter != fm.end(); ++iter) {
int dist = StringEditDistance(str, iter->first, maxDelta+1);
if (dist <= maxDelta)
matches[dist].push_back(iter->first);
}
}
// Now, return the first entry of matches[] that is non-empty, if any.
@@ -308,29 +332,29 @@ void
SymbolTable::Print() {
int depth = 0;
fprintf(stderr, "Variables:\n----------------\n");
std::vector<std::vector<Symbol *> *>::iterator liter = variables.begin();
while (liter != variables.end()) {
fprintf(stderr, "%*c", depth, ' ');
std::vector<Symbol *>::iterator siter = (*liter)->begin();
while (siter != (*liter)->end()) {
fprintf(stderr, "%s [%s]", (*siter)->name.c_str(),
(*siter)->type->GetString().c_str());
++siter;
for (int i = 0; i < (int)variables.size(); ++i) {
SymbolMapType &sm = *(variables[i]);
SymbolMapType::iterator iter;
for (iter = sm.begin(); iter != sm.end(); ++iter) {
fprintf(stderr, "%*c", depth, ' ');
Symbol *sym = iter->second;
fprintf(stderr, "%s [%s]", sym->name.c_str(),
sym->type->GetString().c_str());
}
++liter;
fprintf(stderr, "\n");
depth += 4;
}
fprintf(stderr, "Functions:\n----------------\n");
std::map<std::string, std::vector<Symbol *> >::iterator fiter;
fiter = functions.begin();
while (fiter != functions.end()) {
fprintf(stderr, "%s\n", fiter->first.c_str());
std::vector<Symbol *> &syms = fiter->second;
for (unsigned int i = 0; i < syms.size(); ++i)
fprintf(stderr, " %s\n", syms[i]->type->GetString().c_str());
++fiter;
for (int i = 0; i < (int)functions.size(); ++i) {
FunctionMapType::iterator fiter = functions[i]->begin();
while (fiter != functions[i]->end()) {
fprintf(stderr, "%s\n", fiter->first.c_str());
std::vector<Symbol *> &syms = fiter->second;
for (unsigned int j = 0; j < syms.size(); ++j)
fprintf(stderr, " %s\n", syms[j]->type->GetString().c_str());
++fiter;
}
}
depth = 0;

68
sym.h
View File

@@ -169,11 +169,11 @@ public:
/** Looks for the function or functions with the given name in the
symbol name. If a function has been overloaded and multiple
definitions are present for a given function name, all of them will
be returned and it's up the the caller to resolve which one (if
any) to use.
@return vector of Symbol pointers to functions with the given name. */
std::vector<Symbol *> *LookupFunction(const char *name);
be returned in the provided vector and it's up the the caller to
resolve which one (if any) to use. Returns true if any matches
were found. */
bool LookupFunction(const char *name,
std::vector<Symbol *> *matches = NULL);
/** Looks for a function with the given name and type
in the symbol table.
@@ -248,24 +248,27 @@ private:
std::vector<std::string> closestTypeMatch(const char *str,
bool structsVsEnums) const;
/** This member variable holds one \c vector of Symbol pointers for
each of the current active scopes as the program is being parsed.
New vectors of symbols are added and removed from the end of the
main vector, so searches for symbols start looking at the end of \c
variables and work backwards.
/** This member variable holds one SymbolMap for each of the current
active scopes as the program is being parsed. New maps are added
and removed from the end of the main vector, so searches for
symbols start looking at the end of \c variables and work
backwards.
*/
std::vector<std::vector<Symbol *> *> variables;
/** Because there is no scoping for function symbols, functions are
represented with a single STL \c map from names to symbols. A STL
\c vector is used to store the function symbols for a given name
since, due to function overloading, a name can have multiple
function symbols associated with it. */
std::map<std::string, std::vector<Symbol *> > functions;
typedef std::map<std::string, const Type *> TypeMapType;
/** Like variables, type definitions can be scoped. A new \c TypeMapType
typedef std::map<std::string, Symbol *> SymbolMapType;
std::vector<SymbolMapType *> variables;
/** Function declarations are also scoped., A STL \c vector is used to
store the function symbols for a given name since, due to function
overloading, a name can have multiple function symbols associated
with it. */
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
std::vector<FunctionMapType *> functions;
/** Type definitions can also be scoped. A new \c TypeMapType
is added to the back of the \c types \c vector each time a new scope
is entered. (And it's removed when the scope exits).
*/
typedef std::map<std::string, const Type *> TypeMapType;
std::vector<TypeMapType *> types;
};
@@ -275,12 +278,15 @@ SymbolTable::GetMatchingFunctions(Predicate pred,
std::vector<Symbol *> *matches) const {
// Iterate through all function symbols and apply the given predicate.
// If it returns true, add the Symbol * to the provided vector.
std::map<std::string, std::vector<Symbol *> >::const_iterator iter;
for (iter = functions.begin(); iter != functions.end(); ++iter) {
const std::vector<Symbol *> &syms = iter->second;
for (unsigned int i = 0; i < syms.size(); ++i) {
if (pred(syms[i]))
matches->push_back(syms[i]);
for (unsigned int i = 0; i < functions.size(); ++i) {
FunctionMapType &fm = *(functions[i]);
FunctionMapType::const_iterator iter;
for (iter = fm.begin(); iter != fm.end(); ++iter) {
const std::vector<Symbol *> &syms = iter->second;
for (unsigned int j = 0; j < syms.size(); ++j) {
if (pred(syms[j]))
matches->push_back(syms[j]);
}
}
}
}
@@ -289,10 +295,14 @@ SymbolTable::GetMatchingFunctions(Predicate pred,
template <typename Predicate> void
SymbolTable::GetMatchingVariables(Predicate pred,
std::vector<Symbol *> *matches) const {
for (unsigned int i = 0; i < variables.size(); ++i)
for (unsigned int j = 0; j < variables[i]->size(); ++j)
if (pred((*variables[i])[j]))
matches->push_back((*variables[i])[j]);
for (unsigned int i = 0; i < variables.size(); ++i) {
SymbolMapType &sm = *(variables[i]);
SymbolMapType::const_iterator iter;
for (iter = sm.begin(); iter != sm.end(); ++iter) {
if (pred(iter->second))
matches->push_back(iter->second);
}
}
}
#endif // ISPC_SYM_H