Quellcode durchsuchen

gallivm: Add a new interface for doing TGSI->LLVM conversions

lp_bld_tgsi_soa.c has been adapted to use this new interface, but
lp_bld_tgsi_aos.c has only been partially adapted, since nothing in
gallium currently uses it.

v2:
- Rename lp_bld_tgsi_action.[ch] => lp_bld_tgsi_action.[ch]
- Initialize tgsi_info in lp_bld_tgsi_aos.c
- Fix copyright dates
tags/i965-primitive-restart-v2
Tom Stellard vor 14 Jahren
Ursprung
Commit
bc2875aa48

+ 2
- 0
src/gallium/auxiliary/Makefile.sources Datei anzeigen

@@ -176,6 +176,8 @@ GALLIVM_SOURCES := \
gallivm/lp_bld_sample_soa.c \
gallivm/lp_bld_struct.c \
gallivm/lp_bld_swizzle.c \
gallivm/lp_bld_tgsi.c \
gallivm/lp_bld_tgsi_action.c \
gallivm/lp_bld_tgsi_aos.c \
gallivm/lp_bld_tgsi_info.c \
gallivm/lp_bld_tgsi_soa.c \

+ 409
- 0
src/gallium/auxiliary/gallivm/lp_bld_tgsi.c Datei anzeigen

@@ -0,0 +1,409 @@
/**************************************************************************
*
* Copyright 2011-2012 Advanced Micro Devices, Inc.
* Copyright 2010 VMware, Inc.
* Copyright 2009 VMware, Inc.
* Copyright 2007-2008 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 VMWARE 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.
*
**************************************************************************/

#include "gallivm/lp_bld_tgsi.h"

#include "gallivm/lp_bld_arit.h"
#include "gallivm/lp_bld_gather.h"
#include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_intr.h"
#include "tgsi/tgsi_info.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_util.h"
#include "util/u_memory.h"

/* The user is responsible for freeing list->instructions */
unsigned lp_bld_tgsi_list_init(struct lp_build_tgsi_context * bld_base)
{
bld_base->instructions = (struct tgsi_full_instruction *)
MALLOC( LP_MAX_INSTRUCTIONS * sizeof(struct tgsi_full_instruction) );
if (!bld_base->instructions) {
return 0;
}
bld_base->max_instructions = LP_MAX_INSTRUCTIONS;
return 1;
}


unsigned lp_bld_tgsi_add_instruction(
struct lp_build_tgsi_context * bld_base,
struct tgsi_full_instruction *inst_to_add)
{

if (bld_base->num_instructions == bld_base->max_instructions) {
struct tgsi_full_instruction *instructions;
instructions = REALLOC(bld_base->instructions, bld_base->max_instructions
* sizeof(struct tgsi_full_instruction),
(bld_base->max_instructions + LP_MAX_INSTRUCTIONS)
* sizeof(struct tgsi_full_instruction));
if (!instructions) {
return 0;
}
bld_base->instructions = instructions;
bld_base->max_instructions += LP_MAX_INSTRUCTIONS;
}
memcpy(bld_base->instructions + bld_base->num_instructions, inst_to_add,
sizeof(bld_base->instructions[0]));

bld_base->num_instructions++;

return 1;
}


/**
* This function assumes that all the args in emit_data have been set.
*/
static void
lp_build_action_set_dst_type(
struct lp_build_emit_data * emit_data,
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode)
{
if (emit_data->arg_count == 0) {
emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
} else {
/* XXX: Not all opcodes have the same src and dst types. */
emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
}
}

void
lp_build_tgsi_intrinsic(
const struct lp_build_tgsi_action * action,
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data)
{
struct lp_build_context * base = &bld_base->base;
emit_data->output[emit_data->chan] = lp_build_intrinsic(
base->gallivm->builder, action->intr_name,
emit_data->dst_type, emit_data->args, emit_data->arg_count);
}

LLVMValueRef
lp_build_emit_llvm(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
struct lp_build_emit_data * emit_data)
{
struct lp_build_tgsi_action * action = &bld_base->op_actions[tgsi_opcode];
/* XXX: Assert that this is a componentwise or replicate instruction */

lp_build_action_set_dst_type(emit_data, bld_base, tgsi_opcode);
emit_data->chan = 0;
assert(action->emit);
action->emit(action, bld_base, emit_data);
return emit_data->output[0];
}

LLVMValueRef
lp_build_emit_llvm_unary(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
LLVMValueRef arg0)
{
struct lp_build_emit_data emit_data;
emit_data.arg_count = 1;
emit_data.args[0] = arg0;
return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
}

LLVMValueRef
lp_build_emit_llvm_binary(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
LLVMValueRef arg0,
LLVMValueRef arg1)
{
struct lp_build_emit_data emit_data;
emit_data.arg_count = 2;
emit_data.args[0] = arg0;
emit_data.args[1] = arg1;
return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
}

LLVMValueRef
lp_build_emit_llvm_ternary(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
LLVMValueRef arg0,
LLVMValueRef arg1,
LLVMValueRef arg2)
{
struct lp_build_emit_data emit_data;
emit_data.arg_count = 3;
emit_data.args[0] = arg0;
emit_data.args[1] = arg1;
emit_data.args[2] = arg2;
return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
}

/**
* The default fetch implementation.
*/
void lp_build_fetch_args(
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data)
{
unsigned src;
for (src = 0; src < emit_data->info->num_src; src++) {
emit_data->args[src] = lp_build_emit_fetch(bld_base, emit_data->inst, src,
emit_data->chan);
}
emit_data->arg_count = emit_data->info->num_src;
lp_build_action_set_dst_type(emit_data, bld_base,
emit_data->inst->Instruction.Opcode);
}

/* XXX: COMMENT
* It should be assumed that this function ignores writemasks
*/
boolean
lp_build_tgsi_inst_llvm(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_instruction * inst)
{
unsigned tgsi_opcode = inst->Instruction.Opcode;
const struct tgsi_opcode_info * info = tgsi_get_opcode_info(tgsi_opcode);
const struct lp_build_tgsi_action * action =
&bld_base->op_actions[tgsi_opcode];
struct lp_build_emit_data emit_data;
unsigned chan_index;
LLVMValueRef val;

bld_base->pc++;

/* Ignore deprecated instructions */
switch (inst->Instruction.Opcode) {

case TGSI_OPCODE_RCC:
case TGSI_OPCODE_UP2H:
case TGSI_OPCODE_UP2US:
case TGSI_OPCODE_UP4B:
case TGSI_OPCODE_UP4UB:
case TGSI_OPCODE_X2D:
case TGSI_OPCODE_ARA:
case TGSI_OPCODE_BRA:
case TGSI_OPCODE_DIV:
case TGSI_OPCODE_PUSHA:
case TGSI_OPCODE_POPA:
case TGSI_OPCODE_I2F:
case TGSI_OPCODE_NOT:
case TGSI_OPCODE_SHL:
case TGSI_OPCODE_ISHR:
case TGSI_OPCODE_AND:
case TGSI_OPCODE_OR:
case TGSI_OPCODE_MOD:
case TGSI_OPCODE_XOR:
case TGSI_OPCODE_SAD:
case TGSI_OPCODE_TXF:
case TGSI_OPCODE_TXQ:
/* deprecated? */
assert(0);
return FALSE;
break;
}

/* Check if the opcode has been implemented */
if (!action->emit) {
return FALSE;
}

memset(&emit_data, 0, sizeof(emit_data));

assert(info->num_dst <= 1);
if (info->num_dst) {
TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
emit_data.output[chan_index] = bld_base->base.undef;
}
}

emit_data.inst = inst;
emit_data.info = info;

/* Emit the instructions */
if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) {
TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
emit_data.chan = chan_index;
if (!action->fetch_args) {
lp_build_fetch_args(bld_base, &emit_data);
} else {
action->fetch_args(bld_base, &emit_data);
}
action->emit(action, bld_base, &emit_data);
}
} else {
emit_data.chan = LP_CHAN_ALL;
if (action->fetch_args) {
action->fetch_args(bld_base, &emit_data);
}
/* Make sure the output value is stored in emit_data.output[0], unless
* the opcode is channel dependent */
if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) {
emit_data.chan = 0;
}
action->emit(action, bld_base, &emit_data);

/* Replicate the output values */
if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) {
val = emit_data.output[0];
memset(emit_data.output, 0, sizeof(emit_data.output));
TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
emit_data.output[chan_index] = val;
}
}
}

if (info->num_dst > 0) {
bld_base->emit_store(bld_base, inst, info, emit_data.output);
}
return TRUE;
}


LLVMValueRef
lp_build_emit_fetch(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_instruction *inst,
unsigned src_op,
const unsigned chan_index)
{
const struct tgsi_full_src_register *reg = &inst->Src[src_op];
unsigned swizzle;
LLVMValueRef res;

if (chan_index == LP_CHAN_ALL) {
swizzle = ~0;
} else {
swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index);
if (swizzle > 3) {
assert(0 && "invalid swizzle in emit_fetch()");
return bld_base->base.undef;
}
}

assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]);

if (bld_base->emit_fetch_funcs[reg->Register.File]) {
res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg,
swizzle);
} else {
assert(0 && "invalid src register in emit_fetch()");
return bld_base->base.undef;
}

if (reg->Register.Absolute) {
res = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS, res);
}

if (reg->Register.Negate) {
res = lp_build_negate( &bld_base->base, res );
}

/*
* Swizzle the argument
*/

if (swizzle == ~0) {
res = bld_base->emit_swizzle(bld_base, res,
reg->Register.SwizzleX,
reg->Register.SwizzleY,
reg->Register.SwizzleZ,
reg->Register.SwizzleW);
}

return res;

}

boolean
lp_build_tgsi_llvm(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_token *tokens)
{
struct tgsi_parse_context parse;

if (bld_base->emit_prologue) {
bld_base->emit_prologue(bld_base);
}

if (!lp_bld_tgsi_list_init(bld_base)) {
return FALSE;
}

tgsi_parse_init( &parse, tokens );

while( !tgsi_parse_end_of_tokens( &parse ) ) {
tgsi_parse_token( &parse );

switch( parse.FullToken.Token.Type ) {
case TGSI_TOKEN_TYPE_DECLARATION:
/* Inputs already interpolated */
bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration);
break;

case TGSI_TOKEN_TYPE_INSTRUCTION:
lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction);
break;

case TGSI_TOKEN_TYPE_IMMEDIATE:
bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate);
break;

case TGSI_TOKEN_TYPE_PROPERTY:
break;

default:
assert( 0 );
}
}

while (bld_base->pc != -1) {
struct tgsi_full_instruction *instr = bld_base->instructions +
bld_base->pc;
const struct tgsi_opcode_info *opcode_info =
tgsi_get_opcode_info(instr->Instruction.Opcode);
if (!lp_build_tgsi_inst_llvm(bld_base, instr)) {
_debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
opcode_info->mnemonic);
return FALSE;
}
}

tgsi_parse_free(&parse);

FREE(bld_base->instructions);

if (bld_base->emit_epilogue) {
bld_base->emit_epilogue(bld_base);
}

return TRUE;
}

+ 339
- 2
src/gallium/auxiliary/gallivm/lp_bld_tgsi.h Datei anzeigen

@@ -1,5 +1,6 @@
/**************************************************************************
*
* Copyright 2011-2012 Advanced Micro Devices, Inc.
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
@@ -30,21 +31,33 @@
* TGSI to LLVM IR translation.
*
* @author Jose Fonseca <jfonseca@vmware.com>
* @author Tom Stellard <thomas.stellard@amd.com>
*/

#ifndef LP_BLD_TGSI_H
#define LP_BLD_TGSI_H

#include "gallivm/lp_bld.h"
#include "gallivm/lp_bld_tgsi_action.h"
#include "gallivm/lp_bld_limits.h"
#include "lp_bld_type.h"
#include "pipe/p_compiler.h"
#include "pipe/p_state.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_scan.h"


#define LP_CHAN_ALL ~0

#define LP_MAX_INSTRUCTIONS 256

struct tgsi_full_declaration;
struct tgsi_full_immediate;
struct tgsi_full_instruction;
struct tgsi_full_src_register;
struct tgsi_opcode_info;
struct tgsi_token;
struct tgsi_shader_info;
struct lp_type;
struct lp_build_context;
struct lp_build_mask_context;
struct gallivm_state;

@@ -207,4 +220,328 @@ lp_build_system_values_array(struct gallivm_state *gallivm,
LLVMValueRef facing);


struct lp_exec_mask {
struct lp_build_context *bld;

boolean has_mask;

LLVMTypeRef int_vec_type;

LLVMValueRef cond_stack[LP_MAX_TGSI_NESTING];
int cond_stack_size;
LLVMValueRef cond_mask;

LLVMBasicBlockRef loop_block;
LLVMValueRef cont_mask;
LLVMValueRef break_mask;
LLVMValueRef break_var;
struct {
LLVMBasicBlockRef loop_block;
LLVMValueRef cont_mask;
LLVMValueRef break_mask;
LLVMValueRef break_var;
} loop_stack[LP_MAX_TGSI_NESTING];
int loop_stack_size;

LLVMValueRef ret_mask;
struct {
int pc;
LLVMValueRef ret_mask;
} call_stack[LP_MAX_TGSI_NESTING];
int call_stack_size;

LLVMValueRef exec_mask;
};

struct lp_build_tgsi_inst_list
{
struct tgsi_full_instruction *instructions;
uint max_instructions;
uint num_instructions;
};

unsigned lp_bld_tgsi_list_init(struct lp_build_tgsi_context * bld_base);


unsigned lp_bld_tgsi_add_instruction(
struct lp_build_tgsi_context * bld_base,
struct tgsi_full_instruction *inst_to_add);


struct lp_build_tgsi_context;


typedef LLVMValueRef (*lp_build_emit_fetch_fn)(struct lp_build_tgsi_context *,
const struct tgsi_full_src_register *,
unsigned);

struct lp_build_tgsi_context
{
struct lp_build_context base;

/** This array stores functions that are used to transform TGSI opcodes to
* LLVM instructions.
*/
struct lp_build_tgsi_action op_actions[TGSI_OPCODE_LAST];

/* TGSI_OPCODE_RSQ is defined as 1 / sqrt( abs(src0.x) ), rsq_action
* should compute 1 / sqrt (src0.x) */
struct lp_build_tgsi_action rsq_action;

const struct tgsi_shader_info *info;

lp_build_emit_fetch_fn emit_fetch_funcs[TGSI_FILE_COUNT];

LLVMValueRef (*emit_swizzle)(struct lp_build_tgsi_context *,
LLVMValueRef, unsigned, unsigned, unsigned, unsigned);

void (*emit_store)(struct lp_build_tgsi_context *,
const struct tgsi_full_instruction *,
const struct tgsi_opcode_info *,
LLVMValueRef dst[4]);

void (*emit_declaration)(struct lp_build_tgsi_context *,
const struct tgsi_full_declaration *decl);

void (*emit_immediate)(struct lp_build_tgsi_context *,
const struct tgsi_full_immediate *imm);


/* Allow the user to store data in this structure rather than passing it
* to every function. */
void * userdata;

boolean soa;

int pc;

struct tgsi_full_instruction *instructions;
uint max_instructions;
uint num_instructions;

/** This function allows the user to insert some instructions at the
* beginning of the program. It is optional and does not need to be
* implemented.
*/
void (*emit_prologue)(struct lp_build_tgsi_context*);

/** This function allows the user to insert some instructions at the end of
* the program. This callback is intended to be used for emitting
* instructions to handle the export for the output registers, but it can
* be used for any purpose. Implementing this function is optiona, but
* recommended.
*/
void (*emit_epilogue)(struct lp_build_tgsi_context*);
};

struct lp_build_tgsi_soa_context
{
struct lp_build_tgsi_context bld_base;

/* Builder for vector integer masks and indices */
struct lp_build_context uint_bld;

/* Builder for scalar elements of shader's data type (float) */
struct lp_build_context elem_bld;

LLVMValueRef consts_ptr;
const LLVMValueRef *pos;
const LLVMValueRef (*inputs)[TGSI_NUM_CHANNELS];
LLVMValueRef (*outputs)[TGSI_NUM_CHANNELS];

const struct lp_build_sampler_soa *sampler;

LLVMValueRef immediates[LP_MAX_TGSI_IMMEDIATES][TGSI_NUM_CHANNELS];
LLVMValueRef temps[LP_MAX_TGSI_TEMPS][TGSI_NUM_CHANNELS];
LLVMValueRef addr[LP_MAX_TGSI_ADDRS][TGSI_NUM_CHANNELS];
LLVMValueRef preds[LP_MAX_TGSI_PREDS][TGSI_NUM_CHANNELS];

/* We allocate/use this array of temps if (1 << TGSI_FILE_TEMPORARY) is
* set in the indirect_files field.
* The temps[] array above is unused then.
*/
LLVMValueRef temps_array;

/* We allocate/use this array of output if (1 << TGSI_FILE_OUTPUT) is
* set in the indirect_files field.
* The outputs[] array above is unused then.
*/
LLVMValueRef outputs_array;

/* We allocate/use this array of inputs if (1 << TGSI_FILE_INPUT) is
* set in the indirect_files field.
* The inputs[] array above is unused then.
*/
LLVMValueRef inputs_array;

LLVMValueRef system_values_array;

/** bitmask indicating which register files are accessed indirectly */
unsigned indirect_files;

struct lp_build_mask_context *mask;
struct lp_exec_mask exec_mask;

uint num_immediates;

};

void
lp_emit_declaration_soa(
struct lp_build_tgsi_context *bld,
const struct tgsi_full_declaration *decl);

void lp_emit_immediate_soa(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_immediate *imm);

boolean
lp_emit_instruction_soa(
struct lp_build_tgsi_soa_context *bld,
const struct tgsi_full_instruction *inst,
const struct tgsi_opcode_info *info);


LLVMValueRef
lp_get_temp_ptr_soa(
struct lp_build_tgsi_soa_context *bld,
unsigned index,
unsigned chan);

LLVMValueRef
lp_get_output_ptr(
struct lp_build_tgsi_soa_context *bld,
unsigned index,
unsigned chan);

struct lp_build_tgsi_aos_context
{
struct lp_build_tgsi_context bld_base;

/* Builder for integer masks and indices */
struct lp_build_context int_bld;

/*
* AoS swizzle used:
* - swizzles[0] = red index
* - swizzles[1] = green index
* - swizzles[2] = blue index
* - swizzles[3] = alpha index
*/
unsigned char swizzles[4];
unsigned char inv_swizzles[4];

LLVMValueRef consts_ptr;
const LLVMValueRef *inputs;
LLVMValueRef *outputs;

struct lp_build_sampler_aos *sampler;

LLVMValueRef immediates[LP_MAX_TGSI_IMMEDIATES];
LLVMValueRef temps[LP_MAX_TGSI_TEMPS];
LLVMValueRef addr[LP_MAX_TGSI_ADDRS];
LLVMValueRef preds[LP_MAX_TGSI_PREDS];

/* We allocate/use this array of temps if (1 << TGSI_FILE_TEMPORARY) is
* set in the indirect_files field.
* The temps[] array above is unused then.
*/
LLVMValueRef temps_array;

/** bitmask indicating which register files are accessed indirectly */
unsigned indirect_files;

};

static INLINE struct lp_build_tgsi_soa_context *
lp_soa_context(struct lp_build_tgsi_context *bld_base)
{
return (struct lp_build_tgsi_soa_context *)bld_base;
}

static INLINE struct lp_build_tgsi_aos_context *
lp_aos_context(struct lp_build_tgsi_context *bld_base)
{
return (struct lp_build_tgsi_aos_context *)bld_base;
}

void
lp_emit_declaration_aos(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_declaration *decl);


boolean
lp_emit_instruction_aos(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_instruction *inst,
const struct tgsi_opcode_info *info,
int *pc);

void
lp_emit_store_aos(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_instruction *inst,
unsigned index,
LLVMValueRef value);

void lp_build_fetch_args(
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data);

LLVMValueRef
lp_build_tgsi_inst_llvm_aos(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_instruction *inst);

void
lp_build_tgsi_intrinsic(
const struct lp_build_tgsi_action * action,
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data);

LLVMValueRef
lp_build_emit_llvm(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
struct lp_build_emit_data * emit_data);

LLVMValueRef
lp_build_emit_llvm_unary(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
LLVMValueRef arg0);

LLVMValueRef
lp_build_emit_llvm_binary(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
LLVMValueRef arg0,
LLVMValueRef arg1);

LLVMValueRef
lp_build_emit_llvm_ternary(
struct lp_build_tgsi_context *bld_base,
unsigned tgsi_opcode,
LLVMValueRef arg0,
LLVMValueRef arg1,
LLVMValueRef arg2);

boolean
lp_build_tgsi_inst_llvm(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_instruction *inst);

LLVMValueRef
lp_build_emit_fetch(
struct lp_build_tgsi_context *bld_base,
const struct tgsi_full_instruction *inst,
unsigned src_op,
const unsigned chan_index);

boolean
lp_build_tgsi_llvm(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_token *tokens);

#endif /* LP_BLD_TGSI_H */

+ 1182
- 0
src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 138
- 0
src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.h Datei anzeigen

@@ -0,0 +1,138 @@
/*
* Copyright 2011-2012 Advanced Micro Devices, Inc.
* 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.
*
**************************************************************************/

/**
*
* @author Tom Stellard <thomas.stellard@amd.com>
*
*/


#ifndef LP_BLD_TGSI_ACTION_H
#define LP_BLD_TGSI_ACTION_H

#include <llvm-c/Core.h>

struct lp_build_tgsi_context;

struct lp_build_emit_data {
/** Arguments that are passed to lp_build_tgsi_action::emit. The
* order of the arguments should be as follows:
* SOA: s0.x, s0.y, s0.z, s0.w, s1.x, s1.y, s1.z, s1.w, s2.x, s2.y, s2.x, s2.w
* AOS: s0.xyzw, s1.xyzw, s2.xyzw
* TEXTURE Instructions: coord.xyzw
*
* Arguments should be packed into the args array. For example an SOA
* instructions that reads s0.x and s1.x args should look like this:
* args[0] = s0.x;
* args[1] = s1.x;
*/
LLVMValueRef args[12];

/**
* Number of arguments in the args array.
*/
unsigned arg_count;

/**
* The type output type of the opcode. This should be set in the
* lp_build_tgsi_action::fetch_args function.
*/
LLVMTypeRef dst_type;

/** This is used by the lp_build_tgsi_action::fetch_args function to
* determine which channel to read from the opcode arguments. It also
* specifies which index of the output array should be written to by
* the lp_build_tgsi_action::emit function. However, this value is
* usually ignored by any opcodes that are not TGSI_OUTPUT_COMPONENTWISE.
*/
unsigned chan;

/** The lp_build_tgsi_action::emit 'executes' the opcode and writes the
* results to this array.
*/
LLVMValueRef output[4];

/**
* The current instruction that is being 'executed'.
*/
const struct tgsi_full_instruction * inst;
const struct tgsi_opcode_info * info;
};

struct lp_build_tgsi_action
{

/**
* This function is responsible for doing 2-3 things:
* 1. Fetching the instruction arguments into the emit_data->args array.
* 2. Setting the number of arguments in emit_data->arg_count.
* 3. Setting the destination type in emit_data->dst_type (usually only
* necessary for opcodes that are TGSI_OUTPUT_COMPONENTWISE).
*/
void (*fetch_args)(struct lp_build_tgsi_context *,
struct lp_build_emit_data *);


/**
* This function is responsible for emitting LLVM IR for a TGSI opcode.
* It should store the values it generates in the emit_data->output array
* and for TGSI_OUTPUT_COMPONENTWISE and TGSI_OUTPUT_REPLICATE instructions
* (and possibly others depending on the specific implementation), it should
* make sure to store the values in the array slot indexed by emit_data->chan.
*/
void (*emit)(const struct lp_build_tgsi_action *,
struct lp_build_tgsi_context *,
struct lp_build_emit_data *);

/**
* This variable can be used to store an intrinsic name, in case the TGSI
* opcode will be replaced by a target specific intrinsic. (There is a
* convenience function in lp_bld_tgsi.c called lp_build_tgsi_intrinsic()
* that can be assigned to lp_build_tgsi_action::emit and used for
* generating intrinsics).
*/
const char * intr_name;
};

/**
* This function initializes the bld_base->op_actions array with some
* generic operand actions.
*/
void
lp_set_default_actions(
struct lp_build_tgsi_context * bld_base);

/*
* This function initialize the bld_base->op_actions array with some
* operand actions that are intended only for use when generating
* instructions to be executed on a CPU.
*/
void
lp_set_default_actions_cpu(
struct lp_build_tgsi_context * bld_base);

#endif /* LP_BLD_TGSI_ACTION_H */

+ 237
- 316
src/gallium/auxiliary/gallivm/lp_bld_tgsi_aos.c Datei anzeigen

@@ -55,61 +55,15 @@
#include "lp_bld_flow.h"
#include "lp_bld_quad.h"
#include "lp_bld_tgsi.h"
#include "lp_bld_limits.h"
#include "lp_bld_debug.h"


#define LP_MAX_INSTRUCTIONS 256


struct lp_build_tgsi_aos_context
{
struct lp_build_context base;

/* Builder for integer masks and indices */
struct lp_build_context int_bld;

/*
* AoS swizzle used:
* - swizzles[0] = red index
* - swizzles[1] = green index
* - swizzles[2] = blue index
* - swizzles[3] = alpha index
*/
unsigned char swizzles[4];
unsigned char inv_swizzles[4];

LLVMValueRef consts_ptr;
const LLVMValueRef *inputs;
LLVMValueRef *outputs;

struct lp_build_sampler_aos *sampler;

LLVMValueRef immediates[LP_MAX_TGSI_IMMEDIATES];
LLVMValueRef temps[LP_MAX_TGSI_TEMPS];
LLVMValueRef addr[LP_MAX_TGSI_ADDRS];
LLVMValueRef preds[LP_MAX_TGSI_PREDS];

/* We allocate/use this array of temps if (1 << TGSI_FILE_TEMPORARY) is
* set in the indirect_files field.
* The temps[] array above is unused then.
*/
LLVMValueRef temps_array;

/** bitmask indicating which register files are accessed indirectly */
unsigned indirect_files;

struct tgsi_full_instruction *instructions;
uint max_instructions;
};


/**
* Wrapper around lp_build_swizzle_aos which translates swizzles to another
* ordering.
*/
static LLVMValueRef
swizzle_aos(struct lp_build_tgsi_aos_context *bld,
swizzle_aos(struct lp_build_tgsi_context *bld_base,
LLVMValueRef a,
unsigned swizzle_x,
unsigned swizzle_y,
@@ -117,6 +71,7 @@ swizzle_aos(struct lp_build_tgsi_aos_context *bld,
unsigned swizzle_w)
{
unsigned char swizzles[4];
struct lp_build_tgsi_aos_context *bld = lp_aos_context(bld_base);

assert(swizzle_x < 4);
assert(swizzle_y < 4);
@@ -128,7 +83,7 @@ swizzle_aos(struct lp_build_tgsi_aos_context *bld,
swizzles[bld->inv_swizzles[2]] = bld->swizzles[swizzle_z];
swizzles[bld->inv_swizzles[3]] = bld->swizzles[swizzle_w];

return lp_build_swizzle_aos(&bld->base, a, swizzles);
return lp_build_swizzle_aos(&bld->bld_base.base, a, swizzles);
}


@@ -138,149 +93,133 @@ swizzle_scalar_aos(struct lp_build_tgsi_aos_context *bld,
unsigned chan)
{
chan = bld->swizzles[chan];
return lp_build_swizzle_scalar_aos(&bld->base, a, chan);
return lp_build_swizzle_scalar_aos(&bld->bld_base.base, a, chan);
}


/**
* Register fetch.
*/
static LLVMValueRef
emit_fetch(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_instruction *inst,
unsigned src_op)
emit_fetch_constant(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_src_register * reg,
const unsigned swizzle)
{
LLVMBuilderRef builder = bld->base.gallivm->builder;
struct lp_type type = bld->base.type;
const struct tgsi_full_src_register *reg = &inst->Src[src_op];
struct lp_build_tgsi_aos_context * bld = lp_aos_context(bld_base);
LLVMBuilderRef builder = bld_base->base.gallivm->builder;
struct lp_type type = bld_base->base.type;
LLVMValueRef res;
unsigned chan;

assert(!reg->Register.Indirect);

/*
* Fetch the from the register file.
* Get the constants components
*/

switch (reg->Register.File) {
case TGSI_FILE_CONSTANT:
/*
* Get the constants components
*/

res = bld->base.undef;
for (chan = 0; chan < 4; ++chan) {
LLVMValueRef index;
LLVMValueRef scalar_ptr;
LLVMValueRef scalar;
LLVMValueRef swizzle;

index = lp_build_const_int32(bld->base.gallivm, reg->Register.Index * 4 + chan);

scalar_ptr = LLVMBuildGEP(builder, bld->consts_ptr,
&index, 1, "");
res = bld->bld_base.base.undef;
for (chan = 0; chan < 4; ++chan) {
LLVMValueRef index;
LLVMValueRef scalar_ptr;
LLVMValueRef scalar;
LLVMValueRef swizzle;

scalar = LLVMBuildLoad(builder, scalar_ptr, "");
index = lp_build_const_int32(bld->bld_base.base.gallivm,
reg->Register.Index * 4 + chan);

lp_build_name(scalar, "const[%u].%c", reg->Register.Index, "xyzw"[chan]);
scalar_ptr = LLVMBuildGEP(builder, bld->consts_ptr, &index, 1, "");

/*
* NOTE: constants array is always assumed to be RGBA
*/
scalar = LLVMBuildLoad(builder, scalar_ptr, "");

swizzle = lp_build_const_int32(bld->base.gallivm, bld->swizzles[chan]);

res = LLVMBuildInsertElement(builder, res, scalar, swizzle, "");
}
lp_build_name(scalar, "const[%u].%c", reg->Register.Index, "xyzw"[chan]);

/*
* Broadcast the first quaternion to all others.
*
* XXX: could be factored into a reusable function.
* NOTE: constants array is always assumed to be RGBA
*/

if (type.length > 4) {
LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH];
unsigned i;
swizzle = lp_build_const_int32(bld->bld_base.base.gallivm,
bld->swizzles[chan]);

for (chan = 0; chan < 4; ++chan) {
shuffles[chan] = lp_build_const_int32(bld->base.gallivm, chan);
}

for (i = 4; i < type.length; ++i) {
shuffles[i] = shuffles[i % 4];
}
res = LLVMBuildInsertElement(builder, res, scalar, swizzle, "");
}

res = LLVMBuildShuffleVector(builder,
res, bld->base.undef,
LLVMConstVector(shuffles, type.length),
"");
}
break;
/*
* Broadcast the first quaternion to all others.
*
* XXX: could be factored into a reusable function.
*/

case TGSI_FILE_IMMEDIATE:
res = bld->immediates[reg->Register.Index];
assert(res);
break;
if (type.length > 4) {
LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH];
unsigned i;

case TGSI_FILE_INPUT:
res = bld->inputs[reg->Register.Index];
assert(res);
break;

case TGSI_FILE_TEMPORARY:
{
LLVMValueRef temp_ptr;
temp_ptr = bld->temps[reg->Register.Index];
res = LLVMBuildLoad(builder, temp_ptr, "");
if (!res)
return bld->base.undef;
for (chan = 0; chan < 4; ++chan) {
shuffles[chan] = lp_build_const_int32(bld->bld_base.base.gallivm, chan);
}
break;

default:
assert(0 && "invalid src register in emit_fetch()");
return bld->base.undef;
}

/*
* Apply sign modifier.
*/
for (i = 4; i < type.length; ++i) {
shuffles[i] = shuffles[i % 4];
}

if (reg->Register.Absolute) {
res = lp_build_abs(&bld->base, res);
res = LLVMBuildShuffleVector(builder,
res, bld->bld_base.base.undef,
LLVMConstVector(shuffles, type.length),
"");
}
return res;
}

if(reg->Register.Negate) {
res = lp_build_negate(&bld->base, res);
}
static LLVMValueRef
emit_fetch_immediate(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_src_register * reg,
const unsigned swizzle)
{
struct lp_build_tgsi_aos_context * bld = lp_aos_context(bld_base);
LLVMValueRef res = bld->immediates[reg->Register.Index];
assert(res);
return res;
}

/*
* Swizzle the argument
*/
static LLVMValueRef
emit_fetch_input(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_src_register * reg,
const unsigned swizzle)
{
struct lp_build_tgsi_aos_context * bld = lp_aos_context(bld_base);
LLVMValueRef res = bld->inputs[reg->Register.Index];
assert(!reg->Register.Indirect);
assert(res);
return res;
}

res = swizzle_aos(bld, res,
reg->Register.SwizzleX,
reg->Register.SwizzleY,
reg->Register.SwizzleZ,
reg->Register.SwizzleW);
static LLVMValueRef
emit_fetch_temporary(
struct lp_build_tgsi_context * bld_base,
const struct tgsi_full_src_register * reg,
const unsigned swizzle)
{
struct lp_build_tgsi_aos_context * bld = lp_aos_context(bld_base);
LLVMBuilderRef builder = bld_base->base.gallivm->builder;
LLVMValueRef temp_ptr = bld->temps[reg->Register.Index];
LLVMValueRef res = LLVMBuildLoad(builder, temp_ptr, "");
assert(!reg->Register.Indirect);
if (!res)
return bld->bld_base.base.undef;

return res;
}


/**
* Register store.
*/
static void
emit_store(
void
lp_emit_store_aos(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_instruction *inst,
unsigned index,
LLVMValueRef value)
{
LLVMBuilderRef builder = bld->base.gallivm->builder;
LLVMBuilderRef builder = bld->bld_base.base.gallivm->builder;
const struct tgsi_full_dst_register *reg = &inst->Dst[index];
LLVMValueRef mask = NULL;
LLVMValueRef ptr;
@@ -294,13 +233,13 @@ emit_store(
break;

case TGSI_SAT_ZERO_ONE:
value = lp_build_max(&bld->base, value, bld->base.zero);
value = lp_build_min(&bld->base, value, bld->base.one);
value = lp_build_max(&bld->bld_base.base, value, bld->bld_base.base.zero);
value = lp_build_min(&bld->bld_base.base, value, bld->bld_base.base.one);
break;

case TGSI_SAT_MINUS_PLUS_ONE:
value = lp_build_max(&bld->base, value, lp_build_const_vec(bld->base.gallivm, bld->base.type, -1.0));
value = lp_build_min(&bld->base, value, bld->base.one);
value = lp_build_max(&bld->bld_base.base, value, lp_build_const_vec(bld->bld_base.base.gallivm, bld->bld_base.base.type, -1.0));
value = lp_build_min(&bld->bld_base.base, value, bld->bld_base.base.one);
break;

default:
@@ -335,6 +274,8 @@ emit_store(
return;
}

if (!ptr)
return;
/*
* Predicate
*/
@@ -350,17 +291,17 @@ emit_store(
/*
* Convert the value to an integer mask.
*/
pred = lp_build_compare(bld->base.gallivm,
bld->base.type,
pred = lp_build_compare(bld->bld_base.base.gallivm,
bld->bld_base.base.type,
PIPE_FUNC_NOTEQUAL,
pred,
bld->base.zero);
bld->bld_base.base.zero);

if (inst->Predicate.Negate) {
pred = LLVMBuildNot(builder, pred, "");
}

pred = swizzle_aos(bld, pred,
pred = bld->bld_base.emit_swizzle(&bld->bld_base, pred,
inst->Predicate.SwizzleX,
inst->Predicate.SwizzleY,
inst->Predicate.SwizzleZ,
@@ -380,7 +321,7 @@ emit_store(
if (reg->Register.WriteMask != TGSI_WRITEMASK_XYZW) {
LLVMValueRef writemask;

writemask = lp_build_const_mask_aos(bld->base.gallivm, bld->base.type,
writemask = lp_build_const_mask_aos(bld->bld_base.base.gallivm, bld->bld_base.base.type,
reg->Register.WriteMask);

if (mask) {
@@ -394,7 +335,7 @@ emit_store(
LLVMValueRef orig_value;

orig_value = LLVMBuildLoad(builder, ptr, "");
value = lp_build_select(&bld->base,
value = lp_build_select(&bld->bld_base.base,
mask, value, orig_value);
}

@@ -419,44 +360,44 @@ emit_tex(struct lp_build_tgsi_aos_context *bld,

if (!bld->sampler) {
_debug_printf("warning: found texture instruction but no sampler generator supplied\n");
return bld->base.undef;
return bld->bld_base.base.undef;
}

target = inst->Texture.Texture;

coords = emit_fetch( bld, inst, 0 );
coords = lp_build_emit_fetch( &bld->bld_base, inst, 0 , LP_CHAN_ALL);

if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
ddx = emit_fetch( bld, inst, 1 );
ddy = emit_fetch( bld, inst, 2 );
ddx = lp_build_emit_fetch( &bld->bld_base, inst, 1 , LP_CHAN_ALL);
ddy = lp_build_emit_fetch( &bld->bld_base, inst, 2 , LP_CHAN_ALL);
unit = inst->Src[3].Register.Index;
} else {
#if 0
ddx = lp_build_ddx( &bld->base, coords );
ddy = lp_build_ddy( &bld->base, coords );
ddx = lp_build_ddx( &bld->bld_base.base, coords );
ddy = lp_build_ddy( &bld->bld_base.base, coords );
#else
/* TODO */
ddx = bld->base.one;
ddy = bld->base.one;
ddx = bld->bld_base.base.one;
ddy = bld->bld_base.base.one;
#endif
unit = inst->Src[1].Register.Index;
}

return bld->sampler->emit_fetch_texel(bld->sampler,
&bld->base,
&bld->bld_base.base,
target, unit,
coords, ddx, ddy,
modifier);
}


static void
emit_declaration(
void
lp_emit_declaration_aos(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_declaration *decl)
{
struct gallivm_state *gallivm = bld->base.gallivm;
LLVMTypeRef vec_type = lp_build_vec_type(bld->base.gallivm, bld->base.type);
struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
LLVMTypeRef vec_type = lp_build_vec_type(bld->bld_base.base.gallivm, bld->bld_base.base.type);

unsigned first = decl->Range.First;
unsigned last = decl->Range.Last;
@@ -468,7 +409,7 @@ emit_declaration(
assert(idx < LP_MAX_TGSI_TEMPS);
if (bld->indirect_files & (1 << TGSI_FILE_TEMPORARY)) {
LLVMValueRef array_size = lp_build_const_int32(gallivm, last + 1);
bld->temps_array = lp_build_array_alloca(bld->base.gallivm,
bld->temps_array = lp_build_array_alloca(bld->bld_base.base.gallivm,
vec_type, array_size, "");
} else {
bld->temps[idx] = lp_build_alloca(gallivm, vec_type, "");
@@ -501,8 +442,8 @@ emit_declaration(
* Emit LLVM for one TGSI instruction.
* \param return TRUE for success, FALSE otherwise
*/
static boolean
emit_instruction(
boolean
lp_emit_instruction_aos(
struct lp_build_tgsi_aos_context *bld,
const struct tgsi_full_instruction *inst,
const struct tgsi_opcode_info *info,
@@ -527,17 +468,17 @@ emit_instruction(

assert(info->num_dst <= 1);
if (info->num_dst) {
dst0 = bld->base.undef;
dst0 = bld->bld_base.base.undef;
}

switch (inst->Instruction.Opcode) {
case TGSI_OPCODE_ARL:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_floor(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_floor(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_MOV:
dst0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
break;

case TGSI_OPCODE_LIT:
@@ -545,15 +486,15 @@ emit_instruction(

case TGSI_OPCODE_RCP:
/* TGSI_OPCODE_RECIP */
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_rcp(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_rcp(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_RSQ:
/* TGSI_OPCODE_RECIPSQRT */
src0 = emit_fetch(bld, inst, 0);
tmp0 = lp_build_abs(&bld->base, src0);
dst0 = lp_build_rsqrt(&bld->base, tmp0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
tmp0 = lp_build_emit_llvm_unary(&bld->bld_base, TGSI_OPCODE_ABS, src0);
dst0 = lp_build_rsqrt(&bld->bld_base.base, tmp0);
break;

case TGSI_OPCODE_EXP:
@@ -563,15 +504,15 @@ emit_instruction(
return FALSE;

case TGSI_OPCODE_MUL:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
dst0 = lp_build_mul(&bld->base, src0, src1);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
dst0 = lp_build_mul(&bld->bld_base.base, src0, src1);
break;

case TGSI_OPCODE_ADD:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
dst0 = lp_build_add(&bld->base, src0, src1);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
dst0 = lp_build_add(&bld->bld_base.base, src0, src1);
break;

case TGSI_OPCODE_DP3:
@@ -586,121 +527,116 @@ emit_instruction(
return FALSE;

case TGSI_OPCODE_MIN:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
dst0 = lp_build_max(&bld->base, src0, src1);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
dst0 = lp_build_max(&bld->bld_base.base, src0, src1);
break;

case TGSI_OPCODE_MAX:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
dst0 = lp_build_max(&bld->base, src0, src1);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
dst0 = lp_build_max(&bld->bld_base.base, src0, src1);
break;

case TGSI_OPCODE_SLT:
/* TGSI_OPCODE_SETLT */
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_LESS, src0, src1);
dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_LESS, src0, src1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, bld->bld_base.base.one, bld->bld_base.base.zero);
break;

case TGSI_OPCODE_SGE:
/* TGSI_OPCODE_SETGE */
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_GEQUAL, src0, src1);
dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_GEQUAL, src0, src1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, bld->bld_base.base.one, bld->bld_base.base.zero);
break;

case TGSI_OPCODE_MAD:
/* TGSI_OPCODE_MADD */
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
src2 = emit_fetch(bld, inst, 2);
tmp0 = lp_build_mul(&bld->base, src0, src1);
dst0 = lp_build_add(&bld->base, tmp0, src2);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
src2 = lp_build_emit_fetch(&bld->bld_base, inst, 2, LP_CHAN_ALL);
tmp0 = lp_build_mul(&bld->bld_base.base, src0, src1);
dst0 = lp_build_add(&bld->bld_base.base, tmp0, src2);
break;

case TGSI_OPCODE_SUB:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
dst0 = lp_build_sub(&bld->base, src0, src1);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
dst0 = lp_build_sub(&bld->bld_base.base, src0, src1);
break;

case TGSI_OPCODE_LRP:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
src2 = emit_fetch(bld, inst, 2);
tmp0 = lp_build_sub(&bld->base, src1, src2);
tmp0 = lp_build_mul(&bld->base, src0, tmp0);
dst0 = lp_build_add(&bld->base, tmp0, src2);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
src2 = lp_build_emit_fetch(&bld->bld_base, inst, 2, LP_CHAN_ALL);
tmp0 = lp_build_sub(&bld->bld_base.base, src1, src2);
tmp0 = lp_build_mul(&bld->bld_base.base, src0, tmp0);
dst0 = lp_build_add(&bld->bld_base.base, tmp0, src2);
break;

case TGSI_OPCODE_CND:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
src2 = emit_fetch(bld, inst, 2);
tmp1 = lp_build_const_vec(bld->base.gallivm, bld->base.type, 0.5);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_GREATER, src2, tmp1);
dst0 = lp_build_select(&bld->base, tmp0, src0, src1);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
src2 = lp_build_emit_fetch(&bld->bld_base, inst, 2, LP_CHAN_ALL);
tmp1 = lp_build_const_vec(bld->bld_base.base.gallivm, bld->bld_base.base.type, 0.5);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_GREATER, src2, tmp1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, src0, src1);
break;

case TGSI_OPCODE_DP2A:
return FALSE;

case TGSI_OPCODE_FRC:
src0 = emit_fetch(bld, inst, 0);
tmp0 = lp_build_floor(&bld->base, src0);
dst0 = lp_build_sub(&bld->base, src0, tmp0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
tmp0 = lp_build_floor(&bld->bld_base.base, src0);
dst0 = lp_build_sub(&bld->bld_base.base, src0, tmp0);
break;

case TGSI_OPCODE_CLAMP:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
src2 = emit_fetch(bld, inst, 2);
tmp0 = lp_build_max(&bld->base, src0, src1);
dst0 = lp_build_min(&bld->base, tmp0, src2);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
src2 = lp_build_emit_fetch(&bld->bld_base, inst, 2, LP_CHAN_ALL);
tmp0 = lp_build_max(&bld->bld_base.base, src0, src1);
dst0 = lp_build_min(&bld->bld_base.base, tmp0, src2);
break;

case TGSI_OPCODE_FLR:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_floor(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_floor(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_ROUND:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_round(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_round(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_EX2:
src0 = emit_fetch(bld, inst, 0);
tmp0 = lp_build_swizzle_scalar_aos(&bld->base, src0, TGSI_SWIZZLE_X);
dst0 = lp_build_exp2(&bld->base, tmp0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
tmp0 = lp_build_swizzle_scalar_aos(&bld->bld_base.base, src0, TGSI_SWIZZLE_X);
dst0 = lp_build_exp2(&bld->bld_base.base, tmp0);
break;

case TGSI_OPCODE_LG2:
src0 = emit_fetch(bld, inst, 0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
tmp0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
dst0 = lp_build_log2(&bld->base, tmp0);
dst0 = lp_build_log2(&bld->bld_base.base, tmp0);
break;

case TGSI_OPCODE_POW:
src0 = emit_fetch(bld, inst, 0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
src1 = emit_fetch(bld, inst, 1);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
src1 = swizzle_scalar_aos(bld, src1, TGSI_SWIZZLE_X);
dst0 = lp_build_pow(&bld->base, src0, src1);
dst0 = lp_build_pow(&bld->bld_base.base, src0, src1);
break;

case TGSI_OPCODE_XPD:
return FALSE;

case TGSI_OPCODE_ABS:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_abs(&bld->base, src0);
break;

case TGSI_OPCODE_RCC:
/* deprecated? */
assert(0);
@@ -710,9 +646,9 @@ emit_instruction(
return FALSE;

case TGSI_OPCODE_COS:
src0 = emit_fetch(bld, inst, 0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
tmp0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
dst0 = lp_build_cos(&bld->base, tmp0);
dst0 = lp_build_cos(&bld->bld_base.base, tmp0);
break;

case TGSI_OPCODE_DDX:
@@ -748,45 +684,45 @@ emit_instruction(
return FALSE;

case TGSI_OPCODE_SEQ:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_EQUAL, src0, src1);
dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_EQUAL, src0, src1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, bld->bld_base.base.one, bld->bld_base.base.zero);
break;

case TGSI_OPCODE_SFL:
dst0 = bld->base.zero;
dst0 = bld->bld_base.base.zero;
break;

case TGSI_OPCODE_SGT:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_GREATER, src0, src1);
dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_GREATER, src0, src1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, bld->bld_base.base.one, bld->bld_base.base.zero);
break;

case TGSI_OPCODE_SIN:
src0 = emit_fetch(bld, inst, 0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
tmp0 = swizzle_scalar_aos(bld, src0, TGSI_SWIZZLE_X);
dst0 = lp_build_sin(&bld->base, tmp0);
dst0 = lp_build_sin(&bld->bld_base.base, tmp0);
break;

case TGSI_OPCODE_SLE:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_LEQUAL, src0, src1);
dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_LEQUAL, src0, src1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, bld->bld_base.base.one, bld->bld_base.base.zero);
break;

case TGSI_OPCODE_SNE:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_NOTEQUAL, src0, src1);
dst0 = lp_build_select(&bld->base, tmp0, bld->base.one, bld->base.zero);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_NOTEQUAL, src0, src1);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, bld->bld_base.base.one, bld->bld_base.base.zero);
break;

case TGSI_OPCODE_STR:
dst0 = bld->base.one;
dst0 = bld->bld_base.base.one;
break;

case TGSI_OPCODE_TEX:
@@ -834,8 +770,8 @@ emit_instruction(
break;

case TGSI_OPCODE_ARR:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_round(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_round(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_BRA:
@@ -856,16 +792,16 @@ emit_instruction(

case TGSI_OPCODE_SSG:
/* TGSI_OPCODE_SGN */
tmp0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_sgn(&bld->base, tmp0);
tmp0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_sgn(&bld->bld_base.base, tmp0);
break;

case TGSI_OPCODE_CMP:
src0 = emit_fetch(bld, inst, 0);
src1 = emit_fetch(bld, inst, 1);
src2 = emit_fetch(bld, inst, 2);
tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_LESS, src0, bld->base.zero);
dst0 = lp_build_select(&bld->base, tmp0, src1, src2);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
src1 = lp_build_emit_fetch(&bld->bld_base, inst, 1, LP_CHAN_ALL);
src2 = lp_build_emit_fetch(&bld->bld_base, inst, 2, LP_CHAN_ALL);
tmp0 = lp_build_cmp(&bld->bld_base.base, PIPE_FUNC_LESS, src0, bld->bld_base.base.zero);
dst0 = lp_build_select(&bld->bld_base.base, tmp0, src1, src2);
break;

case TGSI_OPCODE_SCS:
@@ -934,8 +870,8 @@ emit_instruction(
break;

case TGSI_OPCODE_CEIL:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_ceil(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_ceil(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_I2F:
@@ -951,8 +887,8 @@ emit_instruction(
break;

case TGSI_OPCODE_TRUNC:
src0 = emit_fetch(bld, inst, 0);
dst0 = lp_build_trunc(&bld->base, src0);
src0 = lp_build_emit_fetch(&bld->bld_base, inst, 0, LP_CHAN_ALL);
dst0 = lp_build_trunc(&bld->bld_base.base, src0);
break;

case TGSI_OPCODE_SHL:
@@ -1028,7 +964,7 @@ emit_instruction(
}
if (info->num_dst) {
emit_store(bld, inst, 0, dst0);
lp_emit_store_aos(bld, inst, 0, dst0);
}

return TRUE;
@@ -1049,13 +985,12 @@ lp_build_tgsi_aos(struct gallivm_state *gallivm,
struct lp_build_tgsi_aos_context bld;
struct tgsi_parse_context parse;
uint num_immediates = 0;
uint num_instructions = 0;
unsigned chan;
int pc = 0;

/* Setup build context */
memset(&bld, 0, sizeof bld);
lp_build_context_init(&bld.base, gallivm, type);
lp_build_context_init(&bld.bld_base.base, gallivm, type);
lp_build_context_init(&bld.int_bld, gallivm, lp_int_type(type));

for (chan = 0; chan < 4; ++chan) {
@@ -1068,11 +1003,18 @@ lp_build_tgsi_aos(struct gallivm_state *gallivm,
bld.consts_ptr = consts_ptr;
bld.sampler = sampler;
bld.indirect_files = info->indirect_files;
bld.instructions = (struct tgsi_full_instruction *)
MALLOC(LP_MAX_INSTRUCTIONS * sizeof(struct tgsi_full_instruction));
bld.max_instructions = LP_MAX_INSTRUCTIONS;
bld.bld_base.emit_swizzle = swizzle_aos;
bld.bld_base.info = info;

bld.bld_base.emit_fetch_funcs[TGSI_FILE_CONSTANT] = emit_fetch_constant;
bld.bld_base.emit_fetch_funcs[TGSI_FILE_IMMEDIATE] = emit_fetch_immediate;
bld.bld_base.emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch_input;
bld.bld_base.emit_fetch_funcs[TGSI_FILE_TEMPORARY] = emit_fetch_temporary;

if (!bld.instructions) {
/* Set opcode actions */
lp_set_default_actions_cpu(&bld.bld_base);

if (!lp_bld_tgsi_list_init(&bld.bld_base)) {
return;
}

@@ -1084,33 +1026,13 @@ lp_build_tgsi_aos(struct gallivm_state *gallivm,
switch(parse.FullToken.Token.Type) {
case TGSI_TOKEN_TYPE_DECLARATION:
/* Inputs already interpolated */
emit_declaration(&bld, &parse.FullToken.FullDeclaration);
lp_emit_declaration_aos(&bld, &parse.FullToken.FullDeclaration);
break;

case TGSI_TOKEN_TYPE_INSTRUCTION:
{
/* save expanded instruction */
if (num_instructions == bld.max_instructions) {
struct tgsi_full_instruction *instructions;
instructions = REALLOC(bld.instructions,
bld.max_instructions
* sizeof(struct tgsi_full_instruction),
(bld.max_instructions + LP_MAX_INSTRUCTIONS)
* sizeof(struct tgsi_full_instruction));
if (!instructions) {
break;
}
bld.instructions = instructions;
bld.max_instructions += LP_MAX_INSTRUCTIONS;
}

memcpy(bld.instructions + num_instructions,
&parse.FullToken.FullInstruction,
sizeof(bld.instructions[0]));

num_instructions++;
}

/* save expanded instruction */
lp_bld_tgsi_add_instruction(&bld.bld_base,
&parse.FullToken.FullInstruction);
break;

case TGSI_TOKEN_TYPE_IMMEDIATE:
@@ -1144,10 +1066,10 @@ lp_build_tgsi_aos(struct gallivm_state *gallivm,
}

while (pc != -1) {
struct tgsi_full_instruction *instr = bld.instructions + pc;
struct tgsi_full_instruction *instr = bld.bld_base.instructions + pc;
const struct tgsi_opcode_info *opcode_info =
tgsi_get_opcode_info(instr->Instruction.Opcode);
if (!emit_instruction(&bld, instr, opcode_info, &pc))
if (!lp_emit_instruction_aos(&bld, instr, opcode_info, &pc))
_debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
opcode_info->mnemonic);
}
@@ -1168,6 +1090,5 @@ lp_build_tgsi_aos(struct gallivm_state *gallivm,
LLVMDumpModule(module);
}

FREE(bld.instructions);
}


+ 647
- 1334
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


Laden…
Abbrechen
Speichern