void NameResolver::registerFunction(FunctionSymbol *sym) { Scope *scope = sym->scope(); assert(scope == globals_); Symbol *other = scope->localLookup(sym->name()); if (!other) { scope->addSymbol(sym); return; } // If |other| is not a function, it's an error. FunctionSymbol *orig = other->asFunction(); if (!orig) { reportRedeclaration(sym, other); return; } // If both have bodies, it's an error. FunctionStatement *sym_node = sym->node()->toFunctionStatement(); FunctionStatement *orig_node = orig->node()->toFunctionStatement(); if (sym_node->body() && orig_node->body()) { reportRedeclaration(sym, other); return; } // Build a shadow list, containing all symbols with this name. orig->addShadow(orig_node); orig->addShadow(sym_node); sym_node->setShadowed(orig); }
void StrPrinter::bvisit(const FunctionSymbol &x) { std::ostringstream o; o << x.get_name(); o << "("; vec_basic vec = x.get_args(); o << this->apply(vec) << ")"; str_ = o.str(); }
void SemanticAnalysis::visitFunctionStatement(FunctionStatement *node) { FunctionSymbol *sym = node->sym(); if (!funcstate_ && sym->shadows()) { // We are the root in a series of shadowed functions. analyzeShadowedFunctions(sym); } if (!node->body()) return; FuncState state(&funcstate_, node); node->body()->accept(this); }
TypeSpec ASTfunction_call::typecheck_all_poly (TypeSpec expected, bool coerce) { for (FunctionSymbol *poly = func(); poly; poly = poly->nextpoly()) { const char *code = poly->argcodes().c_str(); int advance; TypeSpec returntype = m_compiler->type_from_code (code, &advance); code += advance; if (check_arglist (m_name.c_str(), args(), code, coerce)) { // Return types also must match if not coercible if (coerce || expected == TypeSpec() || expected == returntype) { m_sym = poly; return returntype; } } } return TypeSpec(); }
TEST_F(SymbolTest, testClassSymbol) { DataType* data_type = class_->getDataType(); ASSERT_NE(nullptr, data_type); ASSERT_EQ(DataType::DATA_TYPE_CLASS, data_type->getType()); ClassType* type = dynamic_cast<ClassType*>(data_type); ASSERT_NE(nullptr, type); EXPECT_EQ(class_.get(), type->getClassSymbol()); VariableSymbol* v1 = new VariableSymbol("v1"); v1->setDataType(DataTypeFactory::getInt32Type()); class_->addVariable(v1); VariableSymbol* v2 = new VariableSymbol("v2"); v2->setDataType(DataTypeFactory::getStringType()); class_->addVariable(v2); const auto& actual_vars = class_->getVariables(); std::vector<VariableSymbol*> expected_vars {v1, v2}; EXPECT_EQ(expected_vars, actual_vars); FunctionSymbol* f = new FunctionSymbol("f"); f->setReturnType(DataTypeFactory::getCharType()); class_->addFunction(f); const auto& actual_funcs = class_->getFunctions(); std::vector<FunctionSymbol*> expected_funcs {f}; EXPECT_EQ(expected_funcs, actual_funcs); Scope* scope = class_->getScope(); ASSERT_NE(nullptr, scope); EXPECT_FALSE(scope->isOwnedBySymbolTable()); EXPECT_EQ(class_->getName(), scope->getName()); EXPECT_EQ(4, scope->getSize()); EXPECT_EQ(v1, scope->lookup(v1->getName())); EXPECT_EQ(v2, scope->lookup(v2->getName())); EXPECT_EQ(f, scope->lookup(f->getName())); EXPECT_EQ(class_.get(), scope->lookup(class_->getName())); ClassSymbol super_class("super"); class_->setSuperClass(&super_class); EXPECT_EQ(super_class.getScope(), scope->getParent()); EXPECT_EQ(&super_class, scope->lookup(super_class.getName())); }
void SemanticAnalysis::visitNameProxy(NameProxy *proxy) { Symbol *binding = proxy->sym(); switch (binding->kind()) { case Symbol::kType: cc_.report(proxy->loc(), rmsg::cannot_use_type_as_value) << binding->asType()->type(); break; case Symbol::kConstant: { ConstantSymbol *sym = binding->toConstant(); proxy->setOutput(sym->type(), VK::rvalue); break; } case Symbol::kFunction: { FunctionSymbol *sym = binding->toFunction(); FunctionStatement *decl = sym->impl(); if (!decl) { cc_.report(proxy->loc(), rmsg::function_has_no_impl) << sym->name(); break; } if (!decl->type()) decl->setType(FunctionType::New(decl->signature())); // Function symbols are clvalues, since they are named. // :TODO: proxy->setOutput(decl->type(), VK::lvalue); break; } default: assert(false); } }
// Populate InitFunctions vector with init functions from all input objects. // This is then used either when creating the output linking section or to // synthesize the "__wasm_call_ctors" function. void Writer::calculateInitFunctions() { if (!Config->Relocatable && !WasmSym::CallCtors->isLive()) return; for (ObjFile *File : Symtab->ObjectFiles) { const WasmLinkingData &L = File->getWasmObj()->linkingData(); for (const WasmInitFunc &F : L.InitFunctions) { FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol); assert(Sym->isLive()); if (*Sym->Signature != WasmSignature{{}, {}}) error("invalid signature for init func: " + toString(*Sym)); InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority}); } } // Sort in order of priority (lowest first) so that they are called // in the correct order. std::stable_sort(InitFunctions.begin(), InitFunctions.end(), [](const WasmInitEntry &L, const WasmInitEntry &R) { return L.Priority < R.Priority; }); }
void BasicScope::declareFunction(FunctionSymbol *function){ //cout << "Ololo!"; string name = function->getName(); if(this->isFunction(name)){ //cout << "###__"; FunctionSymbol *tmp = dynamic_cast<FunctionSymbol*>(this->resolveFunction(function)); if(!tmp){ addFunction(name, function); } else if(!tmp->isOnlyDeclared()){ throw NoticeException("Function '" + name + "' redeclaration, previously defined at " + tmp->getPosition().toString()); } return; } if(this->isDefined(name)){ throw NoticeException("Trying to redeclare '" + name + "' as function!"); } addFunction(name, function); }
TypeSpec ASTreturn_statement::typecheck (TypeSpec expected) { FunctionSymbol *myfunc = oslcompiler->current_function (); if (myfunc) { // If it's a user function (as opposed to a main shader body)... if (expr()) { // If we are returning a value, it must be assignable to the // kind of type the function actually returns. This check // will also catch returning a value from a void function. TypeSpec et = expr()->typecheck (myfunc->typespec()); if (! assignable (myfunc->typespec(), et)) { error ("Cannot return a '%s' from '%s %s()'", type_c_str(et), type_c_str(myfunc->typespec()), myfunc->name().c_str()); } } else { // If we are not returning a value, it must be a void function. if (! myfunc->typespec().is_void ()) error ("You must return a '%s' from function '%s'", type_c_str(myfunc->typespec()), myfunc->name().c_str()); } // If the function has other statements AFTER 'return', or if // the return statement is in a conditional, we'll need to // handle it specially when generating code. myfunc->complex_return (this->nextptr() != NULL || myfunc->nesting_level() > 0); } else { // We're not part of any user function, so this 'return' must // be from the main shader body. That's fine (it's equivalent // to calling exit()), but it can't return a value. if (expr()) error ("Cannot return a value from a shader body"); } return TypeSpec(); // TODO: what should be returned here? }
void OSLCompilerImpl::initialize_builtin_funcs () { for (int i = 0; builtin_func_args[i]; ++i) { ustring funcname (builtin_func_args[i++]); // Count the number of polymorphic versions and look for any // special hint markers. int npoly = 0; bool readwrite_special_case = false; bool texture_args = false; bool printf_args = false; bool takes_derivs = false; for (npoly = 0; builtin_func_args[i+npoly]; ++npoly) { if (! strcmp (builtin_func_args[i+npoly], "!rw")) readwrite_special_case = true; else if (! strcmp (builtin_func_args[i+npoly], "!tex")) texture_args = true; else if (! strcmp (builtin_func_args[i+npoly], "!printf")) printf_args = true; else if (! strcmp (builtin_func_args[i+npoly], "!deriv")) takes_derivs = true; } // Now add them in reverse order, so the order in the table is // the priority order for approximate matches. for (int j = npoly-1; j >= 0; --j) { if (builtin_func_args[i+j][0] == '!') // Skip special hints continue; ustring poly (builtin_func_args[i+j]); Symbol *last = symtab().clash (funcname); ASSERT (last == NULL || last->symtype() == SymTypeFunction); TypeSpec rettype = type_from_code (poly.c_str()); FunctionSymbol *f = new FunctionSymbol (funcname, rettype); f->nextpoly ((FunctionSymbol *)last); f->argcodes (poly); f->readwrite_special_case (readwrite_special_case); f->texture_args (texture_args); f->printf_args (printf_args); f->takes_derivs (takes_derivs); symtab().insert (f); } i += npoly; } }
static RCP<const Basic> diff(const FunctionSymbol &self, const RCP<const Symbol> &x) { RCP<const Basic> diff = zero, t; RCP<const Basic> self_ = self.rcp_from_this(); RCP<const Symbol> s; std::string name; unsigned count = 0; bool found_x = false; for (const auto &a : self.get_args()) { if (eq(*a, *x)) { found_x = true; count++; } else if (count < 2 and neq(*a->diff(x), *zero)) { count++; } } if (count == 1 and found_x) { return Derivative::create(self_, {x}); } for (unsigned i = 0; i < self.get_args().size(); i++) { t = self.get_args()[i]->diff(x); if (neq(*t, *zero)) { name = "x"; do { name = "_" + name; s = symbol(name); } while (has_symbol(*self_, s)); vec_basic v = self.get_args(); v[i] = s; map_basic_basic m; insert(m, v[i], self.get_args()[i]); diff = add(diff, mul(t, make_rcp<const Subs>(Derivative::create(self.create(v), {v[i]}), m))); } } return diff; }
TypeSpec ASTfunction_call::typecheck (TypeSpec expected) { typecheck_children (); bool match = false; // Look for an exact match, including expected return type m_typespec = typecheck_all_poly (expected, false); if (m_typespec != TypeSpec()) match = true; // Now look for an exact match on args, but any assignable return type if (! match && expected != TypeSpec()) { m_typespec = typecheck_all_poly (TypeSpec(), false); if (m_typespec != TypeSpec()) match = true; } // Now look for a coercible match of args, exact march on return type if (! match) { m_typespec = typecheck_all_poly (expected, true); if (m_typespec != TypeSpec()) match = true; } // All that failed, try for a coercible match on everything if (! match && expected != TypeSpec()) { m_typespec = typecheck_all_poly (TypeSpec(), true); if (m_typespec != TypeSpec()) match = true; } if (match) { if (! is_user_function ()) typecheck_builtin_specialcase (); return m_typespec; } // Couldn't find any way to match any polymorphic version of the // function that we know about. OK, at least try for helpful error // message. std::string choices (""); for (FunctionSymbol *poly = func(); poly; poly = poly->nextpoly()) { const char *code = poly->argcodes().c_str(); int advance; TypeSpec returntype = m_compiler->type_from_code (code, &advance); code += advance; if (choices.length()) choices += "\n"; choices += Strutil::format ("\t%s %s (%s)", type_c_str(returntype), m_name.c_str(), m_compiler->typelist_from_code(code).c_str()); } std::string actualargs; for (ASTNode::ref arg = args(); arg; arg = arg->next()) { if (actualargs.length()) actualargs += ", "; actualargs += arg->typespec().string(); } error ("No matching function call to '%s (%s)'\n Candidates are:\n%s", m_name.c_str(), actualargs.c_str(), choices.c_str()); return TypeSpec(); }
void Writer::assignIndexes() { assert(InputFunctions.empty()); uint32_t FunctionIndex = NumImportedFunctions; auto AddDefinedFunction = [&](InputFunction *Func) { if (!Func->Live) return; InputFunctions.emplace_back(Func); Func->setFunctionIndex(FunctionIndex++); }; for (InputFunction *Func : Symtab->SyntheticFunctions) AddDefinedFunction(Func); for (ObjFile *File : Symtab->ObjectFiles) { LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); for (InputFunction *Func : File->Functions) AddDefinedFunction(Func); } uint32_t TableIndex = TableBase; auto HandleRelocs = [&](InputChunk *Chunk) { if (!Chunk->Live) return; ObjFile *File = Chunk->File; ArrayRef<WasmSignature> Types = File->getWasmObj()->types(); for (const WasmRelocation &Reloc : Chunk->getRelocations()) { if (Reloc.Type == R_WASM_TABLE_INDEX_I32 || Reloc.Type == R_WASM_TABLE_INDEX_SLEB) { FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); if (Sym->hasTableIndex() || !Sym->hasFunctionIndex()) continue; Sym->setTableIndex(TableIndex++); IndirectFunctions.emplace_back(Sym); } else if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) { // Mark target type as live File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); File->TypeIsUsed[Reloc.Index] = true; } } }; for (ObjFile *File : Symtab->ObjectFiles) { LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); for (InputChunk *Chunk : File->Functions) HandleRelocs(Chunk); for (InputChunk *Chunk : File->Segments) HandleRelocs(Chunk); for (auto &P : File->CustomSections) HandleRelocs(P); } assert(InputGlobals.empty()); uint32_t GlobalIndex = NumImportedGlobals; auto AddDefinedGlobal = [&](InputGlobal *Global) { if (Global->Live) { LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n"); Global->setGlobalIndex(GlobalIndex++); InputGlobals.push_back(Global); } }; for (InputGlobal *Global : Symtab->SyntheticGlobals) AddDefinedGlobal(Global); for (ObjFile *File : Symtab->ObjectFiles) { LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); for (InputGlobal *Global : File->Globals) AddDefinedGlobal(Global); } assert(InputEvents.empty()); uint32_t EventIndex = NumImportedEvents; auto AddDefinedEvent = [&](InputEvent *Event) { if (Event->Live) { LLVM_DEBUG(dbgs() << "AddDefinedEvent: " << EventIndex << "\n"); Event->setEventIndex(EventIndex++); InputEvents.push_back(Event); } }; for (ObjFile *File : Symtab->ObjectFiles) { LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n"); for (InputEvent *Event : File->Events) AddDefinedEvent(Event); } }