Пример #1
0
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);
}
Пример #2
0
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();
}
Пример #3
0
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);
}
Пример #4
0
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();
}
Пример #5
0
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()));
}
Пример #6
0
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);
    }
}
Пример #7
0
// 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;
                   });
}
Пример #8
0
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);
}
Пример #9
0
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?
}
Пример #10
0
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;
    }
}
Пример #11
0
 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;
 }
Пример #12
0
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();
}
Пример #13
0
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);
  }
}