Skip to content

Commit 35b12e4

Browse files
authored
Reduce shared dependencies between liboslcomp and liboslexec (#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]>
1 parent cb08288 commit 35b12e4

File tree

17 files changed

+312
-346
lines changed

17 files changed

+312
-346
lines changed

src/include/osl_pvt.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ class TypeSpec {
9898
/// is not responsible for freeing the characters.
9999
const char* c_str() const;
100100

101+
/// Return the c_str giving a human-readable name of a type, fully
102+
/// accounting for exotic types like structs, etc.
103+
const char* type_c_str() const;
104+
101105
/// Stream output
102106
friend std::ostream& operator<<(std::ostream& o, const TypeSpec& t)
103107
{
@@ -373,6 +377,28 @@ class TypeSpec {
373377
&& (src.is_float() || src.is_int()));
374378
}
375379

380+
/// Given a pointer to a type code string that we use for argument
381+
/// checking ("p", "v", etc.) return the TypeSpec of the first type
382+
/// described by the string (UNKNOWN if it couldn't be recognized).
383+
/// If 'advance' is non-NULL, set *advance to the number of
384+
/// characters taken by the first code so the caller can advance
385+
/// their pointer to the next code in the string.
386+
static TypeSpec type_from_code(const char* code, int* advance = nullptr);
387+
388+
/// Return the argument checking code ("p", "v", etc.) corresponding
389+
/// to the type.
390+
std::string code_from_type() const;
391+
392+
/// Take a type code string (possibly containing many types)
393+
/// and turn it into a human-readable string.
394+
static std::string typelist_from_code(const char* code);
395+
396+
/// Take a type code string (possibly containing many types) and
397+
/// turn it into a TypeSpec vector.
398+
static void typespecs_from_codes(const char* code,
399+
std::vector<TypeSpec>& types);
400+
401+
376402
private:
377403
TypeDesc m_simple; ///< Data if it's a simple type
378404
short m_structure; ///< 0 is not a structure, >=1 for structure id
@@ -1125,6 +1151,16 @@ class Opcode {
11251151

11261152
typedef std::vector<Opcode> OpcodeVec;
11271153

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

11291165

11301166
}; // namespace pvt

src/liboslcomp/ast.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,6 @@ ASTNode::printchildren(std::ostream& out, int indentlevel) const
275275
}
276276

277277

278-
279-
const char*
280-
ASTNode::type_c_str(const TypeSpec& type) const
281-
{
282-
return m_compiler->type_c_str(type);
283-
}
284-
285-
286-
287278
void
288279
ASTNode::list_to_vec(const ref& A, std::vector<ref>& vec)
289280
{
@@ -401,14 +392,14 @@ ASTfunction_declaration::ASTfunction_declaration(OSLCompilerImpl* comp,
401392

402393
// Build up the argument signature for this declared function
403394
m_typespec = type;
404-
std::string argcodes = m_compiler->code_from_type(m_typespec);
395+
std::string argcodes = m_typespec.code_from_type();
405396
for (ASTNode* arg = form; arg; arg = arg->nextptr()) {
406397
const TypeSpec& t(arg->typespec());
407398
if (t == TypeSpec() /* UNKNOWN */) {
408399
m_typespec = TypeDesc::UNKNOWN;
409400
return;
410401
}
411-
argcodes += m_compiler->code_from_type(t);
402+
argcodes += t.code_from_type();
412403
OSL_ASSERT(arg->nodetype() == variable_declaration_node);
413404
ASTvariable_declaration* v = (ASTvariable_declaration*)arg;
414405
if (v->init())

src/liboslcomp/ast.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,6 @@ class ASTNode : public OIIO::RefCnt {
349349
/// coercion if acceptfloat is false.
350350
Symbol* coerce(Symbol* sym, const TypeSpec& type, bool acceptfloat = false);
351351

352-
/// Return the c_str giving a human-readable name of a type, fully
353-
/// accounting for exotic types like structs, etc.
354-
/// N.B.: just conveniently wraps the compiler's identical method.
355-
const char* type_c_str(const TypeSpec& type) const;
356-
357352
/// Assign the struct variable named by srcsym to the struct
358353
/// variable named by dstsym by assigning each field individually.
359354
/// In the case of dstsym naming an array of structs, arrayindex

src/liboslcomp/codegen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,8 +1812,8 @@ ASTfunction_call::codegen(Symbol* dest)
18121812
std::vector<TypeSpec> polyargs;
18131813
const char* param_argcodes = func()->argcodes().c_str();
18141814
int len;
1815-
m_compiler->type_from_code(param_argcodes, &len); // skip ret type
1816-
m_compiler->typespecs_from_codes(param_argcodes + len, polyargs);
1815+
TypeSpec::type_from_code(param_argcodes, &len); // skip ret type
1816+
TypeSpec::typespecs_from_codes(param_argcodes + len, polyargs);
18171817

18181818
// Generate code for all the individual arguments. Remember the
18191819
// individual indices for arguments that are array elements or

src/liboslcomp/oslcomp.cpp

Lines changed: 1 addition & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ OSLCompiler::output_filename() const
8585
namespace pvt { // OSL::pvt
8686

8787

88-
static ustring op_for("for");
89-
static ustring op_while("while");
90-
static ustring op_dowhile("dowhile");
91-
92-
9388

9489
OSLCompilerImpl::OSLCompilerImpl(ErrorHandler* errhandler)
9590
: m_errhandler(errhandler ? errhandler : &ErrorHandler::default_handler())
@@ -769,7 +764,7 @@ OSLCompilerImpl::write_oso_symbol(const Symbol* sym)
769764
if (i > 0)
770765
fieldlist += ",";
771766
fieldlist += structspec->field(i).name.string();
772-
signature += code_from_type(structspec->field(i).type);
767+
signature += structspec->field(i).type.code_from_type();
773768
}
774769
osofmt(
775770
"{}%struct{{\"{}\"}} %structfields{{{}}} %structfieldtypes{{\"{}\"}} %structnfields{{{}}}",
@@ -1068,19 +1063,6 @@ OSLCompilerImpl::pop_nesting(bool isloop)
10681063
}
10691064

10701065

1071-
1072-
const char*
1073-
OSLCompilerImpl::type_c_str(const TypeSpec& type) const
1074-
{
1075-
if (type.is_structure())
1076-
return ustring::fmtformat("struct {}", type.structspec()->name())
1077-
.c_str();
1078-
else
1079-
return type.c_str();
1080-
}
1081-
1082-
1083-
10841066
void
10851067
OSLCompilerImpl::struct_field_pair(Symbol* sym1, Symbol* sym2, int fieldnum,
10861068
Symbol*& field1, Symbol*& field2)
@@ -1162,92 +1144,6 @@ OSLCompilerImpl::check_for_illegal_writes()
11621144

11631145

11641146

1165-
/// Called after code is generated, this function loops over all the ops
1166-
/// and figures out the lifetimes of all variables, based on whether the
1167-
/// args in each op are read or written.
1168-
void
1169-
OSLCompilerImpl::track_variable_lifetimes(const OpcodeVec& code,
1170-
const SymbolPtrVec& opargs,
1171-
const SymbolPtrVec& allsyms,
1172-
std::vector<int>* bblockids)
1173-
{
1174-
// Clear the lifetimes for all symbols
1175-
for (auto&& s : allsyms)
1176-
s->clear_rw();
1177-
1178-
// Keep track of the nested loops we're inside. We track them by pairs
1179-
// of begin/end instruction numbers for that loop body, including
1180-
// conditional evaluation (skip the initialization). Note that the end
1181-
// is inclusive. We use this vector of ranges as a stack.
1182-
typedef std::pair<int, int> intpair;
1183-
std::vector<intpair> loop_bounds;
1184-
1185-
// For each op, mark its arguments as being used at that op
1186-
int opnum = 0;
1187-
for (auto&& op : code) {
1188-
if (op.opname() == op_for || op.opname() == op_while
1189-
|| op.opname() == op_dowhile) {
1190-
// If this is a loop op, we need to mark its control variable
1191-
// (the only arg) as used for the duration of the loop!
1192-
OSL_DASSERT(op.nargs() == 1); // loops should have just one arg
1193-
SymbolPtr s = opargs[op.firstarg()];
1194-
int loopcond = op.jump(0); // after initialization, before test
1195-
int loopend = op.farthest_jump() - 1; // inclusive end
1196-
s->mark_rw(opnum + 1, true, true);
1197-
s->mark_rw(loopend, true, true);
1198-
// Also push the loop bounds for this loop
1199-
loop_bounds.push_back(std::make_pair(loopcond, loopend));
1200-
}
1201-
1202-
// Some work to do for each argument to the op...
1203-
for (int a = 0; a < op.nargs(); ++a) {
1204-
SymbolPtr s = opargs[op.firstarg() + a];
1205-
OSL_DASSERT(s->dealias() == s); // Make sure it's de-aliased
1206-
1207-
// Mark that it's read and/or written for this op
1208-
bool readhere = op.argread(a);
1209-
bool writtenhere = op.argwrite(a);
1210-
s->mark_rw(opnum, readhere, writtenhere);
1211-
1212-
// Adjust lifetimes of symbols whose values need to be preserved
1213-
// between loop iterations.
1214-
for (auto oprange : loop_bounds) {
1215-
int loopcond = oprange.first;
1216-
int loopend = oprange.second;
1217-
OSL_DASSERT(s->firstuse() <= loopend);
1218-
// Special case: a temp or local, even if written inside a
1219-
// loop, if it's entire lifetime is within one basic block
1220-
// and it's strictly written before being read, then its
1221-
// lifetime is truly local and doesn't need to be expanded
1222-
// for the duration of the loop.
1223-
if (bblockids
1224-
&& (s->symtype() == SymTypeLocal
1225-
|| s->symtype() == SymTypeTemp)
1226-
&& (*bblockids)[s->firstuse()] == (*bblockids)[s->lastuse()]
1227-
&& s->lastwrite() < s->firstread()) {
1228-
continue;
1229-
}
1230-
// Syms written before or inside the loop, and referenced
1231-
// inside or after the loop, need to preserve their value
1232-
// for the duration of the loop. We know it's referenced
1233-
// inside the loop because we're here examining it!
1234-
if (s->firstwrite() <= loopend) {
1235-
s->mark_rw(loopcond, readhere, writtenhere);
1236-
s->mark_rw(loopend, readhere, writtenhere);
1237-
}
1238-
}
1239-
}
1240-
1241-
++opnum; // Advance to the next op index
1242-
1243-
// Pop any loop bounds for loops we've just exited
1244-
while (!loop_bounds.empty() && loop_bounds.back().second < opnum)
1245-
loop_bounds.pop_back();
1246-
}
1247-
}
1248-
1249-
1250-
12511147
// This has O(n^2) memory usage, so only for debugging
12521148
//#define DEBUG_SYMBOL_DEPENDENCIES
12531149

src/liboslcomp/oslcomp_pvt.h

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -192,27 +192,6 @@ class OSLCompilerImpl {
192192
}
193193
bool declaring_shader_formals() const { return m_declaring_shader_formals; }
194194

195-
/// Given a pointer to a type code string that we use for argument
196-
/// checking ("p", "v", etc.) return the TypeSpec of the first type
197-
/// described by the string (UNKNOWN if it couldn't be recognized).
198-
/// If 'advance' is non-NULL, set *advance to the number of
199-
/// characters taken by the first code so the caller can advance
200-
/// their pointer to the next code in the string.
201-
static TypeSpec type_from_code(const char* code, int* advance = NULL);
202-
203-
/// Return the argument checking code ("p", "v", etc.) corresponding
204-
/// to the type.
205-
std::string code_from_type(TypeSpec type) const;
206-
207-
/// Take a type code string (possibly containing many types)
208-
/// and turn it into a human-readable string.
209-
std::string typelist_from_code(const char* code) const;
210-
211-
/// Take a type code string (possibly containing many types) and
212-
/// turn it into a TypeSpec vector.
213-
void typespecs_from_codes(const char* code,
214-
std::vector<TypeSpec>& types) const;
215-
216195
/// Emit a single IR opcode -- append one op to the list of
217196
/// intermediate code, returning the label (address) of the new op.
218197
int emitcode(const char* opname, size_t nargs, Symbol** args,
@@ -326,10 +305,6 @@ class OSLCompilerImpl {
326305
return loops ? m_loop_nesting : m_total_nesting;
327306
}
328307

329-
/// Return the c_str giving a human-readable name of a type, fully
330-
/// accounting for exotic types like structs, etc.
331-
const char* type_c_str(const TypeSpec& type) const;
332-
333308
/// Given symbols sym1 and sym2, both the same kind of struct, and the
334309
/// index of a field we're interested, find the symbols that represent
335310
/// that field in the each sym and place them in field1 and field2,
@@ -346,10 +321,6 @@ class OSLCompilerImpl {
346321
ustring sym1, ustring sym2, Symbol*& field1,
347322
Symbol*& field2);
348323

349-
static void track_variable_lifetimes(const OpcodeVec& ircode,
350-
const SymbolPtrVec& opargs,
351-
const SymbolPtrVec& allsyms,
352-
std::vector<int>* bblock_ids = NULL);
353324
static void coalesce_temporaries(SymbolPtrVec& symtab);
354325

355326
ustring main_filename() const { return m_main_filename; }
@@ -399,7 +370,7 @@ class OSLCompilerImpl {
399370

400371
void track_variable_lifetimes()
401372
{
402-
track_variable_lifetimes(m_ircode, m_opargs, symtab().allsyms());
373+
track_variable_lifetimes_main(m_ircode, m_opargs, symtab().allsyms());
403374
}
404375

405376
void track_variable_dependencies();

0 commit comments

Comments
 (0)