Example #1
0
void
OSLCompilerImpl::write_oso_symbol (const Symbol *sym)
{
    // symtype / datatype / name
    oso ("%s\t%s\t%s", sym->symtype_shortname(),
         type_c_str(sym->typespec()), sym->mangled().c_str());

    ASTvariable_declaration *v = NULL;
    if (sym->node() && sym->node()->nodetype() == ASTNode::variable_declaration_node)
        v = static_cast<ASTvariable_declaration *>(sym->node());

    // Print default values
    bool isparam = (sym->symtype() == SymTypeParam ||
                    sym->symtype() == SymTypeOutputParam);
    if (sym->symtype() == SymTypeConst) {
        oso ("\t");
        write_oso_const_value (static_cast<const ConstantSymbol *>(sym));
        oso ("\t");
    } else if (v && isparam) {
        std::string out;
        v->param_default_literals (sym, out);
        oso ("\t%s\t", out.c_str());
    }

    //
    // Now output all the hints, which is most of the work!
    //

    int hints = 0;

    // %meta{} encodes metadata (handled by write_oso_metadata)
    if (v) {
        ASSERT (v);
        for (ASTNode::ref m = v->meta();  m;  m = m->next()) {
            if (hints++ == 0)
                oso ("\t");
            write_oso_metadata (m.get());
        }
    }

    // %read and %write give the range of ops over which a symbol is used.
    if (hints++ == 0)
        oso ("\t");
    oso (" %%read{%d,%d} %%write{%d,%d}", sym->firstread(), sym->lastread(),
         sym->firstwrite(), sym->lastwrite());

    // %struct, %structfields, and %structfieldtypes document the
    // definition of a structure and which other symbols comprise the
    // individual fields.
    if (sym->typespec().is_structure()) {
        if (hints++ == 0)
            oso ("\t");
        const StructSpec *structspec (sym->typespec().structspec());
        std::string fieldlist, signature;
        for (int i = 0;  i < (int)structspec->numfields();  ++i) {
            if (i > 0)
                fieldlist += ",";
            fieldlist += structspec->field(i).name.string();
            signature += code_from_type (structspec->field(i).type);
        }
        oso (" %%struct{\"%s\"} %%structfields{%s} %%structfieldtypes{\"%s\"} %%structnfields{%d}",
             structspec->mangled().c_str(), fieldlist.c_str(),
             signature.c_str(), structspec->numfields());
    }
    // %mystruct and %mystructfield document the symbols holding structure
    // fields, linking them back to the structures they are part of.
    if (sym->fieldid() >= 0) {
        if (hints++ == 0)
            oso ("\t");
        ASTvariable_declaration *vd = (ASTvariable_declaration *) sym->node();
        oso (" %%mystruct{%s} %%mystructfield{%d}",
             vd->sym()->mangled().c_str(), sym->fieldid());
    }

    // %derivs hint marks symbols that need to carry derivatives
    if (sym->has_derivs()) {
        if (hints++ == 0)
            oso ("\t");
        oso (" %%derivs");
    }

#if 0 // this is recomputed by the runtime optimizer, no need to bloat the .oso with these

    // %depends marks, for potential OUTPUTs, which symbols they depend
    // upon.  This is so that derivativeness, etc., may be
    // back-propagated as shader networks are linked together.
    if (isparam || sym->symtype() == SymTypeGlobal) {
        // FIXME
        const SymPtrSet &deps (m_symdeps[sym]);
        std::vector<const Symbol *> inputdeps;
        BOOST_FOREACH (const Symbol *d, deps)
            if (d->symtype() == SymTypeParam ||
                  d->symtype() == SymTypeOutputParam ||
                  d->symtype() == SymTypeGlobal ||
                  d->symtype() == SymTypeLocal ||
                  d->symtype() == SymTypeTemp)
                inputdeps.push_back (d);
        if (inputdeps.size()) {
            if (hints++ == 0)
                oso ("\t");
            oso (" %%depends{");
            int deps = 0;
            for (size_t i = 0;  i < inputdeps.size();  ++i) {
                if (inputdeps[i]->symtype() == SymTypeTemp &&
                    inputdeps[i]->dealias() != inputdeps[i])
                    continue;   // Skip aliased temporaries
                if (deps++)
                    oso (",");
                oso ("%s",  inputdeps[i]->mangled().c_str());
            }
            oso ("}");
        }
    }
#endif
    oso ("\n");
}
void
OSLCompilerImpl::write_oso_file (const std::string &outfilename,
                                 string_view options)
{
    ASSERT (m_osofile != NULL && m_osofile->good());
    oso ("OpenShadingLanguage %d.%02d\n",
         OSO_FILE_VERSION_MAJOR, OSO_FILE_VERSION_MINOR);
    oso ("# Compiled by oslc %s\n", OSL_LIBRARY_VERSION_STRING);
    oso ("# options: %s\n", options);

    ASTshader_declaration *shaderdecl = shader_decl();
    oso ("%s %s", shaderdecl->shadertypename(), 
         shaderdecl->shadername().c_str());

    // output global hints and metadata
    int hints = 0;
    for (ASTNode::ref m = shaderdecl->metadata();  m;  m = m->next()) {
        if (hints++ == 0)
            oso ("\t");
        write_oso_metadata (m.get());
    }

    oso ("\n");

    // Output params, so they are first
    BOOST_FOREACH (const Symbol *s, symtab()) {
        if (s->symtype() == SymTypeParam || s->symtype() == SymTypeOutputParam)
            write_oso_symbol (s);
    }
    // Output globals, locals, temps, const
    BOOST_FOREACH (const Symbol *s, symtab()) {
        if (s->symtype() == SymTypeLocal || s->symtype() == SymTypeTemp ||
            s->symtype() == SymTypeGlobal || s->symtype() == SymTypeConst) {
            // Don't bother writing symbols that are never used
            if (s->lastuse() >= 0) {
                write_oso_symbol (s);
            }
        }
    }

    // Output all opcodes
    int lastline = -1;
    ustring lastfile;
    ustring lastmethod ("___uninitialized___");
    for (OpcodeVec::iterator op = m_ircode.begin(); op != m_ircode.end();  ++op) {
        if (lastmethod != op->method()) {
            oso ("code %s\n", op->method().c_str());
            lastmethod = op->method();
            lastfile = ustring();
            lastline = -1;
        }

        if (/*m_debug &&*/ op->sourcefile()) {
            ustring file = op->sourcefile();
            int line = op->sourceline();
            if (file != lastfile || line != lastline)
                oso ("# %s:%d\n# %s\n", file.c_str(), line,
                     retrieve_source (file, line).c_str());
        }

        // Op name
        oso ("\t%s", op->opname().c_str());

        // Register arguments
        if (op->nargs())
            oso (op->opname().length() < 8 ? "\t\t" : "\t");
        for (int i = 0;  i < op->nargs();  ++i) {
            int arg = op->firstarg() + i;
            oso ("%s ", m_opargs[arg]->dealias()->mangled().c_str());
        }

        // Jump targets
        for (size_t i = 0;  i < Opcode::max_jumps;  ++i)
            if (op->jump(i) >= 0)
                oso ("%d ", op->jump(i));

        //
        // Opcode Hints
        //

        bool firsthint = true;

        // %filename and %line document the source code file and line that
        // contained code that generated this op.  To avoid clutter, we
        // only output these hints when they DIFFER from the previous op.
        if (op->sourcefile()) {
            if (op->sourcefile() != lastfile) {
                lastfile = op->sourcefile();
                oso ("%c%%filename{\"%s\"}", firsthint ? '\t' : ' ', lastfile.c_str());
                firsthint = false;
            }
            if (op->sourceline() != lastline) {
                lastline = op->sourceline();
                oso ("%c%%line{%d}", firsthint ? '\t' : ' ', lastline);
                firsthint = false;
            }
        }

        // %argrw documents which arguments are read, written, or both (rwW).
        if (op->nargs()) {
            oso ("%c%%argrw{\"", firsthint ? '\t' : ' ');
            for (int i = 0;  i < op->nargs();  ++i) {
                if (op->argwrite(i))
                    oso (op->argread(i) ? "W" : "w");
                else
                    oso (op->argread(i) ? "r" : "-");
            }
            oso ("\"}");
            firsthint = false;
        }

        // %argderivs documents which arguments have derivs taken of
        // them by the op.
        if (op->argtakesderivs_all()) {
            oso (" %%argderivs{");
            int any = 0;
            for (int i = 0;  i < op->nargs();  ++i)
                if (op->argtakesderivs(i)) {
                    if (any++)
                        oso (",");
                    oso ("%d", i);
                }
            oso ("}");
            firsthint = false;
        }

        oso ("\n");
    }

    if (lastmethod != main_method_name()) // If no code, still need a code marker
        oso ("code %s\n", main_method_name().c_str());

    oso ("\tend\n");
    m_osofile = NULL;
}