<commit_before>/**************************************************************************
 * 
 * Copyright 2011-2012 Advanced Micro Devices, 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 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.
 * 
 **************************************************************************/

/**
 * @file
 * TGSI to LLVM IR translation.
 *
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 *
 * Based on tgsi_sse2.c code written by <NAME>, <NAME>,
 * <NAME>, and others.
 */


#include "lp_bld_tgsi_action.h"

#include "lp_bld_tgsi.h"
#include "lp_bld_arit.h"
#include "lp_bld_bitarit.h"
#include "lp_bld_const.h"
#include "lp_bld_gather.h"
#include "lp_bld_logic.h"

#include "tgsi/tgsi_exec.h"

/* XXX: The CPU only defaults should be repaced by generic ones.  In most
 * cases, the CPU defaults are just wrappers around a function in
 * lp_build_arit.c and these functions should be inlined here and the CPU
 * generic code should be removed and placed elsewhere.
 */

/* Default actions */

/* Generic fetch_arg functions */

static void scalar_unary_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, 0);
   emit_data->arg_count = 1;
   emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
}

static void scalar_binary_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_X);
   /* src1.x */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            1, TGSI_CHAN_X);
   emit_data->arg_count = 2;
   emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
}

/* TGSI_OPCODE_ADD */
static void
add_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->output[emit_data->chan] = LLVMBuildFAdd(
                                bld_base->base.gallivm->builder,
                                emit_data->args[0], emit_data->args[1], "");
}

/* TGSI_OPCODE_ARR */
static void
arr_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ROUND, emit_data->args[0]);
   emit_data->output[emit_data->chan] = LLVMBuildFPToSI(bld_base->base.gallivm->builder, tmp,
							bld_base->uint_bld.vec_type, "");
}

/* TGSI_OPCODE_CLAMP */
static void
clamp_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MAX,
                                   emit_data->args[0],
                                   emit_data->args[1]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                       TGSI_OPCODE_MIN, tmp, emit_data->args[2]);
}

/* DP* Helper */

static void
dp_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data,
   unsigned dp_components)
{
   unsigned chan, src;
   for (src = 0; src < 2; src++) {
      for (chan = 0; chan < dp_components; chan++) {
         emit_data->args[(src * dp_components) + chan] =
                     lp_build_emit_fetch(bld_base, emit_data->inst, src, chan);
      }
   }
   emit_data->dst_type = bld_base->base.elem_type;
}

/* TGSI_OPCODE_DP2 */
static void
dp2_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 2);
}

static void
dp2_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1;
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[0] /* src0.x */,
                                    emit_data->args[2] /* src1.x */);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[1] /* src0.y */,
                                    emit_data->args[3] /* src1.y */);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                                    TGSI_OPCODE_ADD, tmp0, tmp1);
}

static struct lp_build_tgsi_action dp2_action = {
   dp2_fetch_args,	 /* fetch_args */
   dp2_emit	 /* emit */
};

/* TGSI_OPCODE_DP2A */
static void
dp2a_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 2);
   emit_data->args[5] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            2, TGSI_CHAN_X);
}

static void
dp2a_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm(bld_base, TGSI_OPCODE_DP2, emit_data);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD,
                                    emit_data->args[5], tmp);
}

static struct lp_build_tgsi_action dp2a_action = {
   dp2a_fetch_args,	 /* fetch_args */
   dp2a_emit	 /* emit */
};

/* TGSI_OPCODE_DP3 */
static void
dp3_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 3);
}

static void
dp3_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1;
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[0] /* src0.x */,
                                    emit_data->args[3] /* src1.x */);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[1] /* src0.y */,
                                    emit_data->args[4] /* src1.y */);
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD, tmp1, tmp0);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[2] /* src0.z */,
                                    emit_data->args[5] /* src1.z */);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                                    TGSI_OPCODE_ADD, tmp0, tmp1);
}

static struct lp_build_tgsi_action dp3_action = {
   dp3_fetch_args,	 /* fetch_args */
   dp3_emit	 /* emit */
};

/* TGSI_OPCODDE_DP4 */

static void
dp4_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 4);
}

static void
dp4_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1;
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[0] /* src0.x */,
                                    emit_data->args[4] /* src1.x */);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[1] /* src0.y */,
                                    emit_data->args[5] /* src1.y */);
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD, tmp0, tmp1);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[2] /* src0.z */,
                                    emit_data->args[6] /* src1.z */);
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD, tmp0, tmp1);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[3] /* src0.w */,
                                    emit_data->args[7] /* src1.w */);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                                    TGSI_OPCODE_ADD, tmp0, tmp1);
}

static struct lp_build_tgsi_action dp4_action = {
   dp4_fetch_args,	 /* fetch_args */
   dp4_emit	 /* emit */
};

/* TGSI_OPCODE_DPH */
static void
dph_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 4);
   /* src0.w */
   emit_data->args[3] = bld_base->base.one;
}

const struct lp_build_tgsi_action dph_action = {
   dph_fetch_args,	 /* fetch_args */
   dp4_emit	 /* emit */
};

/* TGSI_OPCODE_DST */
static void
dst_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.y */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Y);
   /* src0.z */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Z);
   /* src1.y */
   emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            1, TGSI_CHAN_Y);
   /* src1.w */
   emit_data->args[3] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            1, TGSI_CHAN_W);
}

static void
dst_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* dst.x */
   emit_data->output[TGSI_CHAN_X] = bld_base->base.one;

   /* dst.y */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                                          TGSI_OPCODE_MUL,
                                          emit_data->args[0] /* src0.y */,
                                          emit_data->args[2] /* src1.y */);
   /* dst.z */
   emit_data->output[TGSI_CHAN_Z] = emit_data->args[1]; /* src0.z */

   /* dst.w */
   emit_data->output[TGSI_CHAN_W] = emit_data->args[3]; /* src1.w */
}

static struct lp_build_tgsi_action dst_action = {
   dst_fetch_args,	 /* fetch_args */
   dst_emit	 /* emit */
};

/* TGSI_OPCODE_END */
static void
end_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   bld_base->pc = -1;
}

/* TGSI_OPCODE_EXP */

static void
exp_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef floor_x;

   /* floor( src0.x ) */
   floor_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR,
                                      emit_data->args[0]);

   /* 2 ^ floor( src0.x ) */
   emit_data->output[TGSI_CHAN_X] = lp_build_emit_llvm_unary(bld_base,
                                       TGSI_OPCODE_EX2, floor_x);

   /* src0.x - floor( src0.x ) */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                   TGSI_OPCODE_SUB,  emit_data->args[0] /* src0.x */, floor_x);

   /* 2 ^ src0.x */
   emit_data->output[TGSI_CHAN_Z] = lp_build_emit_llvm_unary(bld_base,
                             TGSI_OPCODE_EX2, emit_data->args[0] /* src0.x */);

   emit_data->output[TGSI_CHAN_W] = bld_base->base.one;
}

const struct lp_build_tgsi_action exp_action = {
   scalar_unary_fetch_args,	 /* fetch_args */
   exp_emit	 /* emit */
};

/* TGSI_OPCODE_FRC */

static void
frc_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR,
                                  emit_data->args[0]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                       TGSI_OPCODE_SUB, emit_data->args[0], tmp);
}

/* TGSI_OPCODE_KIL */

static void
kil_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_X);
   /* src0.y */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Y);
   /* src0.z */
   emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Z);
   /* src0.w */
   emit_data->args[3] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_W);
   emit_data->arg_count = 4;
   emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
}

/* TGSI_OPCODE_KILP */

static void
kilp_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
}

/* TGSI_OPCODE_LIT */

static void
lit_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_X);
   /* src0.y */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_Y);
   /* src0.w */
   emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_W);
   emit_data->arg_count = 3;
}

static void
lit_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1, tmp2;

   /* dst.x */
   emit_data->output[TGSI_CHAN_X] = bld_base->base.one;

   /* dst. y */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                                               TGSI_OPCODE_MAX,
                                               emit_data->args[0] /* src0.x */,
                                               bld_base->base.zero);

   /* dst.z */
   /* XMM[1] = SrcReg[0].yyyy */
   tmp1 = emit_data->args[1];
   /* XMM[1] = max(XMM[1], 0) */
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MAX,
                                    tmp1, bld_base->base.zero);
   /* XMM[2] = SrcReg[0].wwww */
   tmp2 = emit_data->args[2];
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_POW,
                                    tmp1, tmp2);
   tmp0 = emit_data->args[0];
   emit_data->output[TGSI_CHAN_Z] = lp_build_emit_llvm_ternary(bld_base,
                                             TGSI_OPCODE_CMP,
                                             tmp0, bld_base->base.zero, tmp1);
   /* dst.w */
   emit_data->output[TGSI_CHAN_W] = bld_base->base.one;
}

static struct lp_build_tgsi_action lit_action = {
   lit_fetch_args,	 /* fetch_args */
   lit_emit	 /* emit */
};

/* TGSI_OPCODE_LOG */

static void
log_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{

   LLVMValueRef abs_x, log_abs_x, flr_log_abs_x, ex2_flr_log_abs_x;

   /* abs( src0.x) */
   abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS,
                                    emit_data->args[0] /* src0.x */);

   /* log( abs( src0.x ) ) */
   log_abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_LG2,
                                        abs_x);

   /* floor( log( abs( src0.x ) ) ) */
   flr_log_abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR,
                                            log_abs_x);
   /* dst.x */
   emit_data->output[TGSI_CHAN_X] = flr_log_abs_x;

   /* dst.y */
   ex2_flr_log_abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_EX2,
                                                flr_log_abs_x);

   /* abs( src0.x ) / 2^( floor( lg2( abs( src0.x ) ) ) ) */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                                    TGSI_OPCODE_DIV, abs_x, ex2_flr_log_abs_x);

   /* dst.x */
   emit_data->output[TGSI_CHAN_Z] = log_abs_x;

   /* dst.w */
   emit_data->output[TGSI_CHAN_W] = bld_base->base.one;
}

static struct lp_build_tgsi_action log_action = {
   scalar_unary_fetch_args,	 /* fetch_args */
   log_emit	 /* emit */
};

/* TGSI_OPCODE_LRP */

static void
lrp_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_SUB,
                                   emit_data->args[1],
                                   emit_data->args[2]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_ternary(bld_base,
                    TGSI_OPCODE_MAD, emit_data->args[0], tmp, emit_data->args[2]);
}

/* TGSI_OPCODE_MAD */

static void
mad_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                   emit_data->args[0],
                                   emit_data->args[1]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                       TGSI_OPCODE_ADD, tmp, emit_data->args[2]);
}

/* TGSI_OPCODE_MOV */

static void
mov_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->output[emit_data->chan] = emit_data->args[0];
}

/* TGSI_OPCODE_MUL */
static void
mul_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->output[emit_data->chan] = lp_build_mul(&bld_base->base,
                                   emit_data->args[0], emit_data->args[1]);
}

/*.TGSI_OPCODE_DIV.*/
static void fdiv_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{<commit_msg>gallivm: Lower TGSI_OPCODE_MUL to fmul by default<commit_after>/**************************************************************************
 * 
 * Copyright 2011-2012 Advanced Micro Devices, 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 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.
 * 
 **************************************************************************/

/**
 * @file
 * TGSI to LLVM IR translation.
 *
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 *
 * Based on tgsi_sse2.c code written by <NAME>, <NAME>,
 * <NAME>, and others.
 */


#include "lp_bld_tgsi_action.h"

#include "lp_bld_tgsi.h"
#include "lp_bld_arit.h"
#include "lp_bld_bitarit.h"
#include "lp_bld_const.h"
#include "lp_bld_gather.h"
#include "lp_bld_logic.h"

#include "tgsi/tgsi_exec.h"

/* XXX: The CPU only defaults should be repaced by generic ones.  In most
 * cases, the CPU defaults are just wrappers around a function in
 * lp_build_arit.c and these functions should be inlined here and the CPU
 * generic code should be removed and placed elsewhere.
 */

/* Default actions */

/* Generic fetch_arg functions */

static void scalar_unary_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, 0);
   emit_data->arg_count = 1;
   emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
}

static void scalar_binary_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_X);
   /* src1.x */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            1, TGSI_CHAN_X);
   emit_data->arg_count = 2;
   emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
}

/* TGSI_OPCODE_ADD */
static void
add_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->output[emit_data->chan] = LLVMBuildFAdd(
                                bld_base->base.gallivm->builder,
                                emit_data->args[0], emit_data->args[1], "");
}

/* TGSI_OPCODE_ARR */
static void
arr_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ROUND, emit_data->args[0]);
   emit_data->output[emit_data->chan] = LLVMBuildFPToSI(bld_base->base.gallivm->builder, tmp,
							bld_base->uint_bld.vec_type, "");
}

/* TGSI_OPCODE_CLAMP */
static void
clamp_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MAX,
                                   emit_data->args[0],
                                   emit_data->args[1]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                       TGSI_OPCODE_MIN, tmp, emit_data->args[2]);
}

/* DP* Helper */

static void
dp_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data,
   unsigned dp_components)
{
   unsigned chan, src;
   for (src = 0; src < 2; src++) {
      for (chan = 0; chan < dp_components; chan++) {
         emit_data->args[(src * dp_components) + chan] =
                     lp_build_emit_fetch(bld_base, emit_data->inst, src, chan);
      }
   }
   emit_data->dst_type = bld_base->base.elem_type;
}

/* TGSI_OPCODE_DP2 */
static void
dp2_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 2);
}

static void
dp2_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1;
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[0] /* src0.x */,
                                    emit_data->args[2] /* src1.x */);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[1] /* src0.y */,
                                    emit_data->args[3] /* src1.y */);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                                    TGSI_OPCODE_ADD, tmp0, tmp1);
}

static struct lp_build_tgsi_action dp2_action = {
   dp2_fetch_args,	 /* fetch_args */
   dp2_emit	 /* emit */
};

/* TGSI_OPCODE_DP2A */
static void
dp2a_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 2);
   emit_data->args[5] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            2, TGSI_CHAN_X);
}

static void
dp2a_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm(bld_base, TGSI_OPCODE_DP2, emit_data);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD,
                                    emit_data->args[5], tmp);
}

static struct lp_build_tgsi_action dp2a_action = {
   dp2a_fetch_args,	 /* fetch_args */
   dp2a_emit	 /* emit */
};

/* TGSI_OPCODE_DP3 */
static void
dp3_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 3);
}

static void
dp3_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1;
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[0] /* src0.x */,
                                    emit_data->args[3] /* src1.x */);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[1] /* src0.y */,
                                    emit_data->args[4] /* src1.y */);
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD, tmp1, tmp0);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[2] /* src0.z */,
                                    emit_data->args[5] /* src1.z */);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                                    TGSI_OPCODE_ADD, tmp0, tmp1);
}

static struct lp_build_tgsi_action dp3_action = {
   dp3_fetch_args,	 /* fetch_args */
   dp3_emit	 /* emit */
};

/* TGSI_OPCODDE_DP4 */

static void
dp4_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 4);
}

static void
dp4_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1;
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[0] /* src0.x */,
                                    emit_data->args[4] /* src1.x */);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[1] /* src0.y */,
                                    emit_data->args[5] /* src1.y */);
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD, tmp0, tmp1);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[2] /* src0.z */,
                                    emit_data->args[6] /* src1.z */);
   tmp0 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_ADD, tmp0, tmp1);
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                    emit_data->args[3] /* src0.w */,
                                    emit_data->args[7] /* src1.w */);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                                    TGSI_OPCODE_ADD, tmp0, tmp1);
}

static struct lp_build_tgsi_action dp4_action = {
   dp4_fetch_args,	 /* fetch_args */
   dp4_emit	 /* emit */
};

/* TGSI_OPCODE_DPH */
static void
dph_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   dp_fetch_args(bld_base, emit_data, 4);
   /* src0.w */
   emit_data->args[3] = bld_base->base.one;
}

const struct lp_build_tgsi_action dph_action = {
   dph_fetch_args,	 /* fetch_args */
   dp4_emit	 /* emit */
};

/* TGSI_OPCODE_DST */
static void
dst_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.y */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Y);
   /* src0.z */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Z);
   /* src1.y */
   emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            1, TGSI_CHAN_Y);
   /* src1.w */
   emit_data->args[3] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            1, TGSI_CHAN_W);
}

static void
dst_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* dst.x */
   emit_data->output[TGSI_CHAN_X] = bld_base->base.one;

   /* dst.y */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                                          TGSI_OPCODE_MUL,
                                          emit_data->args[0] /* src0.y */,
                                          emit_data->args[2] /* src1.y */);
   /* dst.z */
   emit_data->output[TGSI_CHAN_Z] = emit_data->args[1]; /* src0.z */

   /* dst.w */
   emit_data->output[TGSI_CHAN_W] = emit_data->args[3]; /* src1.w */
}

static struct lp_build_tgsi_action dst_action = {
   dst_fetch_args,	 /* fetch_args */
   dst_emit	 /* emit */
};

/* TGSI_OPCODE_END */
static void
end_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   bld_base->pc = -1;
}

/* TGSI_OPCODE_EXP */

static void
exp_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef floor_x;

   /* floor( src0.x ) */
   floor_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR,
                                      emit_data->args[0]);

   /* 2 ^ floor( src0.x ) */
   emit_data->output[TGSI_CHAN_X] = lp_build_emit_llvm_unary(bld_base,
                                       TGSI_OPCODE_EX2, floor_x);

   /* src0.x - floor( src0.x ) */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                   TGSI_OPCODE_SUB,  emit_data->args[0] /* src0.x */, floor_x);

   /* 2 ^ src0.x */
   emit_data->output[TGSI_CHAN_Z] = lp_build_emit_llvm_unary(bld_base,
                             TGSI_OPCODE_EX2, emit_data->args[0] /* src0.x */);

   emit_data->output[TGSI_CHAN_W] = bld_base->base.one;
}

const struct lp_build_tgsi_action exp_action = {
   scalar_unary_fetch_args,	 /* fetch_args */
   exp_emit	 /* emit */
};

/* TGSI_OPCODE_FRC */

static void
frc_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR,
                                  emit_data->args[0]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                       TGSI_OPCODE_SUB, emit_data->args[0], tmp);
}

/* TGSI_OPCODE_KIL */

static void
kil_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_X);
   /* src0.y */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Y);
   /* src0.z */
   emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_Z);
   /* src0.w */
   emit_data->args[3] = lp_build_emit_fetch(bld_base, emit_data->inst,
                                            0, TGSI_CHAN_W);
   emit_data->arg_count = 4;
   emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
}

/* TGSI_OPCODE_KILP */

static void
kilp_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
}

/* TGSI_OPCODE_LIT */

static void
lit_fetch_args(
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   /* src0.x */
   emit_data->args[0] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_X);
   /* src0.y */
   emit_data->args[1] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_Y);
   /* src0.w */
   emit_data->args[2] = lp_build_emit_fetch(bld_base, emit_data->inst, 0, TGSI_CHAN_W);
   emit_data->arg_count = 3;
}

static void
lit_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp0, tmp1, tmp2;

   /* dst.x */
   emit_data->output[TGSI_CHAN_X] = bld_base->base.one;

   /* dst. y */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                                               TGSI_OPCODE_MAX,
                                               emit_data->args[0] /* src0.x */,
                                               bld_base->base.zero);

   /* dst.z */
   /* XMM[1] = SrcReg[0].yyyy */
   tmp1 = emit_data->args[1];
   /* XMM[1] = max(XMM[1], 0) */
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MAX,
                                    tmp1, bld_base->base.zero);
   /* XMM[2] = SrcReg[0].wwww */
   tmp2 = emit_data->args[2];
   tmp1 = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_POW,
                                    tmp1, tmp2);
   tmp0 = emit_data->args[0];
   emit_data->output[TGSI_CHAN_Z] = lp_build_emit_llvm_ternary(bld_base,
                                             TGSI_OPCODE_CMP,
                                             tmp0, bld_base->base.zero, tmp1);
   /* dst.w */
   emit_data->output[TGSI_CHAN_W] = bld_base->base.one;
}

static struct lp_build_tgsi_action lit_action = {
   lit_fetch_args,	 /* fetch_args */
   lit_emit	 /* emit */
};

/* TGSI_OPCODE_LOG */

static void
log_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{

   LLVMValueRef abs_x, log_abs_x, flr_log_abs_x, ex2_flr_log_abs_x;

   /* abs( src0.x) */
   abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS,
                                    emit_data->args[0] /* src0.x */);

   /* log( abs( src0.x ) ) */
   log_abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_LG2,
                                        abs_x);

   /* floor( log( abs( src0.x ) ) ) */
   flr_log_abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_FLR,
                                            log_abs_x);
   /* dst.x */
   emit_data->output[TGSI_CHAN_X] = flr_log_abs_x;

   /* dst.y */
   ex2_flr_log_abs_x = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_EX2,
                                                flr_log_abs_x);

   /* abs( src0.x ) / 2^( floor( lg2( abs( src0.x ) ) ) ) */
   emit_data->output[TGSI_CHAN_Y] = lp_build_emit_llvm_binary(bld_base,
                                    TGSI_OPCODE_DIV, abs_x, ex2_flr_log_abs_x);

   /* dst.x */
   emit_data->output[TGSI_CHAN_Z] = log_abs_x;

   /* dst.w */
   emit_data->output[TGSI_CHAN_W] = bld_base->base.one;
}

static struct lp_build_tgsi_action log_action = {
   scalar_unary_fetch_args,	 /* fetch_args */
   log_emit	 /* emit */
};

/* TGSI_OPCODE_LRP */

static void
lrp_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_SUB,
                                   emit_data->args[1],
                                   emit_data->args[2]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_ternary(bld_base,
                    TGSI_OPCODE_MAD, emit_data->args[0], tmp, emit_data->args[2]);
}

/* TGSI_OPCODE_MAD */

static void
mad_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   LLVMValueRef tmp;
   tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_MUL,
                                   emit_data->args[0],
                                   emit_data->args[1]);
   emit_data->output[emit_data->chan] = lp_build_emit_llvm_binary(bld_base,
                                       TGSI_OPCODE_ADD, tmp, emit_data->args[2]);
}

/* TGSI_OPCODE_MOV */

static void
mov_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->output[emit_data->chan] = emit_data->args[0];
}

/* TGSI_OPCODE_MUL */
static void
mul_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
   emit_data->output[emit_data->chan] = LLVMBuildFMul(
                                   bld_base->base.gallivm->builder,
                                   emit_data->args[0], emit_data->args[1], "");
}

/*.TGSI_OPCODE_DIV.*/
static void fdiv_emit(
   const struct lp_build_tgsi_action * action,
   struct lp_build_tgsi_context * bld_base,
   struct lp_build_emit_data * emit_data)
{
{'fraction_non_alphanumeric': 0.11245944357867307, 'fraction_numerical': 0.013029149528651356, 'mean_word_length': 2.4360955056179776, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 330, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 171, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4734178', 'n_tokens_mistral': 14494, 'n_tokens_neox': 14073, 'n_words': 2403}