Skip to content

Commit

Permalink
Reduce shared dependencies between liboslcomp and liboslexec (Academy…
Browse files Browse the repository at this point in the history
…SoftwareFoundation#1890)

* Reduce shared dependencies between liboslcomp and liboslexec by extracting some common utility functions to more standalone classes

Signed-off-by: Chris Kulla <[email protected]>
  • Loading branch information
fpsunflower authored Oct 27, 2024
1 parent cb08288 commit 35b12e4
Show file tree
Hide file tree
Showing 17 changed files with 312 additions and 346 deletions.
36 changes: 36 additions & 0 deletions src/include/osl_pvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ class TypeSpec {
/// is not responsible for freeing the characters.
const char* c_str() const;

/// Return the c_str giving a human-readable name of a type, fully
/// accounting for exotic types like structs, etc.
const char* type_c_str() const;

/// Stream output
friend std::ostream& operator<<(std::ostream& o, const TypeSpec& t)
{
Expand Down Expand Up @@ -373,6 +377,28 @@ class TypeSpec {
&& (src.is_float() || src.is_int()));
}

/// Given a pointer to a type code string that we use for argument
/// checking ("p", "v", etc.) return the TypeSpec of the first type
/// described by the string (UNKNOWN if it couldn't be recognized).
/// If 'advance' is non-NULL, set *advance to the number of
/// characters taken by the first code so the caller can advance
/// their pointer to the next code in the string.
static TypeSpec type_from_code(const char* code, int* advance = nullptr);

/// Return the argument checking code ("p", "v", etc.) corresponding
/// to the type.
std::string code_from_type() const;

/// Take a type code string (possibly containing many types)
/// and turn it into a human-readable string.
static std::string typelist_from_code(const char* code);

/// Take a type code string (possibly containing many types) and
/// turn it into a TypeSpec vector.
static void typespecs_from_codes(const char* code,
std::vector<TypeSpec>& types);


private:
TypeDesc m_simple; ///< Data if it's a simple type
short m_structure; ///< 0 is not a structure, >=1 for structure id
Expand Down Expand Up @@ -1125,6 +1151,16 @@ class Opcode {

typedef std::vector<Opcode> OpcodeVec;

/// Called after code is generated, this function loops over all the ops
/// and figures out the lifetimes of all variables, based on whether the
/// args in each op are read or written. This function is used both in
/// the compiler and the runtime optimizer.
void
track_variable_lifetimes_main(const OpcodeVec& ircode,
const SymbolPtrVec& opargs,
const SymbolPtrVec& allsyms,
std::vector<int>* bblock_ids = nullptr);



}; // namespace pvt
Expand Down
13 changes: 2 additions & 11 deletions src/liboslcomp/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,6 @@ ASTNode::printchildren(std::ostream& out, int indentlevel) const
}



const char*
ASTNode::type_c_str(const TypeSpec& type) const
{
return m_compiler->type_c_str(type);
}



void
ASTNode::list_to_vec(const ref& A, std::vector<ref>& vec)
{
Expand Down Expand Up @@ -401,14 +392,14 @@ ASTfunction_declaration::ASTfunction_declaration(OSLCompilerImpl* comp,

// Build up the argument signature for this declared function
m_typespec = type;
std::string argcodes = m_compiler->code_from_type(m_typespec);
std::string argcodes = m_typespec.code_from_type();
for (ASTNode* arg = form; arg; arg = arg->nextptr()) {
const TypeSpec& t(arg->typespec());
if (t == TypeSpec() /* UNKNOWN */) {
m_typespec = TypeDesc::UNKNOWN;
return;
}
argcodes += m_compiler->code_from_type(t);
argcodes += t.code_from_type();
OSL_ASSERT(arg->nodetype() == variable_declaration_node);
ASTvariable_declaration* v = (ASTvariable_declaration*)arg;
if (v->init())
Expand Down
5 changes: 0 additions & 5 deletions src/liboslcomp/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,6 @@ class ASTNode : public OIIO::RefCnt {
/// coercion if acceptfloat is false.
Symbol* coerce(Symbol* sym, const TypeSpec& type, bool acceptfloat = false);

/// Return the c_str giving a human-readable name of a type, fully
/// accounting for exotic types like structs, etc.
/// N.B.: just conveniently wraps the compiler's identical method.
const char* type_c_str(const TypeSpec& type) const;

/// Assign the struct variable named by srcsym to the struct
/// variable named by dstsym by assigning each field individually.
/// In the case of dstsym naming an array of structs, arrayindex
Expand Down
4 changes: 2 additions & 2 deletions src/liboslcomp/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1812,8 +1812,8 @@ ASTfunction_call::codegen(Symbol* dest)
std::vector<TypeSpec> polyargs;
const char* param_argcodes = func()->argcodes().c_str();
int len;
m_compiler->type_from_code(param_argcodes, &len); // skip ret type
m_compiler->typespecs_from_codes(param_argcodes + len, polyargs);
TypeSpec::type_from_code(param_argcodes, &len); // skip ret type
TypeSpec::typespecs_from_codes(param_argcodes + len, polyargs);

// Generate code for all the individual arguments. Remember the
// individual indices for arguments that are array elements or
Expand Down
106 changes: 1 addition & 105 deletions src/liboslcomp/oslcomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,6 @@ OSLCompiler::output_filename() const
namespace pvt { // OSL::pvt


static ustring op_for("for");
static ustring op_while("while");
static ustring op_dowhile("dowhile");



OSLCompilerImpl::OSLCompilerImpl(ErrorHandler* errhandler)
: m_errhandler(errhandler ? errhandler : &ErrorHandler::default_handler())
Expand Down Expand Up @@ -769,7 +764,7 @@ OSLCompilerImpl::write_oso_symbol(const Symbol* sym)
if (i > 0)
fieldlist += ",";
fieldlist += structspec->field(i).name.string();
signature += code_from_type(structspec->field(i).type);
signature += structspec->field(i).type.code_from_type();
}
osofmt(
"{}%struct{{\"{}\"}} %structfields{{{}}} %structfieldtypes{{\"{}\"}} %structnfields{{{}}}",
Expand Down Expand Up @@ -1068,19 +1063,6 @@ OSLCompilerImpl::pop_nesting(bool isloop)
}



const char*
OSLCompilerImpl::type_c_str(const TypeSpec& type) const
{
if (type.is_structure())
return ustring::fmtformat("struct {}", type.structspec()->name())
.c_str();
else
return type.c_str();
}



void
OSLCompilerImpl::struct_field_pair(Symbol* sym1, Symbol* sym2, int fieldnum,
Symbol*& field1, Symbol*& field2)
Expand Down Expand Up @@ -1162,92 +1144,6 @@ OSLCompilerImpl::check_for_illegal_writes()



/// Called after code is generated, this function loops over all the ops
/// and figures out the lifetimes of all variables, based on whether the
/// args in each op are read or written.
void
OSLCompilerImpl::track_variable_lifetimes(const OpcodeVec& code,
const SymbolPtrVec& opargs,
const SymbolPtrVec& allsyms,
std::vector<int>* bblockids)
{
// Clear the lifetimes for all symbols
for (auto&& s : allsyms)
s->clear_rw();

// Keep track of the nested loops we're inside. We track them by pairs
// of begin/end instruction numbers for that loop body, including
// conditional evaluation (skip the initialization). Note that the end
// is inclusive. We use this vector of ranges as a stack.
typedef std::pair<int, int> intpair;
std::vector<intpair> loop_bounds;

// For each op, mark its arguments as being used at that op
int opnum = 0;
for (auto&& op : code) {
if (op.opname() == op_for || op.opname() == op_while
|| op.opname() == op_dowhile) {
// If this is a loop op, we need to mark its control variable
// (the only arg) as used for the duration of the loop!
OSL_DASSERT(op.nargs() == 1); // loops should have just one arg
SymbolPtr s = opargs[op.firstarg()];
int loopcond = op.jump(0); // after initialization, before test
int loopend = op.farthest_jump() - 1; // inclusive end
s->mark_rw(opnum + 1, true, true);
s->mark_rw(loopend, true, true);
// Also push the loop bounds for this loop
loop_bounds.push_back(std::make_pair(loopcond, loopend));
}

// Some work to do for each argument to the op...
for (int a = 0; a < op.nargs(); ++a) {
SymbolPtr s = opargs[op.firstarg() + a];
OSL_DASSERT(s->dealias() == s); // Make sure it's de-aliased

// Mark that it's read and/or written for this op
bool readhere = op.argread(a);
bool writtenhere = op.argwrite(a);
s->mark_rw(opnum, readhere, writtenhere);

// Adjust lifetimes of symbols whose values need to be preserved
// between loop iterations.
for (auto oprange : loop_bounds) {
int loopcond = oprange.first;
int loopend = oprange.second;
OSL_DASSERT(s->firstuse() <= loopend);
// Special case: a temp or local, even if written inside a
// loop, if it's entire lifetime is within one basic block
// and it's strictly written before being read, then its
// lifetime is truly local and doesn't need to be expanded
// for the duration of the loop.
if (bblockids
&& (s->symtype() == SymTypeLocal
|| s->symtype() == SymTypeTemp)
&& (*bblockids)[s->firstuse()] == (*bblockids)[s->lastuse()]
&& s->lastwrite() < s->firstread()) {
continue;
}
// Syms written before or inside the loop, and referenced
// inside or after the loop, need to preserve their value
// for the duration of the loop. We know it's referenced
// inside the loop because we're here examining it!
if (s->firstwrite() <= loopend) {
s->mark_rw(loopcond, readhere, writtenhere);
s->mark_rw(loopend, readhere, writtenhere);
}
}
}

++opnum; // Advance to the next op index

// Pop any loop bounds for loops we've just exited
while (!loop_bounds.empty() && loop_bounds.back().second < opnum)
loop_bounds.pop_back();
}
}



// This has O(n^2) memory usage, so only for debugging
//#define DEBUG_SYMBOL_DEPENDENCIES

Expand Down
31 changes: 1 addition & 30 deletions src/liboslcomp/oslcomp_pvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,27 +192,6 @@ class OSLCompilerImpl {
}
bool declaring_shader_formals() const { return m_declaring_shader_formals; }

/// Given a pointer to a type code string that we use for argument
/// checking ("p", "v", etc.) return the TypeSpec of the first type
/// described by the string (UNKNOWN if it couldn't be recognized).
/// If 'advance' is non-NULL, set *advance to the number of
/// characters taken by the first code so the caller can advance
/// their pointer to the next code in the string.
static TypeSpec type_from_code(const char* code, int* advance = NULL);

/// Return the argument checking code ("p", "v", etc.) corresponding
/// to the type.
std::string code_from_type(TypeSpec type) const;

/// Take a type code string (possibly containing many types)
/// and turn it into a human-readable string.
std::string typelist_from_code(const char* code) const;

/// Take a type code string (possibly containing many types) and
/// turn it into a TypeSpec vector.
void typespecs_from_codes(const char* code,
std::vector<TypeSpec>& types) const;

/// Emit a single IR opcode -- append one op to the list of
/// intermediate code, returning the label (address) of the new op.
int emitcode(const char* opname, size_t nargs, Symbol** args,
Expand Down Expand Up @@ -326,10 +305,6 @@ class OSLCompilerImpl {
return loops ? m_loop_nesting : m_total_nesting;
}

/// Return the c_str giving a human-readable name of a type, fully
/// accounting for exotic types like structs, etc.
const char* type_c_str(const TypeSpec& type) const;

/// Given symbols sym1 and sym2, both the same kind of struct, and the
/// index of a field we're interested, find the symbols that represent
/// that field in the each sym and place them in field1 and field2,
Expand All @@ -346,10 +321,6 @@ class OSLCompilerImpl {
ustring sym1, ustring sym2, Symbol*& field1,
Symbol*& field2);

static void track_variable_lifetimes(const OpcodeVec& ircode,
const SymbolPtrVec& opargs,
const SymbolPtrVec& allsyms,
std::vector<int>* bblock_ids = NULL);
static void coalesce_temporaries(SymbolPtrVec& symtab);

ustring main_filename() const { return m_main_filename; }
Expand Down Expand Up @@ -399,7 +370,7 @@ class OSLCompilerImpl {

void track_variable_lifetimes()
{
track_variable_lifetimes(m_ircode, m_opargs, symtab().allsyms());
track_variable_lifetimes_main(m_ircode, m_opargs, symtab().allsyms());
}

void track_variable_dependencies();
Expand Down
Loading

0 comments on commit 35b12e4

Please sign in to comment.