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; }