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 VMware, Inc.
      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    const 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, 0);
    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 = {{0}};
    133    emit_data.info = tgsi_get_opcode_info(tgsi_opcode);
    134    emit_data.arg_count = 1;
    135    emit_data.args[0] = arg0;
    136    return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
    137 }
    138 
    139 LLVMValueRef
    140 lp_build_emit_llvm_binary(
    141    struct lp_build_tgsi_context *bld_base,
    142    unsigned tgsi_opcode,
    143    LLVMValueRef arg0,
    144    LLVMValueRef arg1)
    145 {
    146    struct lp_build_emit_data emit_data = {{0}};
    147    emit_data.info = tgsi_get_opcode_info(tgsi_opcode);
    148    emit_data.arg_count = 2;
    149    emit_data.args[0] = arg0;
    150    emit_data.args[1] = arg1;
    151    return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
    152 }
    153 
    154 LLVMValueRef
    155 lp_build_emit_llvm_ternary(
    156    struct lp_build_tgsi_context *bld_base,
    157    unsigned tgsi_opcode,
    158    LLVMValueRef arg0,
    159    LLVMValueRef arg1,
    160    LLVMValueRef arg2)
    161 {
    162    struct lp_build_emit_data emit_data = {{0}};
    163    emit_data.info = tgsi_get_opcode_info(tgsi_opcode);
    164    emit_data.arg_count = 3;
    165    emit_data.args[0] = arg0;
    166    emit_data.args[1] = arg1;
    167    emit_data.args[2] = arg2;
    168    return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
    169 }
    170 
    171 /**
    172  * The default fetch implementation.
    173  */
    174 void lp_build_fetch_args(
    175    struct lp_build_tgsi_context * bld_base,
    176    struct lp_build_emit_data * emit_data)
    177 {
    178    unsigned src;
    179    for (src = 0; src < emit_data->info->num_src; src++) {
    180       emit_data->args[src] = lp_build_emit_fetch(bld_base, emit_data->inst, src,
    181                                                  emit_data->src_chan);
    182    }
    183    emit_data->arg_count = emit_data->info->num_src;
    184    lp_build_action_set_dst_type(emit_data, bld_base,
    185 		emit_data->inst->Instruction.Opcode);
    186 }
    187 
    188 /**
    189  * with 64-bit src and dst channels aren't 1:1.
    190  * check the src/dst types for the opcode,
    191  * 1. if neither is 64-bit then src == dst;
    192  * 2. if dest is 64-bit
    193  *     - don't store to y or w
    194  *     - if src is 64-bit then src == dst.
    195  *     - else for f2d, d.xy = s.x
    196  *     - else for f2d, d.zw = s.y
    197  * 3. if dst is single, src is 64-bit
    198  *    - map dst x,z to src xy;
    199  *    - map dst y,w to src zw;
    200  */
    201 static int get_src_chan_idx(unsigned opcode,
    202                             int dst_chan_index)
    203 {
    204    enum tgsi_opcode_type dtype = tgsi_opcode_infer_dst_type(opcode, 0);
    205    enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(opcode, 0);
    206 
    207    if (!tgsi_type_is_64bit(dtype) && !tgsi_type_is_64bit(stype))
    208       return dst_chan_index;
    209    if (tgsi_type_is_64bit(dtype)) {
    210       if (dst_chan_index == 1 || dst_chan_index == 3)
    211          return -1;
    212       if (tgsi_type_is_64bit(stype))
    213          return dst_chan_index;
    214       if (dst_chan_index == 0)
    215          return 0;
    216       if (dst_chan_index == 2)
    217          return 1;
    218    } else {
    219       if (dst_chan_index == 0 || dst_chan_index == 2)
    220          return 0;
    221       if (dst_chan_index == 1 || dst_chan_index == 3)
    222          return 2;
    223    }
    224    return -1;
    225 }
    226 
    227 /* XXX: COMMENT
    228  * It should be assumed that this function ignores writemasks
    229  */
    230 boolean
    231 lp_build_tgsi_inst_llvm(
    232    struct lp_build_tgsi_context * bld_base,
    233    const struct tgsi_full_instruction * inst)
    234 {
    235    unsigned tgsi_opcode = inst->Instruction.Opcode;
    236    const struct tgsi_opcode_info * info = tgsi_get_opcode_info(tgsi_opcode);
    237    const struct lp_build_tgsi_action * action =
    238                                          &bld_base->op_actions[tgsi_opcode];
    239    struct lp_build_emit_data emit_data;
    240    unsigned chan_index;
    241    LLVMValueRef val;
    242    bld_base->pc++;
    243 
    244    if (bld_base->emit_debug) {
    245       bld_base->emit_debug(bld_base, inst, info);
    246    }
    247 
    248    /* Ignore deprecated instructions */
    249    switch (inst->Instruction.Opcode) {
    250 
    251    case TGSI_OPCODE_UP2US:
    252    case TGSI_OPCODE_UP4B:
    253    case TGSI_OPCODE_UP4UB:
    254       /* deprecated? */
    255       assert(0);
    256       return FALSE;
    257       break;
    258    }
    259 
    260    /* Check if the opcode has been implemented */
    261    if (!action->emit) {
    262       return FALSE;
    263    }
    264 
    265    memset(&emit_data, 0, sizeof(emit_data));
    266 
    267    assert(info->num_dst <= 2);
    268    if (info->num_dst) {
    269       TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
    270          emit_data.output[chan_index] = bld_base->base.undef;
    271       }
    272 
    273       if (info->num_dst >= 2) {
    274          TGSI_FOR_EACH_DST1_ENABLED_CHANNEL( inst, chan_index ) {
    275             emit_data.output1[chan_index] = bld_base->base.undef;
    276          }
    277       }
    278    }
    279 
    280    emit_data.inst = inst;
    281    emit_data.info = info;
    282 
    283    /* Emit the instructions */
    284    if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) {
    285       TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
    286          int src_index = get_src_chan_idx(inst->Instruction.Opcode, chan_index);
    287          /* ignore channels 1/3 in double dst */
    288          if (src_index == -1)
    289             continue;
    290          emit_data.chan = chan_index;
    291          emit_data.src_chan = src_index;
    292          if (!action->fetch_args) {
    293             lp_build_fetch_args(bld_base, &emit_data);
    294          } else {
    295              action->fetch_args(bld_base, &emit_data);
    296          }
    297          action->emit(action, bld_base, &emit_data);
    298       }
    299    } else {
    300       emit_data.chan = LP_CHAN_ALL;
    301       if (action->fetch_args) {
    302          action->fetch_args(bld_base, &emit_data);
    303       }
    304       /* Make sure the output value is stored in emit_data.output[0], unless
    305        * the opcode is channel dependent */
    306       if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) {
    307          emit_data.chan = 0;
    308       }
    309       action->emit(action, bld_base, &emit_data);
    310 
    311       /* Replicate the output values */
    312       if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) {
    313          val = emit_data.output[0];
    314          memset(emit_data.output, 0, sizeof(emit_data.output));
    315          TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
    316             emit_data.output[chan_index] = val;
    317          }
    318 
    319          if (info->num_dst >= 2) {
    320             val = emit_data.output1[0];
    321             memset(emit_data.output1, 0, sizeof(emit_data.output1));
    322             TGSI_FOR_EACH_DST1_ENABLED_CHANNEL(inst, chan_index) {
    323                emit_data.output1[chan_index] = val;
    324             }
    325          }
    326       }
    327    }
    328 
    329    if (info->num_dst > 0 && info->opcode != TGSI_OPCODE_STORE) {
    330       bld_base->emit_store(bld_base, inst, info, 0, emit_data.output);
    331       if (info->num_dst >= 2)
    332          bld_base->emit_store(bld_base, inst, info, 1, emit_data.output1);
    333    }
    334    return TRUE;
    335 }
    336 
    337 
    338 LLVMValueRef
    339 lp_build_emit_fetch_src(
    340    struct lp_build_tgsi_context *bld_base,
    341    const struct tgsi_full_src_register *reg,
    342    enum tgsi_opcode_type stype,
    343    const unsigned chan_index)
    344 {
    345    unsigned swizzle;
    346    LLVMValueRef res;
    347 
    348    if (chan_index == LP_CHAN_ALL) {
    349       swizzle = ~0u;
    350    } else {
    351       swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index);
    352       if (swizzle > 3) {
    353          assert(0 && "invalid swizzle in emit_fetch()");
    354          return bld_base->base.undef;
    355       }
    356    }
    357 
    358    assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]);
    359 
    360    if (bld_base->emit_fetch_funcs[reg->Register.File]) {
    361       res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype,
    362                                                            swizzle);
    363    } else {
    364       assert(0 && "invalid src register in emit_fetch()");
    365       return bld_base->base.undef;
    366    }
    367 
    368    if (reg->Register.Absolute) {
    369       switch (stype) {
    370       case TGSI_TYPE_FLOAT:
    371       case TGSI_TYPE_DOUBLE:
    372       case TGSI_TYPE_UNTYPED:
    373           /* modifiers on movs assume data is float */
    374          res = lp_build_abs(&bld_base->base, res);
    375          break;
    376       case TGSI_TYPE_UNSIGNED:
    377       case TGSI_TYPE_SIGNED:
    378       case TGSI_TYPE_UNSIGNED64:
    379       case TGSI_TYPE_SIGNED64:
    380       case TGSI_TYPE_VOID:
    381       default:
    382          /* abs modifier is only legal on floating point types */
    383          assert(0);
    384          break;
    385       }
    386    }
    387 
    388    if (reg->Register.Negate) {
    389       switch (stype) {
    390       case TGSI_TYPE_FLOAT:
    391       case TGSI_TYPE_UNTYPED:
    392          /* modifiers on movs assume data is float */
    393          res = lp_build_negate( &bld_base->base, res );
    394          break;
    395       case TGSI_TYPE_DOUBLE:
    396          /* no double build context */
    397          assert(0);
    398          break;
    399       case TGSI_TYPE_SIGNED:
    400       case TGSI_TYPE_UNSIGNED:
    401          res = lp_build_negate( &bld_base->int_bld, res );
    402          break;
    403       case TGSI_TYPE_SIGNED64:
    404       case TGSI_TYPE_UNSIGNED64:
    405          res = lp_build_negate( &bld_base->int64_bld, res );
    406          break;
    407       case TGSI_TYPE_VOID:
    408       default:
    409          assert(0);
    410          break;
    411       }
    412    }
    413 
    414    /*
    415     * Swizzle the argument
    416     */
    417 
    418    if (swizzle == ~0u) {
    419       res = bld_base->emit_swizzle(bld_base, res,
    420                      reg->Register.SwizzleX,
    421                      reg->Register.SwizzleY,
    422                      reg->Register.SwizzleZ,
    423                      reg->Register.SwizzleW);
    424    }
    425 
    426    return res;
    427 }
    428 
    429 
    430 LLVMValueRef
    431 lp_build_emit_fetch(
    432    struct lp_build_tgsi_context *bld_base,
    433    const struct tgsi_full_instruction *inst,
    434    unsigned src_op,
    435    const unsigned chan_index)
    436 {
    437    const struct tgsi_full_src_register *reg = &inst->Src[src_op];
    438    enum tgsi_opcode_type stype =
    439       tgsi_opcode_infer_src_type(inst->Instruction.Opcode, src_op);
    440 
    441    return lp_build_emit_fetch_src(bld_base, reg, stype, chan_index);
    442 }
    443 
    444 
    445 LLVMValueRef
    446 lp_build_emit_fetch_texoffset(
    447    struct lp_build_tgsi_context *bld_base,
    448    const struct tgsi_full_instruction *inst,
    449    unsigned tex_off_op,
    450    const unsigned chan_index)
    451 {
    452    const struct tgsi_texture_offset *off = &inst->TexOffsets[tex_off_op];
    453    struct tgsi_full_src_register reg;
    454    unsigned swizzle;
    455    LLVMValueRef res;
    456    enum tgsi_opcode_type stype = TGSI_TYPE_SIGNED;
    457 
    458    /* convert offset "register" to ordinary register so can use normal emit funcs */
    459    memset(&reg, 0, sizeof(reg));
    460    reg.Register.File = off->File;
    461    reg.Register.Index = off->Index;
    462    reg.Register.SwizzleX = off->SwizzleX;
    463    reg.Register.SwizzleY = off->SwizzleY;
    464    reg.Register.SwizzleZ = off->SwizzleZ;
    465 
    466    if (chan_index == LP_CHAN_ALL) {
    467       swizzle = ~0;
    468    } else {
    469       assert(chan_index < TGSI_SWIZZLE_W);
    470       swizzle = tgsi_util_get_src_register_swizzle(&reg.Register, chan_index);
    471    }
    472 
    473    assert(off->Index <= bld_base->info->file_max[off->File]);
    474 
    475    if (bld_base->emit_fetch_funcs[off->File]) {
    476       res = bld_base->emit_fetch_funcs[off->File](bld_base, &reg, stype,
    477                                                            swizzle);
    478    } else {
    479       assert(0 && "invalid src register in emit_fetch_texoffset()");
    480       return bld_base->base.undef;
    481    }
    482 
    483    /*
    484     * Swizzle the argument
    485     */
    486 
    487    if (swizzle == ~0u) {
    488       res = bld_base->emit_swizzle(bld_base, res,
    489                                    off->SwizzleX,
    490                                    off->SwizzleY,
    491                                    off->SwizzleZ,
    492                                    /* there's no 4th channel */
    493                                    off->SwizzleX);
    494    }
    495 
    496    return res;
    497 
    498 }
    499 
    500 
    501 boolean
    502 lp_build_tgsi_llvm(
    503    struct lp_build_tgsi_context * bld_base,
    504    const struct tgsi_token *tokens)
    505 {
    506    struct tgsi_parse_context parse;
    507 
    508    if (bld_base->emit_prologue) {
    509       bld_base->emit_prologue(bld_base);
    510    }
    511 
    512    if (!lp_bld_tgsi_list_init(bld_base)) {
    513       return FALSE;
    514    }
    515 
    516    tgsi_parse_init( &parse, tokens );
    517 
    518    while( !tgsi_parse_end_of_tokens( &parse ) ) {
    519       tgsi_parse_token( &parse );
    520 
    521       switch( parse.FullToken.Token.Type ) {
    522       case TGSI_TOKEN_TYPE_DECLARATION:
    523          /* Inputs already interpolated */
    524          bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration);
    525          break;
    526 
    527       case TGSI_TOKEN_TYPE_INSTRUCTION:
    528          lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction);
    529          break;
    530 
    531       case TGSI_TOKEN_TYPE_IMMEDIATE:
    532          bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate);
    533          break;
    534 
    535       case TGSI_TOKEN_TYPE_PROPERTY:
    536          break;
    537 
    538       default:
    539          assert( 0 );
    540       }
    541    }
    542 
    543    while (bld_base->pc != -1) {
    544       const struct tgsi_full_instruction *instr =
    545          bld_base->instructions + bld_base->pc;
    546       if (!lp_build_tgsi_inst_llvm(bld_base, instr)) {
    547          _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
    548                        tgsi_get_opcode_name(instr->Instruction.Opcode));
    549          return FALSE;
    550       }
    551    }
    552 
    553    tgsi_parse_free(&parse);
    554 
    555    FREE(bld_base->instructions);
    556 
    557    if (bld_base->emit_epilogue) {
    558       bld_base->emit_epilogue(bld_base);
    559    }
    560 
    561    return TRUE;
    562 }
    563