void ASTvariable_declaration::typecheck_initlist (ref init, TypeSpec type, const char *name) { // Loop over a list of initializers (it's just 1 if not an array)... for (int i = 0; init; init = init->next(), ++i) { // Check for too many initializers for an array if (type.is_array() && i > type.arraylength()) { error ("Too many initializers for a '%s'", type_c_str(type)); break; } // Special case: ok to assign a literal 0 to a closure to // initialize it. if (type.is_closure() && ! init->typespec().is_closure() && init->typespec().is_int_or_float() && init->nodetype() == literal_node && ((ASTliteral *)init.get())->floatval() == 0.0f) { continue; // it's ok } if (! type.is_array() && i > 0) error ("Can't assign array initializers to non-array %s %s", type_c_str(type), name); if (! assignable(type.elementtype(), init->typespec())) error ("Can't assign '%s' to %s %s", type_c_str(init->typespec()), type_c_str(type), name); } }
/// Return the symbol pointer to the individual field that this /// structselect represents; also set structid to the ID of the /// structure type, and fieldid to the field index within the struct. Symbol * ASTstructselect::find_fieldsym (int &structid, int &fieldid) { if (! lvalue()->typespec().is_structure() && ! lvalue()->typespec().is_structure_array()) { return NULL; } ustring structsymname; TypeSpec structtype; find_structsym (lvalue().get(), structsymname, structtype); structid = structtype.structure(); StructSpec *structspec (structtype.structspec()); fieldid = -1; for (int i = 0; i < (int)structspec->numfields(); ++i) { if (structspec->field(i).name == m_field) { fieldid = i; break; } } if (fieldid < 0) { error ("struct type '%s' does not have a member '%s'", structspec->name().c_str(), m_field.c_str()); return NULL; } const StructSpec::FieldSpec &fieldrec (structspec->field(fieldid)); ustring fieldsymname = ustring::format ("%s.%s", structsymname.c_str(), fieldrec.name.c_str()); Symbol *sym = m_compiler->symtab().find (fieldsymname); return sym; }
TypeSpec ASTunary_expression::typecheck (TypeSpec expected) { // FIXME - closures typecheck_children (expected); TypeSpec t = expr()->typespec(); if (t.is_structure()) { error ("Can't do '%s' to a %s.", opname(), type_c_str(t)); return TypeSpec (); } switch (m_op) { case Sub : case Add : if (t.is_string()) { error ("Can't do '%s' to a %s.", opname(), type_c_str(t)); return TypeSpec (); } m_typespec = t; break; case Not : m_typespec = TypeDesc::TypeInt; // ! is always an int break; case Compl : if (! t.is_int()) { error ("Operator '~' can only be done to an int"); return TypeSpec (); } m_typespec = t; break; default: error ("unknown unary operator"); } return m_typespec; }
TypeSpec ASTternary_expression::typecheck (TypeSpec expected) { // FIXME - closures TypeSpec c = typecheck_list (cond(), TypeDesc::TypeInt); TypeSpec t = typecheck_list (trueexpr(), expected); TypeSpec f = typecheck_list (falseexpr(), expected); if (c.is_closure()) error ("Cannot use a closure as a condition"); if (c.is_structure()) error ("Cannot use a struct as a condition"); if (c.is_array()) error ("Cannot use an array as a condition"); // No arrays if (t.is_array() || t.is_array()) { error ("Not allowed: '%s ? %s : %s'", type_c_str(c), type_c_str(t), type_c_str(f)); return TypeSpec (); } // The true and false clauses need to be equivalent types, or one // needs to be assignable to the other (so one can be upcast). if (assignable (t, f) || assignable (f, t)) m_typespec = higherprecision (t.simpletype(), f.simpletype()); else error ("Not allowed: '%s ? %s : %s'", type_c_str(c), type_c_str(t), type_c_str(f)); return m_typespec; }
TypeSpec OSLCompilerImpl::type_from_code (const char *code, int *advance) { TypeSpec t; int i = 0; switch (code[i]) { case 'i' : t = TypeDesc::TypeInt; break; case 'f' : t = TypeDesc::TypeFloat; break; case 'c' : t = TypeDesc::TypeColor; break; case 'p' : t = TypeDesc::TypePoint; break; case 'v' : t = TypeDesc::TypeVector; break; case 'n' : t = TypeDesc::TypeNormal; break; case 'm' : t = TypeDesc::TypeMatrix; break; case 's' : t = TypeDesc::TypeString; break; case 'x' : t = TypeDesc (TypeDesc::NONE); break; case 'X' : t = TypeDesc (TypeDesc::PTR); break; case 'L' : t = TypeDesc (TypeDesc::LONGLONG); break; case 'C' : // color closure t = TypeSpec (TypeDesc::TypeColor, true); break; case 'S' : // structure // Following the 'S' is the numeric structure ID t = TypeSpec ("struct", atoi (code+i+1)); // Skip to the last digit while (isdigit(code[i+1])) ++i; break; case '?' : break; // anything will match, so keep 'UNKNOWN' case '*' : break; // anything will match, so keep 'UNKNOWN' case '.' : break; // anything will match, so keep 'UNKNOWN' default: std::cerr << "Don't know how to decode type code '" << code << "' " << (int)code[0] << "\n"; ASSERT (0); // FIXME if (advance) *advance = 1; return TypeSpec(); } ++i; if (code[i] == '[') { ++i; t.make_array (-1); // signal arrayness, unknown length if (isdigit(code[i]) || code[i] == ']') { if (isdigit(code[i])) t.make_array (atoi (code+i)); while (isdigit(code[i])) ++i; if (code[i] == ']') ++i; } } if (advance) *advance = i; return t; }
llvm::Type * BackendLLVM::llvm_type_groupdata () { // If already computed, return it if (m_llvm_type_groupdata) return m_llvm_type_groupdata; std::vector<llvm::Type*> fields; // First, add the array that tells if each layer has run. But only make // slots for the layers that may be called/used. int sz = (m_num_used_layers + 3) & (~3); // Round up to 32 bit boundary fields.push_back (ll.type_array (ll.type_bool(), sz)); size_t offset = sz * sizeof(bool); // For each layer in the group, add entries for all params that are // connected or interpolated, and output params. Also mark those // symbols with their offset within the group struct. if (llvm_debug() >= 2) std::cout << "Group param struct:\n"; m_param_order_map.clear (); int order = 1; for (int layer = 0; layer < group().nlayers(); ++layer) { ShaderInstance *inst = group()[layer]; if (inst->unused()) continue; FOREACH_PARAM (Symbol &sym, inst) { TypeSpec ts = sym.typespec(); if (ts.is_structure()) // skip the struct symbol itself continue; int arraylen = std::max (1, sym.typespec().arraylength()); int deriv_mult = sym.has_derivs() ? 3 : 1; int n = arraylen * deriv_mult; ts.make_array (n); fields.push_back (llvm_type (ts)); // Alignment size_t align = sym.typespec().is_closure_based() ? sizeof(void*) : sym.typespec().simpletype().basesize(); if (offset & (align-1)) offset += align - (offset & (align-1)); if (llvm_debug() >= 2) std::cout << " " << inst->layername() << " (" << inst->id() << ") " << sym.mangled() << " " << ts.c_str() << ", field " << order << ", offset " << offset << std::endl; sym.dataoffset ((int)offset); offset += int(sym.size()) * deriv_mult; m_param_order_map[&sym] = order; ++order; } }
TypeSpec ASTtypecast_expression::typecheck (TypeSpec expected) { // FIXME - closures typecheck_children (m_typespec); TypeSpec t = expr()->typespec(); if (! assignable (m_typespec, t) && ! (m_typespec.is_int() && t.is_float()) && // (int)float is ok ! (m_typespec.is_triple() && t.is_triple())) error ("Cannot cast '%s' to '%s'", type_c_str(t), type_c_str(m_typespec)); return m_typespec; }
void OSOReaderToMaster::symbol (SymType symtype, TypeSpec typespec, const char *name_) { ustring name(name_); Symbol sym (name, typespec, symtype); TypeDesc t = typespec.simpletype(); int nvals = t.aggregate * (t.is_unsized_array() ? 1 : t.numelements()); if (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) { // Skip structs for now, they're just placeholders if (typespec.is_structure()) { } else if (typespec.simpletype().basetype == TypeDesc::FLOAT) { sym.dataoffset ((int) m_master->m_fdefaults.size()); expand (m_master->m_fdefaults, nvals); } else if (typespec.simpletype().basetype == TypeDesc::INT) { sym.dataoffset ((int) m_master->m_idefaults.size()); expand (m_master->m_idefaults, nvals); } else if (typespec.simpletype().basetype == TypeDesc::STRING) { sym.dataoffset ((int) m_master->m_sdefaults.size()); expand (m_master->m_sdefaults, nvals); } else if (typespec.is_closure_based()) { // Closures are pointers, so we allocate a string default taking // adventage of their default being NULL as well. sym.dataoffset ((int) m_master->m_sdefaults.size()); expand (m_master->m_sdefaults, nvals); } else { ASSERT (0 && "unexpected type"); } } if (sym.symtype() == SymTypeConst) { if (typespec.simpletype().basetype == TypeDesc::FLOAT) { sym.dataoffset ((int) m_master->m_fconsts.size()); expand (m_master->m_fconsts, nvals); } else if (typespec.simpletype().basetype == TypeDesc::INT) { sym.dataoffset ((int) m_master->m_iconsts.size()); expand (m_master->m_iconsts, nvals); } else if (typespec.simpletype().basetype == TypeDesc::STRING) { sym.dataoffset ((int) m_master->m_sconsts.size()); expand (m_master->m_sconsts, nvals); } else { ASSERT (0 && "unexpected type"); } } #if 0 // FIXME -- global_heap_offset is quite broken. But also not necessary. // We made need to fix this later. if (sym.symtype() == SymTypeGlobal) { sym.dataoffset (m_shadingsys.global_heap_offset (sym.name())); } #endif sym.lockgeom (m_shadingsys.lockgeom_default()); m_master->m_symbols.push_back (sym); m_symmap[name] = int(m_master->m_symbols.size()) - 1; // Start the index at which we add specified defaults m_sym_default_index = 0; }
ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp, const TypeSpec &type, ustring name, ASTNode *init, bool isparam, bool ismeta, bool isoutput, bool initlist) : ASTNode (variable_declaration_node, comp, 0, init, NULL /* meta */), m_name(name), m_sym(NULL), m_isparam(isparam), m_isoutput(isoutput), m_ismetadata(ismeta), m_initlist(initlist) { m_typespec = type; Symbol *f = comp->symtab().clash (name); if (f && ! m_ismetadata) { std::string e = Strutil::format ("\"%s\" already declared in this scope", name.c_str()); if (f->node()) { std::string filename = OIIO::Filesystem::filename(f->node()->sourcefile().string()); e += Strutil::format ("\n\t\tprevious declaration was at %s:%d", filename, f->node()->sourceline()); } if (f->scope() == 0 && f->symtype() == SymTypeFunction && isparam) { // special case: only a warning for param to mask global function warning ("%s", e.c_str()); } else { error ("%s", e.c_str()); } } if (name[0] == '_' && name[1] == '_' && name[2] == '_') { error ("\"%s\" : sorry, can't start with three underscores", name.c_str()); } SymType symtype = isparam ? (isoutput ? SymTypeOutputParam : SymTypeParam) : SymTypeLocal; // Sneaky debugging aid: a local that starts with "__debug_tmp__" // gets declared as a temp. Don't do this on purpose!!! if (symtype == SymTypeLocal && Strutil::starts_with (name, "__debug_tmp__")) symtype = SymTypeTemp; m_sym = new Symbol (name, type, symtype, this); if (! m_ismetadata) oslcompiler->symtab().insert (m_sym); // A struct really makes several subvariables if (type.is_structure() || type.is_structure_array()) { ASSERT (! m_ismetadata); // Add the fields as individual declarations m_compiler->add_struct_fields (type.structspec(), m_sym->name(), symtype, type.is_unsized_array() ? -1 : type.arraylength(), this, init); } }
void scContUnit::PasteText( const scContUnit* srcPara, long& offset ) { try { if ( offset == 0 ) { TypeSpec ts = srcPara->GetDefaultSpec(); if ( ts.ptr() ) SetDefaultSpec( ts ); } // paste the specs in fSpecRun.InsertRun( offset, srcPara->GetContentSize(), srcPara->GetSpecRun() ); // paste the text in fCharArray.Paste( ((scContUnit*)srcPara)->GetCharArray(), offset ); Mark( scREBREAK ); #ifdef _RUBI_SUPPORT // paste the rubis in if ( fRubiArray || srcPara->GetRubiArray() ) { if ( fRubiArray && !srcPara->GetRubiArray() ) fRubiArray->BumpRubiData( offset, srcPara->GetContentSize() ); else if ( !fRubiArray && srcPara->GetRubiArray() ) { AllocRubiArray( *srcPara->GetRubiArray() ); fRubiArray->BumpRubiData( 0, offset ); } else fRubiArray->Paste( *srcPara->GetRubiArray(), offset, srcPara->GetContentSize() ); } #endif scTextline* txl = FindLine( offset ); if ( txl ) txl->Mark( scREPAINT ); /* force repaint */ long startOffset = offset; offset += srcPara->GetContentSize(); fSpecRun.SetContentSize( GetContentSize() ); fCharArray.RepairText( fSpecRun, startOffset, offset ); } catch( ... ) { SCDebugBreak(); // remove stuff from the paragraph throw; } }
/// structnode is an AST node representing a struct. It could be a /// struct variable, or a field of a struct (which is itself a struct), /// or an array element of a struct. Whatever, here we figure out some /// vital information about it: the name of the symbol representing the /// struct, and its type. void ASTstructselect::find_structsym (ASTNode *structnode, ustring &structname, TypeSpec &structtype) { // This node selects a field from a struct. The purpose of this // method is to "flatten" the possibly-nested (struct in struct, and // or array of structs) down to a symbol that represents the // particular field. In the process, we set structname and its // type structtype. ASSERT (structnode->typespec().is_structure() || structnode->typespec().is_structure_array()); if (structnode->nodetype() == variable_ref_node) { // The structnode is a top-level struct variable ASTvariable_ref *var = (ASTvariable_ref *) structnode; structname = var->name(); structtype = var->typespec(); } else if (structnode->nodetype() == structselect_node) { // The structnode is itself a field of another struct. ASTstructselect *thestruct = (ASTstructselect *) structnode; int structid, fieldid; Symbol *sym = thestruct->find_fieldsym (structid, fieldid); structname = sym->name(); structtype = sym->typespec(); } else if (structnode->nodetype() == index_node) { // The structnode is an element of an array of structs: ASTindex *arrayref = (ASTindex *) structnode; find_structsym (arrayref->lvalue().get(), structname, structtype); structtype.make_array (0); // clear its arrayness } else { ASSERT (0 && "Malformed ASTstructselect"); } }
void scContUnit::ChInfo( long offset, UCS2& ch, /* character at offset */ ulong& flags, MicroPoint& escapement, /* escapement at offset */ MicroPoint& wordspace, /* ws escapement at offset */ TypeSpec& ts, /* typespec at offset */ eUnitType& unitType ) /* relative or absolute */ { if ( offset == 0 ) { ch = scParaStart; flags = 0; escapement = 0; ts = fSpecRun.SpecAtOffset( offset ); unitType = eAbsUnit; } else if ( offset == GetContentSize() + 1 ) { ch = scParaEnd; flags = 0; escapement = 0; ts = fSpecRun.SpecAtOffset( GetContentSize() ); unitType = eAbsUnit; } else if ( offset > GetContentSize() ) { ch = 0; flags = 0; escapement = 0; ts.clear(); unitType = eAbsUnit; } else fCharArray.CharInfo( fSpecRun, offset, ch, flags, escapement, ts, unitType ); fCharArray.WordSpaceInfo( offset, wordspace ); }
void scCachedStyle::SetParaStyle( const scContUnit* cu, TypeSpec& ts ) { if ( ts.ptr() == cachedParaStyle_.fSpec.ptr() ) return; cachedPara_ = cu; cachedParaStyle_.Init( ts ); }
void scTypeSpecList::Insert( TypeSpec& ts ) { for ( int i = 0; i < NumItems(); i++ ) { if ( ts.ptr() == (*this)[i].ptr() ) return; } Append( ts ); }
void scContUnit::SetDefaultSpec( TypeSpec& ts ) { if ( ts.ptr() != defspec_.ptr() ) { defspec_ = ts; Mark( scREBREAK ); } ForceRepaint( 0, LONG_MAX ); }
void OSOReaderQuery::symbol (SymType symtype, TypeSpec typespec, const char *name) { if (symtype == SymTypeParam || symtype == SymTypeOutputParam) { m_reading_param = true; OSLQuery::Parameter p; p.name = name; p.type = typespec.simpletype(); // FIXME -- struct & closure p.isoutput = (symtype == SymTypeOutputParam); p.varlenarray = (typespec.arraylength() < 0); p.isstruct = typespec.is_structure(); p.isclosure = typespec.is_closure(); m_query.m_params.push_back (p); } else { m_reading_param = false; } }
TypeSpec ASTconditional_statement::typecheck (TypeSpec expected) { typecheck_list (cond ()); oslcompiler->push_nesting (false); typecheck_list (truestmt ()); typecheck_list (falsestmt ()); oslcompiler->pop_nesting (false); TypeSpec c = cond()->typespec(); if (c.is_closure()) error ("Cannot use a closure as an 'if' condition"); if (c.is_structure()) error ("Cannot use a struct as an 'if' condition"); if (c.is_array()) error ("Cannot use an array as an 'if' condition"); return m_typespec = TypeDesc (TypeDesc::NONE); }
TypeSpec ASTloop_statement::typecheck (TypeSpec expected) { typecheck_list (init ()); oslcompiler->push_nesting (true); typecheck_list (cond ()); typecheck_list (iter ()); typecheck_list (stmt ()); oslcompiler->pop_nesting (true); TypeSpec c = cond()->typespec(); if (c.is_closure()) error ("Cannot use a closure as an '%s' condition", opname()); if (c.is_structure()) error ("Cannot use a struct as an '%s' condition", opname()); if (c.is_array()) error ("Cannot use an array as an '%s' condition", opname()); return m_typespec = TypeDesc (TypeDesc::NONE); }
void BackendLLVM::initialize_llvm_group () { ll.setup_optimization_passes (shadingsys().llvm_optimize()); // Clear the shaderglobals and groupdata types -- they will be // created on demand. m_llvm_type_sg = NULL; m_llvm_type_groupdata = NULL; m_llvm_type_closure_component = NULL; m_llvm_type_closure_component_attr = NULL; for (int i = 0; llvm_helper_function_table[i]; i += 2) { const char *funcname = llvm_helper_function_table[i]; bool varargs = false; const char *types = llvm_helper_function_table[i+1]; int advance; TypeSpec rettype = OSLCompilerImpl::type_from_code (types, &advance); types += advance; std::vector<llvm::Type*> params; while (*types) { TypeSpec t = OSLCompilerImpl::type_from_code (types, &advance); if (t.simpletype().basetype == TypeDesc::UNKNOWN) { if (*types == '*') varargs = true; else ASSERT (0); } else { params.push_back (llvm_pass_type (t)); } types += advance; } ll.make_function (funcname, false, llvm_type(rettype), params, varargs); } // Needed for closure setup std::vector<llvm::Type*> params(3); params[0] = (llvm::Type *) ll.type_char_ptr(); params[1] = ll.type_int(); params[2] = (llvm::Type *) ll.type_char_ptr(); m_llvm_type_prepare_closure_func = ll.type_function_ptr (ll.type_void(), params); m_llvm_type_setup_closure_func = m_llvm_type_prepare_closure_func; }
void OSLCompilerImpl::write_oso_metadata (const ASTNode *metanode) const { ASSERT (metanode->nodetype() == ASTNode::variable_declaration_node); const ASTvariable_declaration *metavar = static_cast<const ASTvariable_declaration *>(metanode); Symbol *metasym = metavar->sym(); ASSERT (metasym); TypeSpec ts = metasym->typespec(); std::string pdl; bool ok = metavar->param_default_literals (metasym, pdl, ","); if (ok) { oso ("%%meta{%s,%s,%s} ", ts.string().c_str(), metasym->name(), pdl); } else { error (metanode->sourcefile(), metanode->sourceline(), "Don't know how to print metadata %s (%s) with node type %s", metasym->name().c_str(), ts.string().c_str(), metavar->init()->nodetypename()); } }
void scContUnit::Insert( const CharRecord& ch, TypeSpec& spec, long offset ) { CharRecordP chRec = (CharRecordP)&ch; fCharArray.Insert( chRec, offset, 1 ); fSpecRun.BumpOffset( offset, fCharArray.GetNumItems() ); if ( spec.ptr() ) fSpecRun.ApplySpec( spec, offset, offset + 1 ); Mark( scREBREAK ); }
/* return true if a spec exists on a line */ BOOL scTextline::ContainTS( TypeSpec ts ) { scSpecRun& run = fPara->GetSpecRun(); int i = run.indexAtOffset( fStartOffset ); do { if ( run[i].spec().ptr() == ts.ptr() ) return true; } while ( run[++i].offset() < fEndOffset ); return false; }
TiXmlElement* GetSParamElement(Parameter *param) { TiXmlElement *gParamEl = new TiXmlElement("SPar"); TypeSpec *tSpec = dynamic_cast<TypeSpec*>(param->type); TypeRef *tRef = dynamic_cast<TypeRef*>(param->type); if (tRef) tSpec = static_cast<TypeSpec*>(tRef->type); gParamEl->SetAttribute("Qual", tSpec->GetParentModule()->Name.c_str()); //if (tSpec->IsTagged) // gParamEl->SetAttribute("Name", (tSpec->base ? tSpec->base->Name.c_str() : "NIL")); //else // gParamEl->SetAttribute("Name", (tSpec->base ? tSpec->Name.c_str() : "NIL")); gParamEl->SetAttribute("Name", tSpec->GetCPPTypeName(false).c_str()); if (tSpec->IsTagged) gParamEl->SetAttribute("Tag", tSpec->Name.c_str()); return gParamEl; }
void scCachedStyle::StyleInvalidateCache( TypeSpec& ts ) { int i; TypeSpec nullSpec; for ( i = 0; i < fEntries; i++ ) { if ( ts.ptr() == fCachedStyles[i].GetSpec().ptr() ) fCachedStyles[i].Init( nullSpec ); else fCachedStyles[i].Init( nullSpec ); } cachedParaStyle_.Init( nullSpec ); }
bool ASTNode::check_arglist (const char *funcname, ASTNode::ref arg, const char *formals, bool coerce) { // std::cerr << "ca " << funcname << " formals='" << formals << "\n"; for ( ; arg; arg = arg->next()) { if (! *formals) // More formal args, but no more actual args return false; if (*formals == '*') // Will match anything left return true; if (*formals == '.') { // Special case for token/value pairs // FIXME -- require that the tokens be string literals if (arg->typespec().is_string() && arg->next() != NULL) { arg = arg->next(); continue; } return false; } if (*formals == '?') { if (formals[1] == '[' && formals[2] == ']') { // Any array formals += 3; if (arg->typespec().is_array()) continue; // match else return false; // wanted an array, didn't get one } if (arg->typespec().is_array()) return false; // wanted any scalar, got an array formals += 1; continue; // match anything } TypeSpec argtype = arg->typespec(); int advance; TypeSpec formaltype = m_compiler->type_from_code (formals, &advance); formals += advance; // std::cerr << "\targ is " << argtype.string() // << ", formal is " << formaltype.string() << "\n"; if (argtype == formaltype) continue; // ok, move on to next arg if (coerce && assignable (formaltype, argtype)) continue; // Allow a fixed-length array match to a formal array with // unspecified length, if the element types are the same. if (formaltype.arraylength() < 0 && argtype.arraylength() && formaltype.elementtype() == argtype.elementtype()) continue; // anything that gets this far we don't consider a match return false; } if (*formals && *formals != '*' && *formals != '.') return false; // Non-*, non-... formals expected, no more actuals return true; // Is this safe? }
Type Type::specialize(TypeSpec spec) const { assertx(!spec.arrSpec() || supports(SpecKind::Array)); assertx(!spec.clsSpec() || supports(SpecKind::Class)); // If we don't have exactly one kind of specialization, or if our bits // support both kinds, don't specialize. if ((bool)spec.arrSpec() == (bool)spec.clsSpec() || (supports(SpecKind::Array) && supports(SpecKind::Class))) { return *this; } if (spec.arrSpec() != ArraySpec::Bottom) { return Type{*this, spec.arrSpec()}; } assertx(spec.clsSpec() != ClassSpec::Bottom); return Type{*this, spec.clsSpec()}; }
void scCachedStyle::Init( TypeSpec& ts ) { if ( ts.ptr() ) { TSGetStyle( ts, *this ); SetSpec( ts ); fTimeStamp = ++scCachedStyle::fCacheTime; fPtConv = (REAL)GetGlyphHeight() / scBaseRLUsystem; fSetConv = (REAL)GetGlyphWidth() / scBaseRLUsystem; InitWidths(); ComputeExtentsnCursor(); } else { TypeSpec nullSpec; SetSpec( nullSpec ); fPtConv = 0; fSetConv = 0; InitWidths(); fTimeStamp = 0; } }
std::string OSLCompilerImpl::code_from_type (TypeSpec type) const { std::string out; TypeDesc elem = type.elementtype().simpletype(); if (type.is_structure()) { out = Strutil::format ("S%d", type.structure()); } else if (type.is_closure()) { out = 'C'; } else { if (elem == TypeDesc::TypeInt) out = 'i'; else if (elem == TypeDesc::TypeFloat) out = 'f'; else if (elem == TypeDesc::TypeColor) out = 'c'; else if (elem == TypeDesc::TypePoint) out = 'p'; else if (elem == TypeDesc::TypeVector) out = 'v'; else if (elem == TypeDesc::TypeNormal) out = 'n'; else if (elem == TypeDesc::TypeMatrix) out = 'm'; else if (elem == TypeDesc::TypeString) out = 's'; else if (elem == TypeDesc::NONE) out = 'x'; else ASSERT (0); } if (type.is_array()) { int len = type.arraylength (); if (len > 0) out += Strutil::format ("[%d]", len); else out += "[]"; } return out; }
bool OSLCompilerImpl::compile (const std::string &filename, const std::vector<std::string> &options) { if (! boost::filesystem::exists (filename)) { error (ustring(), 0, "Input file \"%s\" not found", filename.c_str()); return false; } std::string stdinclude; #ifdef USE_BOOST_WAVE std::vector<std::string> defines; std::vector<std::string> undefines; std::vector<std::string> includepaths; #else std::string cppoptions; #endif // Determine where the installed shader include directory is, and // look for ../shaders/stdosl.h and force it to include. std::string program = Sysutil::this_program_path (); if (program.size()) { boost::filesystem::path path (program); // our program #if BOOST_VERSION >= 103600 path = path.parent_path (); // now the bin dir of our program path = path.parent_path (); // now the parent dir #else path = path.branch_path (); // now the bin dir of our program path = path.branch_path (); // now the parent dir #endif path = path / "shaders"; bool found = false; if (boost::filesystem::exists (path)) { path = path / "stdosl.h"; if (boost::filesystem::exists (path)) { stdinclude = path.string(); found = true; } } if (! found) warning (ustring(filename), 0, "Unable to find \"%s\"", path.string().c_str()); } m_output_filename.clear (); bool preprocess_only = false; for (size_t i = 0; i < options.size(); ++i) { if (options[i] == "-v") { // verbose mode m_verbose = true; } else if (options[i] == "-q") { // quiet mode m_quiet = true; } else if (options[i] == "-d") { // debug mode m_debug = true; } else if (options[i] == "-E") { preprocess_only = true; } else if (options[i] == "-o" && i < options.size()-1) { ++i; m_output_filename = options[i]; } else if (options[i] == "-O0") { m_optimizelevel = 0; } else if (options[i] == "-O" || options[i] == "-O1") { m_optimizelevel = 1; } else if (options[i] == "-O2") { m_optimizelevel = 2; #ifdef USE_BOOST_WAVE } else if (options[i].c_str()[0] == '-' && options[i].size() > 2) { // options meant for the preprocessor if(options[i].c_str()[1] == 'D') defines.push_back(options[i].substr(2)); else if(options[i].c_str()[1] == 'U') undefines.push_back(options[i].substr(2)); else if(options[i].c_str()[1] == 'I') includepaths.push_back(options[i].substr(2)); #else } else { // something meant for the cpp command cppoptions += "\""; cppoptions += options[i]; cppoptions += "\" "; #endif } } std::string preprocess_result; #ifdef USE_BOOST_WAVE if (! preprocess(filename, stdinclude, defines, undefines, includepaths, preprocess_result)) { #else if (! preprocess(filename, stdinclude, cppoptions, preprocess_result)) { #endif return false; } else if (preprocess_only) { std::cout << preprocess_result; } else { std::istringstream in (preprocess_result); oslcompiler = this; // Create a lexer, parse the file, delete the lexer m_lexer = new oslFlexLexer (&in); oslparse (); bool parseerr = error_encountered(); delete m_lexer; if (! parseerr) { shader()->typecheck (); } // Print the parse tree if there were no errors if (m_debug) { symtab().print (); if (shader()) shader()->print (std::cout); } if (! error_encountered()) { shader()->codegen (); // add_useparam (); track_variable_dependencies (); track_variable_lifetimes (); check_for_illegal_writes (); // if (m_optimizelevel >= 1) // coalesce_temporaries (); } if (! error_encountered()) { if (m_output_filename.size() == 0) m_output_filename = default_output_filename (); write_oso_file (m_output_filename); } oslcompiler = NULL; } return ! error_encountered(); } struct GlobalTable { const char *name; TypeSpec type; }; static GlobalTable globals[] = { { "P", TypeDesc::TypePoint }, { "I", TypeDesc::TypeVector }, { "N", TypeDesc::TypeNormal }, { "Ng", TypeDesc::TypeNormal }, { "u", TypeDesc::TypeFloat }, { "v", TypeDesc::TypeFloat }, { "dPdu", TypeDesc::TypeVector }, { "dPdv", TypeDesc::TypeVector }, #if 0 // Light variables -- we don't seem to be on a route to support this // kind of light shader, so comment these out for now. { "L", TypeDesc::TypeVector }, { "Cl", TypeDesc::TypeColor }, { "Ns", TypeDesc::TypeNormal }, { "Pl", TypeDesc::TypePoint }, { "Nl", TypeDesc::TypeNormal }, #endif { "Ps", TypeDesc::TypePoint }, { "Ci", TypeSpec (TypeDesc::TypeColor, true) }, { "time", TypeDesc::TypeFloat }, { "dtime", TypeDesc::TypeFloat }, { "dPdtime", TypeDesc::TypeVector }, { NULL } }; void OSLCompilerImpl::initialize_globals () { for (int i = 0; globals[i].name; ++i) { Symbol *s = new Symbol (ustring(globals[i].name), globals[i].type, SymTypeGlobal); symtab().insert (s); } } std::string OSLCompilerImpl::default_output_filename () { if (m_shader && shader_decl()) return shader_decl()->shadername().string() + ".oso"; return std::string(); } void OSLCompilerImpl::write_oso_metadata (const ASTNode *metanode) const { ASSERT (metanode->nodetype() == ASTNode::variable_declaration_node); const ASTvariable_declaration *metavar = static_cast<const ASTvariable_declaration *>(metanode); Symbol *metasym = metavar->sym(); ASSERT (metasym); TypeSpec ts = metasym->typespec(); oso ("%%meta{%s,%s,", ts.string().c_str(), metasym->name().c_str()); const ASTNode *init = metavar->init().get(); ASSERT (init); if (ts.is_string() && init->nodetype() == ASTNode::literal_node) oso ("\"%s\"", ((const ASTliteral *)init)->strval()); else if (ts.is_int() && init->nodetype() == ASTNode::literal_node) oso ("%d", ((const ASTliteral *)init)->intval()); else if (ts.is_float() && init->nodetype() == ASTNode::literal_node) oso ("%.8g", ((const ASTliteral *)init)->floatval()); // FIXME -- what about type constructors? else { std::cout << "Error, don't know how to print metadata " << ts.string() << " with node type " << init->nodetypename() << "\n"; ASSERT (0); // FIXME } oso ("} "); }
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()); } }