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 ASTindex::typecheck (TypeSpec expected) { typecheck_children (); const char *indextype = ""; TypeSpec t = lvalue()->typespec(); if (t.is_structure()) { error ("Cannot use [] indexing on a struct"); return TypeSpec(); } if (t.is_closure()) { error ("Cannot use [] indexing on a closure"); return TypeSpec(); } if (index3()) { if (! t.is_array() && ! t.elementtype().is_matrix()) error ("[][][] only valid for a matrix array"); m_typespec = TypeDesc::FLOAT; } else if (t.is_array()) { indextype = "array"; m_typespec = t.elementtype(); if (index2()) { if (t.aggregate() == TypeDesc::SCALAR) error ("can't use [][] on a simple array"); m_typespec = TypeDesc::FLOAT; } } else if (t.aggregate() == TypeDesc::VEC3) { indextype = "component"; TypeDesc tnew = t.simpletype(); tnew.aggregate = TypeDesc::SCALAR; tnew.vecsemantics = TypeDesc::NOXFORM; m_typespec = tnew; if (index2()) error ("can't use [][] on a %s", type_c_str(t)); } else if (t.aggregate() == TypeDesc::MATRIX44) { indextype = "component"; TypeDesc tnew = t.simpletype(); tnew.aggregate = TypeDesc::SCALAR; tnew.vecsemantics = TypeDesc::NOXFORM; m_typespec = tnew; if (! index2()) error ("must use [][] on a matrix, not just []"); } else { error ("can only use [] indexing for arrays or multi-component types"); return TypeSpec(); } // Make sure the indices (children 1+) are integers for (size_t c = 1; c < nchildren(); ++c) if (! child(c)->typespec().is_int()) error ("%s index must be an integer, not a %s", indextype, type_c_str(index()->typespec())); // If the thing we're indexing is an lvalue, so is the indexed element m_is_lvalue = lvalue()->is_lvalue(); 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; }
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; } }
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; }
TypeSpec ASTbinary_expression::typecheck (TypeSpec expected) { typecheck_children (expected); TypeSpec l = left()->typespec(); TypeSpec r = right()->typespec(); // No binary ops work on structs or arrays if (l.is_structure() || r.is_structure() || l.is_array() || r.is_array()) { error ("Not allowed: '%s %s %s'", type_c_str(l), opname(), type_c_str(r)); return TypeSpec (); } // Special for closures -- just a few cases to worry about if (l.is_color_closure() || r.is_color_closure()) { if (m_op == Add) { if (l.is_color_closure() && r.is_color_closure()) return m_typespec = l; } if (m_op == Mul) { if (l.is_color_closure() && (r.is_color() || r.is_int_or_float())) return m_typespec = l; if (r.is_color_closure() && (l.is_color() || l.is_int_or_float())) { // N.B. Reorder so that it's always r = closure * k, // not r = k * closure. See codegen for why this helps. std::swap (m_children[0], m_children[1]); return m_typespec = r; } } // If we got this far, it's an op that's not allowed error ("Not allowed: '%s %s %s'", type_c_str(l), opname(), type_c_str(r)); return TypeSpec (); } switch (m_op) { case Sub : case Add : case Mul : case Div : // Add/Sub/Mul/Div work for any equivalent types, and // combination of int/float and other numeric types, but do not // work with strings. Add/Sub don't work with matrices, but // Mul/Div do. // FIXME -- currently, equivalent types combine to make the // left type. But maybe we should be more careful, for example // point-point -> vector, etc. if (l.is_string() || r.is_string()) break; // Dispense with strings trivially if ((m_op == Sub || m_op == Add) && (l.is_matrix() || r.is_matrix())) break; // Matrices don't combine for + and - if (equivalent (l, r) || (l.is_numeric() && r.is_int_or_float()) || (l.is_int_or_float() && r.is_numeric())) return m_typespec = higherprecision (l.simpletype(), r.simpletype()); break; case Mod : // Mod only works with ints, and return ints. if (l.is_int() && r.is_int()) return m_typespec = TypeDesc::TypeInt; break; case Equal : case NotEqual : // Any equivalent types can be compared with == and !=, also a // float or int can be compared to any other numeric type. // Result is always an int. if (equivalent (l, r) || (l.is_numeric() && r.is_int_or_float()) || (l.is_int_or_float() && r.is_numeric())) return m_typespec = TypeDesc::TypeInt; break; case Greater : case Less : case GreaterEqual : case LessEqual : // G/L comparisons only work with floats or ints, and always // return int. if (l.is_int_or_float() && r.is_int_or_float()) return m_typespec = TypeDesc::TypeInt; break; case BitAnd : case BitOr : case Xor : case ShiftLeft : case ShiftRight : // Bitwise ops only work with ints, and return ints. if (l.is_int() && r.is_int()) return m_typespec = TypeDesc::TypeInt; break; case And : case Or : // Logical ops work on any simple type (since they test for // nonzeroness), but always return int. return m_typespec = TypeDesc::TypeInt; default: error ("unknown binary operator"); } // If we got this far, it's an op that's not allowed error ("Not allowed: '%s %s %s'", type_c_str(l), opname(), type_c_str(r)); return TypeSpec (); }
void RuntimeOptimizer::initialize_llvm_group () { // I don't think we actually need to lock here (lg) // static spin_mutex mutex; // OIIO::spin_lock lock (mutex); m_llvm_context = m_thread->llvm_context; ASSERT (m_llvm_context && m_llvm_module); llvm_setup_optimization_passes (); // 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; // Set up aliases for types we use over and over m_llvm_type_float = (llvm::Type *) llvm::Type::getFloatTy (*m_llvm_context); m_llvm_type_int = (llvm::Type *) llvm::Type::getInt32Ty (*m_llvm_context); if (sizeof(char *) == 4) m_llvm_type_addrint = (llvm::Type *) llvm::Type::getInt32Ty (*m_llvm_context); else m_llvm_type_addrint = (llvm::Type *) llvm::Type::getInt64Ty (*m_llvm_context); m_llvm_type_int_ptr = (llvm::PointerType *) llvm::Type::getInt32PtrTy (*m_llvm_context); m_llvm_type_bool = (llvm::Type *) llvm::Type::getInt1Ty (*m_llvm_context); m_llvm_type_longlong = (llvm::Type *) llvm::Type::getInt64Ty (*m_llvm_context); m_llvm_type_void = (llvm::Type *) llvm::Type::getVoidTy (*m_llvm_context); m_llvm_type_char_ptr = (llvm::PointerType *) llvm::Type::getInt8PtrTy (*m_llvm_context); m_llvm_type_float_ptr = (llvm::PointerType *) llvm::Type::getFloatPtrTy (*m_llvm_context); m_llvm_type_ustring_ptr = (llvm::PointerType *) llvm::PointerType::get (m_llvm_type_char_ptr, 0); // A triple is a struct composed of 3 floats std::vector<llvm::Type*> triplefields(3, m_llvm_type_float); m_llvm_type_triple = llvm_type_struct (triplefields, "Vec3"); m_llvm_type_triple_ptr = (llvm::PointerType *) llvm::PointerType::get (m_llvm_type_triple, 0); // A matrix is a struct composed 16 floats std::vector<llvm::Type*> matrixfields(16, m_llvm_type_float); m_llvm_type_matrix = llvm_type_struct (matrixfields, "Matrix4"); m_llvm_type_matrix_ptr = (llvm::PointerType *) llvm::PointerType::get (m_llvm_type_matrix, 0); 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; } llvm::FunctionType *func = llvm::FunctionType::get (llvm_type(rettype), params, varargs); m_llvm_module->getOrInsertFunction (funcname, func); } // Needed for closure setup std::vector<llvm::Type*> params(3); params[0] = m_llvm_type_char_ptr; params[1] = m_llvm_type_int; params[2] = m_llvm_type_char_ptr; m_llvm_type_prepare_closure_func = llvm::PointerType::getUnqual (llvm::FunctionType::get (m_llvm_type_void, params, false)); m_llvm_type_setup_closure_func = m_llvm_type_prepare_closure_func; }