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
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -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:
|
||||
res = bld->bld_base.base.undef;
|
||||
for (chan = 0; chan < 4; ++chan) {
|
||||
LLVMValueRef index;
|
||||
LLVMValueRef scalar_ptr;
|
||||
LLVMValueRef scalar;
|
||||
LLVMValueRef swizzle;
|
||||
|
||||
index = lp_build_const_int32(bld->bld_base.base.gallivm,
|
||||
reg->Register.Index * 4 + chan);
|
||||
|
||||
scalar_ptr = LLVMBuildGEP(builder, bld->consts_ptr, &index, 1, "");
|
||||
|
||||
scalar = LLVMBuildLoad(builder, scalar_ptr, "");
|
||||
|
||||
lp_build_name(scalar, "const[%u].%c", reg->Register.Index, "xyzw"[chan]);
|
||||
|
||||
/*
|
||||
* Get the constants components
|
||||
* NOTE: constants array is always assumed to be RGBA
|
||||
*/
|
||||
|
||||
res = bld->base.undef;
|
||||
swizzle = lp_build_const_int32(bld->bld_base.base.gallivm,
|
||||
bld->swizzles[chan]);
|
||||
|
||||
res = LLVMBuildInsertElement(builder, res, scalar, swizzle, "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Broadcast the first quaternion to all others.
|
||||
*
|
||||
* XXX: could be factored into a reusable function.
|
||||
*/
|
||||
|
||||
if (type.length > 4) {
|
||||
LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH];
|
||||
unsigned i;
|
||||
|
||||
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, "");
|
||||
|
||||
scalar = LLVMBuildLoad(builder, scalar_ptr, "");
|
||||
|
||||
lp_build_name(scalar, "const[%u].%c", reg->Register.Index, "xyzw"[chan]);
|
||||
|
||||
/*
|
||||
* NOTE: constants array is always assumed to be RGBA
|
||||
*/
|
||||
|
||||
swizzle = lp_build_const_int32(bld->base.gallivm, bld->swizzles[chan]);
|
||||
|
||||
res = LLVMBuildInsertElement(builder, res, scalar, swizzle, "");
|
||||
shuffles[chan] = lp_build_const_int32(bld->bld_base.base.gallivm, chan);
|
||||
}
|
||||
|
||||
/*
|
||||
* Broadcast the first quaternion to all others.
|
||||
*
|
||||
* XXX: could be factored into a reusable function.
|
||||
*/
|
||||
|
||||
if (type.length > 4) {
|
||||
LLVMValueRef shuffles[LP_MAX_VECTOR_LENGTH];
|
||||
unsigned i;
|
||||
|
||||
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 = LLVMBuildShuffleVector(builder,
|
||||
res, bld->base.undef,
|
||||
LLVMConstVector(shuffles, type.length),
|
||||
"");
|
||||
for (i = 4; i < type.length; ++i) {
|
||||
shuffles[i] = shuffles[i % 4];
|
||||
}
|
||||
break;
|
||||
|
||||
case TGSI_FILE_IMMEDIATE:
|
||||
res = bld->immediates[reg->Register.Index];
|
||||
assert(res);
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0 && "invalid src register in emit_fetch()");
|
||||
return bld->base.undef;
|
||||
res = LLVMBuildShuffleVector(builder,
|
||||
res, bld->bld_base.base.undef,
|
||||
LLVMConstVector(shuffles, type.length),
|
||||
"");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply sign modifier.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
if (reg->Register.Absolute) {
|
||||
res = lp_build_abs(&bld->base, res);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if(reg->Register.Negate) {
|
||||
res = lp_build_negate(&bld->base, res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Swizzle the argument
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
if (!bld.instructions) {
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user