Skip to content

Commit

Permalink
Avoid creating tiny std::vectors during LLVM code generation where po…
Browse files Browse the repository at this point in the history
…ssible

Refactor call_function methods to use a span instead of raw pointers to unify disparate idioms

Simplify llvm_call_function to use a short vector as it is never used on very long arrays
  • Loading branch information
fpsunflower committed Jul 8, 2019
1 parent 1cbec06 commit ae65c11
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 386 deletions.
22 changes: 7 additions & 15 deletions src/include/OSL/llvm_util.h
Expand Up @@ -30,6 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <OSL/export.h>
#include <OSL/oslversion.h>
#include <OSL/oslconfig.h>

#include <vector>

Expand Down Expand Up @@ -354,36 +355,27 @@ class OSLEXECPUBLIC LLVM_Util {
/// Generate code for a call to the function pointer, with the given
/// arg list. Return an llvm::Value* corresponding to the return
/// value of the function, if any.
llvm::Value *call_function (llvm::Value *func,
llvm::Value **args, int nargs);
llvm::Value *call_function (llvm::Value *func, cspan<llvm::Value *> args);
/// Generate code for a call to the named function with the given arg
/// list. Return an llvm::Value* corresponding to the return value of
/// the function, if any.
llvm::Value *call_function (const char *name,
llvm::Value **args, int nargs);
template<size_t N>
llvm::Value* call_function (const char *name, llvm::Value* (&args)[N]) {
return call_function (name, &args[0], int(N));
}
llvm::Value *call_function (const char *name, cspan<llvm::Value *> args);

llvm::Value *call_function (const char *name, llvm::Value *arg0) {
return call_function (name, &arg0, 1);
return call_function (name, cspan<llvm::Value*>(&arg0, 1));
}
llvm::Value *call_function (const char *name, llvm::Value *arg0,
llvm::Value *arg1) {
llvm::Value *args[2] = { arg0, arg1 };
return call_function (name, args, 2);
return call_function (name, { arg0, arg1 });
}
llvm::Value *call_function (const char *name, llvm::Value *arg0,
llvm::Value *arg1, llvm::Value *arg2) {
llvm::Value *args[3] = { arg0, arg1, arg2 };
return call_function (name, args, 3);
return call_function (name, { arg0, arg1, arg2 });
}
llvm::Value *call_function (const char *name, llvm::Value *arg0,
llvm::Value *arg1, llvm::Value *arg2,
llvm::Value *arg3) {
llvm::Value *args[4] = { arg0, arg1, arg2, arg3 };
return call_function (name, args, 4);
return call_function (name, { arg0, arg1, arg2, arg3 });
}

/// Mark the function call (which MUST be the value returned by a
Expand Down
62 changes: 15 additions & 47 deletions src/liboslexec/backendllvm.cpp
Expand Up @@ -949,13 +949,21 @@ BackendLLVM::userdata_initialized_ref (int userdata_index)

llvm::Value *
BackendLLVM::llvm_call_function (const char *name,
const Symbol **symargs, int nargs,
bool deriv_ptrs)
cspan<const Symbol *> args,
bool deriv_ptrs)
{
std::vector<llvm::Value *> valargs;
valargs.resize ((size_t)nargs);
for (int i = 0; i < nargs; ++i) {
const Symbol &s = *(symargs[i]);
// most invocations of this function will only need a handful of args
// so avoid dynamic allocation where possible
constexpr int SHORT_NUM_ARGS = 16;
llvm::Value *short_valargs[SHORT_NUM_ARGS];
std::vector<llvm::Value*> long_valargs;
llvm::Value **valargs = short_valargs;
if (args.size() > SHORT_NUM_ARGS) {
long_valargs.resize(args.size());
valargs = long_valargs.data();
}
for (int i = 0, nargs = args.size(); i < nargs; ++i) {
const Symbol &s = *(args[i]);
if (s.typespec().is_closure())
valargs[i] = llvm_load_value (s);
else if (use_optix() && s.typespec().is_string())
Expand All @@ -966,49 +974,9 @@ BackendLLVM::llvm_call_function (const char *name,
else
valargs[i] = llvm_load_value (s);
}
return ll.call_function (name, (valargs.size())? &valargs[0]: NULL,
(int)valargs.size());
}



llvm::Value *
BackendLLVM::llvm_call_function (const char *name, const Symbol &A,
bool deriv_ptrs)
{
const Symbol *args[1];
args[0] = &A;
return llvm_call_function (name, args, 1, deriv_ptrs);
}



llvm::Value *
BackendLLVM::llvm_call_function (const char *name, const Symbol &A,
const Symbol &B, bool deriv_ptrs)
{
const Symbol *args[2];
args[0] = &A;
args[1] = &B;
return llvm_call_function (name, args, 2, deriv_ptrs);
}



llvm::Value *
BackendLLVM::llvm_call_function (const char *name, const Symbol &A,
const Symbol &B, const Symbol &C,
bool deriv_ptrs)
{
const Symbol *args[3];
args[0] = &A;
args[1] = &B;
args[2] = &C;
return llvm_call_function (name, args, 3, deriv_ptrs);
return ll.call_function (name, cspan<llvm::Value*>(valargs, args.size()));
}



llvm::Value *
BackendLLVM::llvm_test_nonzero (Symbol &val, bool test_derivs)
{
Expand Down
16 changes: 11 additions & 5 deletions src/liboslexec/backendllvm.h
Expand Up @@ -376,15 +376,21 @@ class BackendLLVM : public OSOProcessorBase {
/// is true, pass pointers even for floats if they have derivs.
/// Return an llvm::Value* corresponding to the return value of the
/// function, if any.
llvm::Value *llvm_call_function (const char *name, const Symbol **args,
int nargs, bool deriv_ptrs=false);
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
llvm::Value *llvm_call_function (const char *name, cspan<const Symbol *> args,
bool deriv_ptrs=false);
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
const Symbol &B, bool deriv_ptrs=false);
bool deriv_ptrs=false) {
return llvm_call_function (name, { &A }, deriv_ptrs);
}
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
const Symbol &B, bool deriv_ptrs=false) {
return llvm_call_function (name, { &A, &B }, deriv_ptrs);
}
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
const Symbol &B, const Symbol &C,
bool deriv_ptrs=false);
bool deriv_ptrs=false) {
return llvm_call_function (name, { &A, &B, &C }, deriv_ptrs);
}

TypeDesc llvm_typedesc (const TypeSpec &typespec) {
return typespec.is_closure_based()
Expand Down

0 comments on commit ae65c11

Please sign in to comment.