/// Are two symbols equivalent (from the point of view of merging /// shader instances)? Note that this is not a true ==, it ignores /// the m_data, m_node, and m_alias pointers! static bool equivalent (const Symbol &a, const Symbol &b) { // If they aren't used, don't consider them a mismatch if (! a.everused() && ! b.everused()) return true; // Different symbol types or data types are a mismatch if (a.symtype() != b.symtype() || a.typespec() != b.typespec()) return false; // Don't consider different names to be a mismatch if the symbol // is a temp or constant. if (a.symtype() != SymTypeTemp && a.symtype() != SymTypeConst && a.name() != b.name()) return false; // But constants had better match their values! if (a.symtype() == SymTypeConst && memcmp (a.data(), b.data(), a.typespec().simpletype().size())) return false; return a.has_derivs() == b.has_derivs() && a.lockgeom() == b.lockgeom() && a.valuesource() == b.valuesource() && a.fieldid() == b.fieldid() && a.initbegin() == b.initbegin() && a.initend() == b.initend() ; }
inline std::string print_vals (const Symbol &s) { std::stringstream out; TypeDesc t = s.typespec().simpletype(); int n = t.aggregate * t.numelements(); if (t.basetype == TypeDesc::FLOAT) { for (int j = 0; j < n; ++j) out << (j ? " " : "") << ((float *)s.data())[j]; } else if (t.basetype == TypeDesc::INT) { for (int j = 0; j < n; ++j) out << (j ? " " : "") << ((int *)s.data())[j]; } else if (t.basetype == TypeDesc::STRING) { for (int j = 0; j < n; ++j) out << (j ? " " : "") << "\"" << ((ustring *)s.data())[j] << "\""; } return out.str(); }
virtual Value* eval(Environment& env) { Symbol *symbol = dynamic_cast<Symbol*>(sym); if (symbol) { Value* be = bond->eval(env); env.bind(symbol->data(), be); return be->clone(); } else { return NULL; } }
void ShaderInstance::copy_code_from_master (ShaderGroup &group) { ASSERT (m_instops.empty() && m_instargs.empty()); // reserve with enough room for a few insertions m_instops.reserve (master()->m_ops.size()+10); m_instargs.reserve (master()->m_args.size()+10); m_instops = master()->m_ops; m_instargs = master()->m_args; // Copy the symbols from the master ASSERT (m_instsymbols.size() == 0 && "should not have copied m_instsymbols yet"); m_instsymbols = m_master->m_symbols; // Copy the instance override data // Also set the renderer_output flags where needed. ASSERT (m_instoverrides.size() == (size_t)std::max(0,lastparam())); ASSERT (m_instsymbols.size() >= (size_t)std::max(0,lastparam())); if (m_instoverrides.size()) { for (size_t i = 0, e = lastparam(); i < e; ++i) { Symbol *si = &m_instsymbols[i]; if (m_instoverrides[i].valuesource() == Symbol::DefaultVal) { // Fix the length of any default-value variable length array // parameters. if (si->typespec().is_unsized_array()) si->arraylen (si->initializers()); } else { if (m_instoverrides[i].arraylen()) si->arraylen (m_instoverrides[i].arraylen()); si->valuesource (m_instoverrides[i].valuesource()); si->connected_down (m_instoverrides[i].connected_down()); si->lockgeom (m_instoverrides[i].lockgeom()); si->dataoffset (m_instoverrides[i].dataoffset()); si->data (param_storage(i)); } if (shadingsys().is_renderer_output (layername(), si->name(), &group)) { si->renderer_output (true); renderer_outputs (true); } } } evaluate_writes_globals_and_userdata_params (); off_t symmem = vectorbytes(m_instsymbols) - vectorbytes(m_instoverrides); SymOverrideInfoVec().swap (m_instoverrides); // free it // adjust stats { spin_lock lock (shadingsys().m_stat_mutex); shadingsys().m_stat_mem_inst_syms += symmem; shadingsys().m_stat_mem_inst += symmem; shadingsys().m_stat_memory += symmem; } }
void ShaderInstance::copy_code_from_master () { ASSERT (m_instops.empty() && m_instargs.empty()); // reserve with enough room for a few insertions m_instops.reserve (master()->m_ops.size()+10); m_instargs.reserve (master()->m_args.size()+10); m_instops = master()->m_ops; m_instargs = master()->m_args; // Copy the symbols from the master ASSERT (m_instsymbols.size() == 0 && "should not have copied m_instsymbols yet"); m_instsymbols = m_master->m_symbols; // Copy the instance override data ASSERT (m_instoverrides.size() == (size_t)std::max(0,lastparam())); ASSERT (m_instsymbols.size() >= (size_t)std::max(0,lastparam())); if (m_instoverrides.size()) { for (size_t i = 0, e = lastparam(); i < e; ++i) { if (m_instoverrides[i].valuesource() != Symbol::DefaultVal) { Symbol *si = &m_instsymbols[i]; si->data (param_storage(i)); si->valuesource (m_instoverrides[i].valuesource()); si->connected_down (m_instoverrides[i].connected_down()); si->lockgeom (m_instoverrides[i].lockgeom()); } } } off_t symmem = vectorbytes(m_instsymbols) - vectorbytes(m_instoverrides); SymOverrideInfoVec().swap (m_instoverrides); // free it // adjust stats { spin_lock lock (shadingsys().m_stat_mutex); shadingsys().m_stat_mem_inst_syms += symmem; shadingsys().m_stat_mem_inst += symmem; shadingsys().m_stat_memory += symmem; } }
void BackendLLVM::llvm_assign_initial_value (const Symbol& sym) { // Don't write over connections! Connection values are written into // our layer when the earlier layer is run, as part of its code. So // we just don't need to initialize it here at all. if (sym.valuesource() == Symbol::ConnectedVal && !sym.typespec().is_closure_based()) return; if (sym.typespec().is_closure_based() && sym.symtype() == SymTypeGlobal) return; int arraylen = std::max (1, sym.typespec().arraylength()); // Closures need to get their storage before anything can be // assigned to them. Unless they are params, in which case we took // care of it in the group entry point. if (sym.typespec().is_closure_based() && sym.symtype() != SymTypeParam && sym.symtype() != SymTypeOutputParam) { llvm_assign_zero (sym); return; } if ((sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp) && shadingsys().debug_uninit()) { // Handle the "debug uninitialized values" case bool isarray = sym.typespec().is_array(); int alen = isarray ? sym.typespec().arraylength() : 1; llvm::Value *u = NULL; if (sym.typespec().is_closure_based()) { // skip closures } else if (sym.typespec().is_floatbased()) u = ll.constant (std::numeric_limits<float>::quiet_NaN()); else if (sym.typespec().is_int_based()) u = ll.constant (std::numeric_limits<int>::min()); else if (sym.typespec().is_string_based()) u = ll.constant (Strings::uninitialized_string); if (u) { for (int a = 0; a < alen; ++a) { llvm::Value *aval = isarray ? ll.constant(a) : NULL; for (int c = 0; c < (int)sym.typespec().aggregate(); ++c) llvm_store_value (u, sym, 0, aval, c); } } return; } if ((sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp) && sym.typespec().is_string_based()) { // Strings are pointers. Can't take any chance on leaving // local/tmp syms uninitialized. llvm_assign_zero (sym); return; // we're done, the parts below are just for params } ASSERT_MSG (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam, "symtype was %d, data type was %s", (int)sym.symtype(), sym.typespec().c_str()); if (sym.has_init_ops() && sym.valuesource() == Symbol::DefaultVal) { // Handle init ops. build_llvm_code (sym.initbegin(), sym.initend()); } else if (! sym.lockgeom() && ! sym.typespec().is_closure()) { // geometrically-varying param; memcpy its default value TypeDesc t = sym.typespec().simpletype(); ll.op_memcpy (llvm_void_ptr (sym), ll.constant_ptr (sym.data()), t.size(), t.basesize() /*align*/); if (sym.has_derivs()) llvm_zero_derivs (sym); } else { // Use default value int num_components = sym.typespec().simpletype().aggregate; TypeSpec elemtype = sym.typespec().elementtype(); for (int a = 0, c = 0; a < arraylen; ++a) { llvm::Value *arrind = sym.typespec().is_array() ? ll.constant(a) : NULL; if (sym.typespec().is_closure_based()) continue; for (int i = 0; i < num_components; ++i, ++c) { // Fill in the constant val llvm::Value* init_val = 0; if (elemtype.is_floatbased()) init_val = ll.constant (((float*)sym.data())[c]); else if (elemtype.is_string()) init_val = ll.constant (((ustring*)sym.data())[c]); else if (elemtype.is_int()) init_val = ll.constant (((int*)sym.data())[c]); ASSERT (init_val); llvm_store_value (init_val, sym, 0, arrind, i); } } if (sym.has_derivs()) llvm_zero_derivs (sym); } // Handle interpolated params. // FIXME -- really, we shouldn't assign defaults or run init ops if // the values are interpolated. The perf hit is probably small, since // there are so few interpolated params, but we should come back and // fix this later. if ((sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) && ! sym.lockgeom()) { std::vector<llvm::Value*> args; args.push_back (sg_void_ptr()); args.push_back (ll.constant (sym.name())); args.push_back (ll.constant (sym.typespec().simpletype())); args.push_back (ll.constant ((int) sym.has_derivs())); args.push_back (llvm_void_ptr (sym)); ll.call_function ("osl_bind_interpolated_param", &args[0], args.size()); } }
void RuntimeOptimizer::llvm_assign_initial_value (const Symbol& sym) { // Don't write over connections! Connection values are written into // our layer when the earlier layer is run, as part of its code. So // we just don't need to initialize it here at all. if (sym.valuesource() == Symbol::ConnectedVal && !sym.typespec().is_closure_based()) return; if (sym.typespec().is_closure_based() && sym.symtype() == SymTypeGlobal) return; int arraylen = std::max (1, sym.typespec().arraylength()); // Closures need to get their storage before anything can be // assigned to them. Unless they are params, in which case we took // care of it in the group entry point. if (sym.typespec().is_closure_based() && sym.symtype() != SymTypeParam && sym.symtype() != SymTypeOutputParam) { llvm_assign_zero (sym); } if (sym.symtype() != SymTypeParam && sym.symtype() != SymTypeOutputParam && sym.symtype() != SymTypeConst && sym.typespec().is_string_based()) { // Strings are pointers. Can't take any chance on leaving local/tmp // syms uninitialized. DASSERT (sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp); llvm_assign_zero (sym); return; // we're done, the parts below are just for params } if (sym.has_init_ops() && sym.valuesource() == Symbol::DefaultVal) { // Handle init ops. build_llvm_code (sym.initbegin(), sym.initend()); } else { // Use default value int num_components = sym.typespec().simpletype().aggregate; for (int a = 0, c = 0; a < arraylen; ++a) { llvm::Value *arrind = sym.typespec().is_array() ? llvm_constant(a) : NULL; if (sym.typespec().is_closure_based()) continue; for (int i = 0; i < num_components; ++i, ++c) { // Fill in the constant val llvm::Value* init_val = 0; TypeSpec elemtype = sym.typespec().elementtype(); if (elemtype.is_floatbased()) init_val = llvm_constant (((float*)sym.data())[c]); else if (elemtype.is_string()) init_val = llvm_constant (((ustring*)sym.data())[c]); else if (elemtype.is_int()) init_val = llvm_constant (((int*)sym.data())[c]); ASSERT (init_val); llvm_store_value (init_val, sym, 0, arrind, i); } } if (sym.has_derivs()) llvm_zero_derivs (sym); } // Handle interpolated params. // FIXME -- really, we shouldn't assign defaults or run init ops if // the values are interpolated. The perf hit is probably small, since // there are so few interpolated params, but we should come back and // fix this later. if ((sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) && ! sym.lockgeom()) { std::vector<llvm::Value*> args; args.push_back (sg_void_ptr()); args.push_back (llvm_constant (sym.name())); args.push_back (llvm_constant (sym.typespec().simpletype())); args.push_back (llvm_constant ((int) sym.has_derivs())); args.push_back (llvm_void_ptr (sym)); llvm_call_function ("osl_bind_interpolated_param", &args[0], args.size()); } }