Refactor the LLVM code a bit.
authorZack Rusin <zack@tungstengraphics.com>
Mon, 29 Oct 2007 12:27:32 +0000 (08:27 -0400)
committerKeith Whitwell <keith@tungstengraphics.com>
Mon, 29 Oct 2007 16:14:10 +0000 (16:14 +0000)
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.

src/mesa/pipe/draw/draw_private.h
src/mesa/pipe/draw/draw_vertex_shader.c
src/mesa/pipe/draw/draw_vertex_shader_llvm.c
src/mesa/pipe/llvm/llvmtgsi.cpp
src/mesa/pipe/llvm/llvmtgsi.h
src/mesa/state_tracker/st_program.c

index ac47d2a..f52ff0b 100644 (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
 };
 
 
index 9dbb317..7fd1729 100644 (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;
 }
index c0720d2..b340ab3 100644 (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;
 
index af60232..b57a0f8 100644 (file)
 #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 */
+
+
index d4cf61c..a76dfd6 100644 (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
index 8c61815..706238c 100644 (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;