Home | History | Annotate | Download | only in gallivm
      1 /**************************************************************************
      2  *
      3  * Copyright 2011-2012 Advanced Micro Devices, Inc.
      4  * Copyright 2010 VMware, Inc.
      5  * Copyright 2009 VMware, Inc.
      6  * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      7  * All Rights Reserved.
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a
     10  * copy of this software and associated documentation files (the
     11  * "Software"), to deal in the Software without restriction, including
     12  * without limitation the rights to use, copy, modify, merge, publish,
     13  * distribute, sub license, and/or sell copies of the Software, and to
     14  * permit persons to whom the Software is furnished to do so, subject to
     15  * the following conditions:
     16  *
     17  * The above copyright notice and this permission notice (including the
     18  * next paragraph) shall be included in all copies or substantial portions
     19  * of the Software.
     20  *
     21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     24  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     25  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     26  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     27  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  *
     29  **************************************************************************/
     30 
     31 #include "gallivm/lp_bld_tgsi.h"
     32 
     33 #include "gallivm/lp_bld_arit.h"
     34 #include "gallivm/lp_bld_gather.h"
     35 #include "gallivm/lp_bld_init.h"
     36 #include "gallivm/lp_bld_intr.h"
     37 #include "tgsi/tgsi_info.h"
     38 #include "tgsi/tgsi_parse.h"
     39 #include "tgsi/tgsi_util.h"
     40 #include "util/u_memory.h"
     41 
     42 /* The user is responsible for freeing list->instructions */
     43 unsigned lp_bld_tgsi_list_init(struct lp_build_tgsi_context * bld_base)
     44 {
     45    bld_base->instructions = (struct tgsi_full_instruction *)
     46          MALLOC( LP_MAX_INSTRUCTIONS * sizeof(struct tgsi_full_instruction) );
     47    if (!bld_base->instructions) {
     48       return 0;
     49    }
     50    bld_base->max_instructions = LP_MAX_INSTRUCTIONS;
     51    return 1;
     52 }
     53 
     54 
     55 unsigned lp_bld_tgsi_add_instruction(
     56    struct lp_build_tgsi_context * bld_base,
     57    struct tgsi_full_instruction *inst_to_add)
     58 {
     59 
     60    if (bld_base->num_instructions == bld_base->max_instructions) {
     61       struct tgsi_full_instruction *instructions;
     62       instructions = REALLOC(bld_base->instructions, bld_base->max_instructions
     63                                       * sizeof(struct tgsi_full_instruction),
     64                                       (bld_base->max_instructions + LP_MAX_INSTRUCTIONS)
     65                                       * sizeof(struct tgsi_full_instruction));
     66       if (!instructions) {
     67          return 0;
     68       }
     69       bld_base->instructions = instructions;
     70       bld_base->max_instructions += LP_MAX_INSTRUCTIONS;
     71    }
     72    memcpy(bld_base->instructions + bld_base->num_instructions, inst_to_add,
     73           sizeof(bld_base->instructions[0]));
     74 
     75    bld_base->num_instructions++;
     76 
     77    return 1;
     78 }
     79 
     80 
     81 /**
     82  * This function assumes that all the args in emit_data have been set.
     83  */
     84 static void
     85 lp_build_action_set_dst_type(
     86    struct lp_build_emit_data * emit_data,
     87    struct lp_build_tgsi_context *bld_base,
     88    unsigned tgsi_opcode)
     89 {
     90    if (emit_data->arg_count == 0) {
     91       emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
     92    } else {
     93       /* XXX: Not all opcodes have the same src and dst types. */
     94       emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
     95    }
     96 }
     97 
     98 void
     99 lp_build_tgsi_intrinsic(
    100  const struct lp_build_tgsi_action * action,
    101  struct lp_build_tgsi_context * bld_base,
    102  struct lp_build_emit_data * emit_data)
    103 {
    104    struct lp_build_context * base = &bld_base->base;
    105    emit_data->output[emit_data->chan] = lp_build_intrinsic(
    106                base->gallivm->builder, action->intr_name,
    107                emit_data->dst_type, emit_data->args, emit_data->arg_count);
    108 }
    109 
    110 LLVMValueRef
    111 lp_build_emit_llvm(
    112    struct lp_build_tgsi_context *bld_base,
    113    unsigned tgsi_opcode,
    114    struct lp_build_emit_data * emit_data)
    115 {
    116    struct lp_build_tgsi_action * action = &bld_base->op_actions[tgsi_opcode];
    117    /* XXX: Assert that this is a componentwise or replicate instruction */
    118 
    119    lp_build_action_set_dst_type(emit_data, bld_base, tgsi_opcode);
    120    emit_data->chan = 0;
    121    assert(action->emit);
    122    action->emit(action, bld_base, emit_data);
    123    return emit_data->output[0];
    124 }
    125 
    126 LLVMValueRef
    127 lp_build_emit_llvm_unary(
    128    struct lp_build_tgsi_context *bld_base,
    129    unsigned tgsi_opcode,
    130    LLVMValueRef arg0)
    131 {
    132    struct lp_build_emit_data emit_data;
    133    emit_data.arg_count = 1;
    134    emit_data.args[0] = arg0;
    135    return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
    136 }
    137 
    138 LLVMValueRef
    139 lp_build_emit_llvm_binary(
    140    struct lp_build_tgsi_context *bld_base,
    141    unsigned tgsi_opcode,
    142    LLVMValueRef arg0,
    143    LLVMValueRef arg1)
    144 {
    145    struct lp_build_emit_data emit_data;
    146    emit_data.arg_count = 2;
    147    emit_data.args[0] = arg0;
    148    emit_data.args[1] = arg1;
    149    return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
    150 }
    151 
    152 LLVMValueRef
    153 lp_build_emit_llvm_ternary(
    154    struct lp_build_tgsi_context *bld_base,
    155    unsigned tgsi_opcode,
    156    LLVMValueRef arg0,
    157    LLVMValueRef arg1,
    158    LLVMValueRef arg2)
    159 {
    160    struct lp_build_emit_data emit_data;
    161    emit_data.arg_count = 3;
    162    emit_data.args[0] = arg0;
    163    emit_data.args[1] = arg1;
    164    emit_data.args[2] = arg2;
    165    return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
    166 }
    167 
    168 /**
    169  * The default fetch implementation.
    170  */
    171 void lp_build_fetch_args(
    172    struct lp_build_tgsi_context * bld_base,
    173    struct lp_build_emit_data * emit_data)
    174 {
    175    unsigned src;
    176    for (src = 0; src < emit_data->info->num_src; src++) {
    177       emit_data->args[src] = lp_build_emit_fetch(bld_base, emit_data->inst, src,
    178                                                emit_data->chan);
    179    }
    180    emit_data->arg_count = emit_data->info->num_src;
    181    lp_build_action_set_dst_type(emit_data, bld_base,
    182 		emit_data->inst->Instruction.Opcode);
    183 }
    184 
    185 /* XXX: COMMENT
    186  * It should be assumed that this function ignores writemasks
    187  */
    188 boolean
    189 lp_build_tgsi_inst_llvm(
    190    struct lp_build_tgsi_context * bld_base,
    191    const struct tgsi_full_instruction * inst)
    192 {
    193    unsigned tgsi_opcode = inst->Instruction.Opcode;
    194    const struct tgsi_opcode_info * info = tgsi_get_opcode_info(tgsi_opcode);
    195    const struct lp_build_tgsi_action * action =
    196                                          &bld_base->op_actions[tgsi_opcode];
    197    struct lp_build_emit_data emit_data;
    198    unsigned chan_index;
    199    LLVMValueRef val;
    200 
    201    bld_base->pc++;
    202 
    203    /* Ignore deprecated instructions */
    204    switch (inst->Instruction.Opcode) {
    205 
    206    case TGSI_OPCODE_RCC:
    207    case TGSI_OPCODE_UP2H:
    208    case TGSI_OPCODE_UP2US:
    209    case TGSI_OPCODE_UP4B:
    210    case TGSI_OPCODE_UP4UB:
    211    case TGSI_OPCODE_X2D:
    212    case TGSI_OPCODE_ARA:
    213    case TGSI_OPCODE_BRA:
    214    case TGSI_OPCODE_DIV:
    215    case TGSI_OPCODE_PUSHA:
    216    case TGSI_OPCODE_POPA:
    217    case TGSI_OPCODE_SAD:
    218       /* deprecated? */
    219       assert(0);
    220       return FALSE;
    221       break;
    222    }
    223 
    224    /* Check if the opcode has been implemented */
    225    if (!action->emit) {
    226       return FALSE;
    227    }
    228 
    229    memset(&emit_data, 0, sizeof(emit_data));
    230 
    231    assert(info->num_dst <= 1);
    232    if (info->num_dst) {
    233       TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
    234          emit_data.output[chan_index] = bld_base->base.undef;
    235       }
    236    }
    237 
    238    emit_data.inst = inst;
    239    emit_data.info = info;
    240 
    241    /* Emit the instructions */
    242    if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) {
    243       TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
    244          emit_data.chan = chan_index;
    245          if (!action->fetch_args) {
    246             lp_build_fetch_args(bld_base, &emit_data);
    247          } else {
    248              action->fetch_args(bld_base, &emit_data);
    249          }
    250          action->emit(action, bld_base, &emit_data);
    251       }
    252    } else {
    253       emit_data.chan = LP_CHAN_ALL;
    254       if (action->fetch_args) {
    255          action->fetch_args(bld_base, &emit_data);
    256       }
    257       /* Make sure the output value is stored in emit_data.output[0], unless
    258        * the opcode is channel dependent */
    259       if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) {
    260          emit_data.chan = 0;
    261       }
    262       action->emit(action, bld_base, &emit_data);
    263 
    264       /* Replicate the output values */
    265       if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) {
    266          val = emit_data.output[0];
    267          memset(emit_data.output, 0, sizeof(emit_data.output));
    268          TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
    269             emit_data.output[chan_index] = val;
    270          }
    271       }
    272    }
    273 
    274    if (info->num_dst > 0) {
    275       bld_base->emit_store(bld_base, inst, info, emit_data.output);
    276    }
    277    return TRUE;
    278 }
    279 
    280 
    281 LLVMValueRef
    282 lp_build_emit_fetch(
    283    struct lp_build_tgsi_context *bld_base,
    284    const struct tgsi_full_instruction *inst,
    285    unsigned src_op,
    286    const unsigned chan_index)
    287 {
    288    const struct tgsi_full_src_register *reg = &inst->Src[src_op];
    289    unsigned swizzle;
    290    LLVMValueRef res;
    291    enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(inst->Instruction.Opcode);
    292 
    293    if (chan_index == LP_CHAN_ALL) {
    294       swizzle = ~0;
    295    } else {
    296       swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index);
    297       if (swizzle > 3) {
    298          assert(0 && "invalid swizzle in emit_fetch()");
    299          return bld_base->base.undef;
    300       }
    301    }
    302 
    303    assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]);
    304 
    305    if (bld_base->emit_fetch_funcs[reg->Register.File]) {
    306       res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype,
    307                                                            swizzle);
    308    } else {
    309       assert(0 && "invalid src register in emit_fetch()");
    310       return bld_base->base.undef;
    311    }
    312 
    313    if (reg->Register.Absolute) {
    314       res = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS, res);
    315    }
    316 
    317    if (reg->Register.Negate) {
    318       res = lp_build_negate( &bld_base->base, res );
    319    }
    320 
    321    /*
    322     * Swizzle the argument
    323     */
    324 
    325    if (swizzle == ~0) {
    326       res = bld_base->emit_swizzle(bld_base, res,
    327                      reg->Register.SwizzleX,
    328                      reg->Register.SwizzleY,
    329                      reg->Register.SwizzleZ,
    330                      reg->Register.SwizzleW);
    331    }
    332 
    333    return res;
    334 
    335 }
    336 
    337 boolean
    338 lp_build_tgsi_llvm(
    339    struct lp_build_tgsi_context * bld_base,
    340    const struct tgsi_token *tokens)
    341 {
    342    struct tgsi_parse_context parse;
    343 
    344    if (bld_base->emit_prologue) {
    345       bld_base->emit_prologue(bld_base);
    346    }
    347 
    348    if (!lp_bld_tgsi_list_init(bld_base)) {
    349       return FALSE;
    350    }
    351 
    352    tgsi_parse_init( &parse, tokens );
    353 
    354    while( !tgsi_parse_end_of_tokens( &parse ) ) {
    355       tgsi_parse_token( &parse );
    356 
    357       switch( parse.FullToken.Token.Type ) {
    358       case TGSI_TOKEN_TYPE_DECLARATION:
    359          /* Inputs already interpolated */
    360          bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration);
    361          break;
    362 
    363       case TGSI_TOKEN_TYPE_INSTRUCTION:
    364          lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction);
    365          break;
    366 
    367       case TGSI_TOKEN_TYPE_IMMEDIATE:
    368          bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate);
    369          break;
    370 
    371       case TGSI_TOKEN_TYPE_PROPERTY:
    372          break;
    373 
    374       default:
    375          assert( 0 );
    376       }
    377    }
    378 
    379    while (bld_base->pc != -1) {
    380       struct tgsi_full_instruction *instr = bld_base->instructions +
    381 							bld_base->pc;
    382       const struct tgsi_opcode_info *opcode_info =
    383          tgsi_get_opcode_info(instr->Instruction.Opcode);
    384       if (!lp_build_tgsi_inst_llvm(bld_base, instr)) {
    385          _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
    386                        opcode_info->mnemonic);
    387          return FALSE;
    388       }
    389    }
    390 
    391    tgsi_parse_free(&parse);
    392 
    393    FREE(bld_base->instructions);
    394 
    395    if (bld_base->emit_epilogue) {
    396       bld_base->emit_epilogue(bld_base);
    397    }
    398 
    399    return TRUE;
    400 }
    401