Skip to content

Commit

Permalink
Reduce shared dependencies between liboslcomp and liboslexec by extra…
Browse files Browse the repository at this point in the history
…cting some common utility functions to more standalone classes

Signed-off-by: Chris Kulla <[email protected]>
  • Loading branch information
fpsunflower committed Oct 22, 2024
1 parent 98adc79 commit cfa7b01
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 343 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 cfa7b01

Please sign in to comment.