blob: 1bd00a0c2a612321309621dace52bb1a488a457d [file] [log] [blame]
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Authors:
* Zack Rusin zack@tungstengraphics.com
*/
#ifdef MESA_LLVM
#include "gallivm.h"
#include "gallivm_p.h"
#include "instructions.h"
#include "loweringpass.h"
#include "storage.h"
#include "tgsitollvm.h"
#include "pipe/p_context.h"
#include "pipe/p_shader_tokens.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_dump.h"
#include "util/u_memory.h"
#include "util/u_math.h"
#include <llvm/Module.h>
#include <llvm/CallingConv.h>
#include <llvm/Constants.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Instructions.h>
#include <llvm/ModuleProvider.h>
#include <llvm/Pass.h>
#include <llvm/PassManager.h>
#include <llvm/Attributes.h>
#include <llvm/Support/PatternMatch.h>
#include <llvm/ExecutionEngine/JIT.h>
#include <llvm/ExecutionEngine/Interpreter.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/LinkAllPasses.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Analysis/LoopPass.h>
#include <llvm/Target/TargetData.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Transforms/Utils/Cloning.h>
#include <sstream>
#include <fstream>
#include <iostream>
struct gallivm_cpu_engine {
llvm::ExecutionEngine *engine;
};
static struct gallivm_cpu_engine *CPU = 0;
typedef int (*fragment_shader_runner)(float x, float y,
float (*dests)[16][4],
float (*inputs)[16][4],
int num_attribs,
float (*consts)[4], int num_consts,
struct tgsi_sampler *samplers);
int gallivm_cpu_fs_exec(struct gallivm_prog *prog,
float fx, float fy,
float (*dests)[16][4],
float (*inputs)[16][4],
float (*consts)[4],
struct tgsi_sampler *samplers)
{
fragment_shader_runner runner = reinterpret_cast<fragment_shader_runner>(prog->function);
assert(runner);
return runner(fx, fy, dests, inputs, prog->num_interp,
consts, prog->num_consts,
samplers);
}
static inline llvm::Function *func_for_shader(struct gallivm_prog *prog)
{
llvm::Module *mod = prog->module;
llvm::Function *func = 0;
switch (prog->type) {
case GALLIVM_VS:
func = mod->getFunction("vs_shader");
break;
case GALLIVM_FS:
func = mod->getFunction("fs_shader");
break;
default:
assert(!"Unknown shader type!");
break;
}
return func;
}
/*!
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);
ee->DisableLazyCompilation();
cpu->engine = ee;
llvm::Function *func = func_for_shader(prog);
prog->function = ee->getPointerToFunction(func);
CPU = cpu;
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);
/*FIXME : why was this disabled ? we need it for pow/sqrt/... */
ee->DisableLazyCompilation(false);
ee->addModuleProvider(mp);
llvm::Function *func = func_for_shader(prog);
prog->function = ee->getPointerToFunction(func);
}
void gallivm_cpu_engine_delete(struct gallivm_cpu_engine *cpu)
{
free(cpu);
}
struct gallivm_cpu_engine * gallivm_global_cpu_engine()
{
return CPU;
}
typedef void (*vertex_shader_runner)(void *ainputs,
void *dests,
float (*aconsts)[4]);
#define MAX_TGSI_VERTICES 4
/*!
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_cpu_vs_exec(struct gallivm_prog *prog,
struct tgsi_exec_machine *machine,
const float (*input)[4],
unsigned num_inputs,
float (*output)[4],
unsigned num_outputs,
const float (*constants)[4],
unsigned count,
unsigned input_stride,
unsigned output_stride )
{
unsigned int i, j;
unsigned slot;
vertex_shader_runner runner = reinterpret_cast<vertex_shader_runner>(prog->function);
assert(runner);
for (i = 0; i < count; i += MAX_TGSI_VERTICES) {
unsigned int max_vertices = MIN2(MAX_TGSI_VERTICES, count - i);
/* Swizzle inputs.
*/
for (j = 0; j < max_vertices; j++) {
for (slot = 0; slot < num_inputs; slot++) {
machine->Inputs[slot].xyzw[0].f[j] = input[slot][0];
machine->Inputs[slot].xyzw[1].f[j] = input[slot][1];
machine->Inputs[slot].xyzw[2].f[j] = input[slot][2];
machine->Inputs[slot].xyzw[3].f[j] = input[slot][3];
}
input = (const float (*)[4])((const char *)input + input_stride);
}
/* run shader */
runner(machine->Inputs,
machine->Outputs,
(float (*)[4]) constants);
/* Unswizzle all output results
*/
for (j = 0; j < max_vertices; j++) {
for (slot = 0; slot < num_outputs; slot++) {
output[slot][0] = machine->Outputs[slot].xyzw[0].f[j];
output[slot][1] = machine->Outputs[slot].xyzw[1].f[j];
output[slot][2] = machine->Outputs[slot].xyzw[2].f[j];
output[slot][3] = machine->Outputs[slot].xyzw[3].f[j];
}
output = (float (*)[4])((char *)output + output_stride);
}
}
return 0;
}
#endif