X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgallium%2Fauxiliary%2Fgallivm%2Flp_bld_tgsi.c;h=64d2cd703be7fc805b2a39d54749103b2ce200c9;hb=45b8f620a545bcdb8a4942bafd505c9418f6d9f2;hp=261301ce542ed7ef1a99acdec168cc2b8a163672;hpb=bc2875aa483a0fef7f6e32c1886f6e2edaba7694;p=mesa.git diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c index 261301ce542..64d2cd703be 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c @@ -3,7 +3,7 @@ * Copyright 2011-2012 Advanced Micro Devices, Inc. * Copyright 2010 VMware, Inc. * Copyright 2009 VMware, Inc. - * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007-2008 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -54,7 +54,7 @@ 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) + const struct tgsi_full_instruction *inst_to_add) { if (bld_base->num_instructions == bld_base->max_instructions) { @@ -104,7 +104,7 @@ lp_build_tgsi_intrinsic( 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); + emit_data->dst_type, emit_data->args, emit_data->arg_count, 0); } LLVMValueRef @@ -129,7 +129,8 @@ lp_build_emit_llvm_unary( unsigned tgsi_opcode, LLVMValueRef arg0) { - struct lp_build_emit_data emit_data; + struct lp_build_emit_data emit_data = {{0}}; + emit_data.info = tgsi_get_opcode_info(tgsi_opcode); emit_data.arg_count = 1; emit_data.args[0] = arg0; return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data); @@ -142,7 +143,8 @@ lp_build_emit_llvm_binary( LLVMValueRef arg0, LLVMValueRef arg1) { - struct lp_build_emit_data emit_data; + struct lp_build_emit_data emit_data = {{0}}; + emit_data.info = tgsi_get_opcode_info(tgsi_opcode); emit_data.arg_count = 2; emit_data.args[0] = arg0; emit_data.args[1] = arg1; @@ -157,7 +159,8 @@ lp_build_emit_llvm_ternary( LLVMValueRef arg1, LLVMValueRef arg2) { - struct lp_build_emit_data emit_data; + struct lp_build_emit_data emit_data = {{0}}; + emit_data.info = tgsi_get_opcode_info(tgsi_opcode); emit_data.arg_count = 3; emit_data.args[0] = arg0; emit_data.args[1] = arg1; @@ -175,13 +178,52 @@ void lp_build_fetch_args( 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->src_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); } +/** + * with 64-bit src and dst channels aren't 1:1. + * check the src/dst types for the opcode, + * 1. if neither is 64-bit then src == dst; + * 2. if dest is 64-bit + * - don't store to y or w + * - if src is 64-bit then src == dst. + * - else for f2d, d.xy = s.x + * - else for f2d, d.zw = s.y + * 3. if dst is single, src is 64-bit + * - map dst x,z to src xy; + * - map dst y,w to src zw; + */ +static int get_src_chan_idx(enum tgsi_opcode opcode, + int dst_chan_index) +{ + enum tgsi_opcode_type dtype = tgsi_opcode_infer_dst_type(opcode, 0); + enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(opcode, 0); + + if (!tgsi_type_is_64bit(dtype) && !tgsi_type_is_64bit(stype)) + return dst_chan_index; + if (tgsi_type_is_64bit(dtype)) { + if (dst_chan_index == 1 || dst_chan_index == 3) + return -1; + if (tgsi_type_is_64bit(stype)) + return dst_chan_index; + if (dst_chan_index == 0) + return 0; + if (dst_chan_index == 2) + return 1; + } else { + if (dst_chan_index == 0 || dst_chan_index == 2) + return 0; + if (dst_chan_index == 1 || dst_chan_index == 3) + return 2; + } + return -1; +} + /* XXX: COMMENT * It should be assumed that this function ignores writemasks */ @@ -190,41 +232,25 @@ 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); + enum tgsi_opcode opcode = inst->Instruction.Opcode; + const struct tgsi_opcode_info * info = tgsi_get_opcode_info(opcode); const struct lp_build_tgsi_action * action = - &bld_base->op_actions[tgsi_opcode]; + &bld_base->op_actions[opcode]; struct lp_build_emit_data emit_data; unsigned chan_index; LLVMValueRef val; - bld_base->pc++; + if (bld_base->emit_debug) { + bld_base->emit_debug(bld_base, inst, info); + } + /* 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; @@ -238,11 +264,17 @@ lp_build_tgsi_inst_llvm( memset(&emit_data, 0, sizeof(emit_data)); - assert(info->num_dst <= 1); + assert(info->num_dst <= 2); if (info->num_dst) { TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) { emit_data.output[chan_index] = bld_base->base.undef; } + + if (info->num_dst >= 2) { + TGSI_FOR_EACH_DST1_ENABLED_CHANNEL( inst, chan_index ) { + emit_data.output1[chan_index] = bld_base->base.undef; + } + } } emit_data.inst = inst; @@ -251,7 +283,12 @@ lp_build_tgsi_inst_llvm( /* Emit the instructions */ if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) { TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) { + int src_index = get_src_chan_idx(inst->Instruction.Opcode, chan_index); + /* ignore channels 1/3 in double dst */ + if (src_index == -1) + continue; emit_data.chan = chan_index; + emit_data.src_chan = src_index; if (!action->fetch_args) { lp_build_fetch_args(bld_base, &emit_data); } else { @@ -278,29 +315,38 @@ lp_build_tgsi_inst_llvm( TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) { emit_data.output[chan_index] = val; } + + if (info->num_dst >= 2) { + val = emit_data.output1[0]; + memset(emit_data.output1, 0, sizeof(emit_data.output1)); + TGSI_FOR_EACH_DST1_ENABLED_CHANNEL(inst, chan_index) { + emit_data.output1[chan_index] = val; + } + } } } - if (info->num_dst > 0) { - bld_base->emit_store(bld_base, inst, info, emit_data.output); + if (info->num_dst > 0 && info->opcode != TGSI_OPCODE_STORE) { + bld_base->emit_store(bld_base, inst, info, 0, emit_data.output); + if (info->num_dst >= 2) + bld_base->emit_store(bld_base, inst, info, 1, emit_data.output1); } return TRUE; } LLVMValueRef -lp_build_emit_fetch( +lp_build_emit_fetch_src( struct lp_build_tgsi_context *bld_base, - const struct tgsi_full_instruction *inst, - unsigned src_op, + const struct tgsi_full_src_register *reg, + enum tgsi_opcode_type stype, 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; + swizzle = ~0u; } else { swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index); if (swizzle > 3) { @@ -312,7 +358,7 @@ lp_build_emit_fetch( 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, + res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype, swizzle); } else { assert(0 && "invalid src register in emit_fetch()"); @@ -320,18 +366,56 @@ lp_build_emit_fetch( } if (reg->Register.Absolute) { - res = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS, res); + switch (stype) { + case TGSI_TYPE_FLOAT: + case TGSI_TYPE_DOUBLE: + case TGSI_TYPE_UNTYPED: + /* modifiers on movs assume data is float */ + res = lp_build_abs(&bld_base->base, res); + break; + case TGSI_TYPE_UNSIGNED: + case TGSI_TYPE_SIGNED: + case TGSI_TYPE_UNSIGNED64: + case TGSI_TYPE_SIGNED64: + case TGSI_TYPE_VOID: + default: + /* abs modifier is only legal on floating point types */ + assert(0); + break; + } } if (reg->Register.Negate) { - res = lp_build_negate( &bld_base->base, res ); + switch (stype) { + case TGSI_TYPE_FLOAT: + case TGSI_TYPE_UNTYPED: + /* modifiers on movs assume data is float */ + res = lp_build_negate( &bld_base->base, res ); + break; + case TGSI_TYPE_DOUBLE: + /* no double build context */ + assert(0); + break; + case TGSI_TYPE_SIGNED: + case TGSI_TYPE_UNSIGNED: + res = lp_build_negate( &bld_base->int_bld, res ); + break; + case TGSI_TYPE_SIGNED64: + case TGSI_TYPE_UNSIGNED64: + res = lp_build_negate( &bld_base->int64_bld, res ); + break; + case TGSI_TYPE_VOID: + default: + assert(0); + break; + } } /* * Swizzle the argument */ - if (swizzle == ~0) { + if (swizzle == ~0u) { res = bld_base->emit_swizzle(bld_base, res, reg->Register.SwizzleX, reg->Register.SwizzleY, @@ -339,10 +423,81 @@ lp_build_emit_fetch( reg->Register.SwizzleW); } + return res; +} + + +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]; + enum tgsi_opcode_type stype = + tgsi_opcode_infer_src_type(inst->Instruction.Opcode, src_op); + + return lp_build_emit_fetch_src(bld_base, reg, stype, chan_index); +} + + +LLVMValueRef +lp_build_emit_fetch_texoffset( + struct lp_build_tgsi_context *bld_base, + const struct tgsi_full_instruction *inst, + unsigned tex_off_op, + const unsigned chan_index) +{ + const struct tgsi_texture_offset *off = &inst->TexOffsets[tex_off_op]; + struct tgsi_full_src_register reg; + unsigned swizzle; + LLVMValueRef res; + enum tgsi_opcode_type stype = TGSI_TYPE_SIGNED; + + /* convert offset "register" to ordinary register so can use normal emit funcs */ + memset(®, 0, sizeof(reg)); + reg.Register.File = off->File; + reg.Register.Index = off->Index; + reg.Register.SwizzleX = off->SwizzleX; + reg.Register.SwizzleY = off->SwizzleY; + reg.Register.SwizzleZ = off->SwizzleZ; + + if (chan_index == LP_CHAN_ALL) { + swizzle = ~0; + } else { + assert(chan_index < TGSI_SWIZZLE_W); + swizzle = tgsi_util_get_src_register_swizzle(®.Register, chan_index); + } + + assert(off->Index <= bld_base->info->file_max[off->File]); + + if (bld_base->emit_fetch_funcs[off->File]) { + res = bld_base->emit_fetch_funcs[off->File](bld_base, ®, stype, + swizzle); + } else { + assert(0 && "invalid src register in emit_fetch_texoffset()"); + return bld_base->base.undef; + } + + /* + * Swizzle the argument + */ + + if (swizzle == ~0u) { + res = bld_base->emit_swizzle(bld_base, res, + off->SwizzleX, + off->SwizzleY, + off->SwizzleZ, + /* there's no 4th channel */ + off->SwizzleX); + } + return res; } + boolean lp_build_tgsi_llvm( struct lp_build_tgsi_context * bld_base, @@ -386,13 +541,11 @@ lp_build_tgsi_llvm( } 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); + const struct tgsi_full_instruction *instr = + bld_base->instructions + bld_base->pc; if (!lp_build_tgsi_inst_llvm(bld_base, instr)) { _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n", - opcode_info->mnemonic); + tgsi_get_opcode_name(instr->Instruction.Opcode)); return FALSE; } }