Refactor the LLVM code a bit.

Move the CPU vertex shader execution code to the draw
module, remove traces of LLVM from the state tracker,
abstract execution engine for the purposes of the draw module.
This commit is contained in:
Zack Rusin 2007-10-29 08:27:32 -04:00 committed by Keith Whitwell
parent abe8cd1917
commit 25b17b213b
6 changed files with 97 additions and 26 deletions

View file

@ -50,6 +50,8 @@
#include "pipe/tgsi/exec/tgsi_core.h"
struct gallivm_prog;
struct gallivm_cpu_engine;
/**
* Basic vertex info.
* Carry some useful information around with the vertices in the prim pipe.
@ -127,6 +129,9 @@ struct draw_vertex_shader {
#if defined(__i386__) || defined(__386__)
struct x86_function sse2_program;
#endif
#ifdef MESA_LLVM
struct gallivm_prog *llvm_prog;
#endif
};
/**
@ -226,6 +231,9 @@ struct draw_context
} pq;
int use_sse : 1;
#ifdef MESA_LLVM
struct gallivm_cpu_engine *engine;
#endif
};

View file

@ -39,6 +39,7 @@
#include "x86/rtasm/x86sse.h"
#include "pipe/tgsi/exec/tgsi_core.h"
#include "pipe/llvm/llvmtgsi.h"
#define DBG 0
@ -187,7 +188,7 @@ void draw_vertex_shader_queue_flush( struct draw_context *draw )
// fprintf(stderr, " q(%d) ", draw->vs.queue_nr );
#ifdef MESA_LLVM
if (draw->vertex_shader->state->llvm_prog) {
if (draw->vertex_shader->llvm_prog) {
draw_vertex_shader_queue_flush_llvm(draw);
return;
}
@ -233,6 +234,13 @@ draw_create_vertex_shader(struct draw_context *draw,
tgsi_emit_sse2( sh->tokens, &vs->sse2_program );
}
#endif
#ifdef MESA_LLVM
vs->llvm_prog = gallivm_from_tgsi(shader->tokens);
if (!draw->engine)
draw->engine = gallivm_cpu_engine_create(vs->llvm_prog);
else
gallivm_cpu_jit_compile(draw->engine, vs->llvm_prog);
#endif
return vs;
}

View file

@ -125,7 +125,7 @@ void draw_vertex_shader_queue_flush_llvm(struct draw_context *draw)
float inputs[VS_QUEUE_LENGTH][PIPE_MAX_SHADER_INPUTS][4];
float outputs[VS_QUEUE_LENGTH][PIPE_MAX_SHADER_INPUTS][4];
float (*consts)[4] = (float (*)[4]) draw->mapped_constants;
struct gallivm_prog *prog = (struct gallivm_prog *)draw->vertex_shader->state->llvm_prog;
struct gallivm_prog *prog = draw->vertex_shader->llvm_prog;
const float *scale = draw->viewport.scale;
const float *trans = draw->viewport.translate;

View file

@ -70,12 +70,16 @@
#ifdef MESA_LLVM
struct gallivm_prog {
void *module;
llvm::Module *module;
void *function;
int num_consts;
int id;
};
struct gallivm_cpu_engine {
llvm::ExecutionEngine *engine;
};
using namespace llvm;
#include "llvm_base_shader.cpp"
@ -698,13 +702,21 @@ tgsi_to_llvm(struct gallivm_prog *prog, const struct tgsi_token *tokens)
return mod;
}
/*!
Translates the TGSI tokens into LLVM format. Translated representation
is stored in the gallivm_prog and returned.
After calling this function the gallivm_prog can either be used with a custom
code generator to generate machine code for the GPU which the code generator
addresses or it can be jit compiled with gallivm_cpu_jit_compile and executed
with gallivm_prog_exec to run the module on the CPU.
*/
struct gallivm_prog *
gallivm_from_tgsi(struct pipe_context *pipe, const struct tgsi_token *tokens)
gallivm_from_tgsi(const struct tgsi_token *tokens)
{
std::cout << "Creating llvm from: " <<std::endl;
++GLOBAL_ID;
struct gallivm_prog *gallivm =
(struct gallivm_prog *)malloc(sizeof(struct gallivm_prog));
(struct gallivm_prog *)calloc(1, sizeof(struct gallivm_prog));
gallivm->id = GLOBAL_ID;
tgsi_dump(tokens, 0);
@ -718,20 +730,8 @@ gallivm_from_tgsi(struct pipe_context *pipe, const struct tgsi_token *tokens)
AddStandardCompilePasses(passes);
passes.run(*mod);
llvm::ExistingModuleProvider *mp = new llvm::ExistingModuleProvider(mod);
llvm::ExecutionEngine *ee = 0;
if (!pipe->llvm_execution_engine) {
ee = llvm::ExecutionEngine::create(mp, false);
pipe->llvm_execution_engine = ee;
} else {
ee = (llvm::ExecutionEngine*)pipe->llvm_execution_engine;
ee->addModuleProvider(mp);
}
gallivm->module = mod;
Function *func = mod->getFunction("run_vertex_shader");
gallivm->function = ee->getPointerToFunctionOrStub(func);
gallivm_prog_dump(gallivm, 0);
return gallivm;
@ -754,6 +754,12 @@ typedef void (*vertex_shader_runner)(float (*ainputs)[PIPE_MAX_SHADER_INPUTS][4]
int num_attribs,
int num_consts);
/*!
This function is used to execute the gallivm_prog in software. Before calling
this function the gallivm_prog has to be JIT compiled with the gallivm_cpu_jit_compile
function.
*/
int gallivm_prog_exec(struct gallivm_prog *prog,
float (*inputs)[PIPE_MAX_SHADER_INPUTS][4],
float (*dests)[PIPE_MAX_SHADER_INPUTS][4],
@ -763,6 +769,7 @@ int gallivm_prog_exec(struct gallivm_prog *prog,
int num_attribs)
{
vertex_shader_runner runner = reinterpret_cast<vertex_shader_runner>(prog->function);
assert(runner);
runner(inputs, dests, consts, num_vertices, num_inputs,
num_attribs, prog->num_consts);
@ -803,4 +810,53 @@ void gallivm_prog_dump(struct gallivm_prog *prog, const char *file_prefix)
}
}
/*!
This function creates a CPU based execution engine for the given gallivm_prog.
gallivm_cpu_engine should be used as a singleton throughout the library. Before
executing gallivm_prog_exec one needs to call gallivm_cpu_jit_compile.
The gallivm_prog instance which is being passed to the constructor is being
automatically JIT compiled so one shouldn't call gallivm_cpu_jit_compile
with it again.
*/
struct gallivm_cpu_engine * gallivm_cpu_engine_create(struct gallivm_prog *prog)
{
struct gallivm_cpu_engine *cpu = (struct gallivm_cpu_engine *)
calloc(1, sizeof(struct gallivm_cpu_engine));
llvm::Module *mod = static_cast<llvm::Module*>(prog->module);
llvm::ExistingModuleProvider *mp = new llvm::ExistingModuleProvider(mod);
llvm::ExecutionEngine *ee = llvm::ExecutionEngine::create(mp, false);
cpu->engine = ee;
llvm::Function *func = mod->getFunction("run_vertex_shader");
prog->function = ee->getPointerToFunctionOrStub(func);
return cpu;
}
/*!
This function JIT compiles the given gallivm_prog with the given cpu based execution engine.
The reference to the generated machine code entry point will be stored
in the gallivm_prog program. After executing this function one can call gallivm_prog_exec
in order to execute the gallivm_prog on the CPU.
*/
void gallivm_cpu_jit_compile(struct gallivm_cpu_engine *cpu, struct gallivm_prog *prog)
{
llvm::Module *mod = static_cast<llvm::Module*>(prog->module);
llvm::ExistingModuleProvider *mp = new llvm::ExistingModuleProvider(mod);
llvm::ExecutionEngine *ee = cpu->engine;
assert(ee);
ee->addModuleProvider(mp);
llvm::Function *func = mod->getFunction("run_vertex_shader");
prog->function = ee->getPointerToFunctionOrStub(func);
}
void gallivm_cpu_engine_delete(struct gallivm_cpu_engine *cpu)
{
free(cpu);
}
#endif /* MESA_LLVM */

View file

@ -44,15 +44,12 @@ extern "C" {
struct tgsi_exec_machine;
struct tgsi_token;
struct tgsi_sampler;
struct pipe_context;
struct gallivm_prog;
struct gallivm_cpu_engine;
struct gallivm_prog *
gallivm_from_tgsi(struct pipe_context *pipe, const struct tgsi_token *tokens);
struct gallivm_prog *gallivm_from_tgsi(const struct tgsi_token *tokens);
void gallivm_prog_delete(struct gallivm_prog *prog);
int gallivm_prog_exec(struct gallivm_prog *prog,
float (*inputs)[PIPE_MAX_SHADER_INPUTS][4],
float (*dests)[PIPE_MAX_SHADER_INPUTS][4],
@ -60,9 +57,13 @@ int gallivm_prog_exec(struct gallivm_prog *prog,
int num_vertices,
int num_inputs,
int num_attribs);
void gallivm_prog_dump(struct gallivm_prog *prog, const char *file_prefix);
struct gallivm_cpu_engine *gallivm_cpu_engine_create(struct gallivm_prog *prog);
void gallivm_cpu_jit_compile(struct gallivm_cpu_engine *ee, struct gallivm_prog *prog);
void gallivm_cpu_engine_delete(struct gallivm_cpu_engine *ee);
#endif /* MESA_LLVM */
#if defined __cplusplus

View file

@ -251,9 +251,7 @@ st_translate_vertex_program(struct st_context *st,
tokensOut, maxTokens);
vs.tokens = tokensOut;
#ifdef MESA_LLVM
vs.llvm_prog = (void*)gallivm_from_tgsi(st->pipe, vs.tokens);
#endif
cso = st_cached_vs_state(st, &vs);
stvp->vs = cso;