+/* FIXME: this will only work if default is last */
+static void
+exec_default(struct tgsi_exec_machine *mach)
+{
+ uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask;
+
+ mach->Switch.mask |= ~mach->Switch.defaultMask & prevMask;
+
+ UPDATE_EXEC_MASK(mach);
+}
+
+static void
+exec_endswitch(struct tgsi_exec_machine *mach)
+{
+ mach->Switch = mach->SwitchStack[--mach->SwitchStackTop];
+ mach->BreakType = mach->BreakStack[--mach->BreakStackTop];
+
+ UPDATE_EXEC_MASK(mach);
+}
+
+typedef void (* micro_dop)(union tgsi_double_channel *dst,
+ const union tgsi_double_channel *src);
+
+static void
+fetch_double_channel(struct tgsi_exec_machine *mach,
+ union tgsi_double_channel *chan,
+ const struct tgsi_full_src_register *reg,
+ uint chan_0,
+ uint chan_1)
+{
+ union tgsi_exec_channel src[2];
+ uint i;
+
+ fetch_source_d(mach, &src[0], reg, chan_0, TGSI_EXEC_DATA_UINT);
+ fetch_source_d(mach, &src[1], reg, chan_1, TGSI_EXEC_DATA_UINT);
+
+ for (i = 0; i < TGSI_QUAD_SIZE; i++) {
+ chan->u[i][0] = src[0].u[i];
+ chan->u[i][1] = src[1].u[i];
+ }
+ if (reg->Register.Absolute) {
+ micro_dabs(chan, chan);
+ }
+ if (reg->Register.Negate) {
+ micro_dneg(chan, chan);
+ }
+}
+
+static void
+store_double_channel(struct tgsi_exec_machine *mach,
+ const union tgsi_double_channel *chan,
+ const struct tgsi_full_dst_register *reg,
+ const struct tgsi_full_instruction *inst,
+ uint chan_0,
+ uint chan_1)
+{
+ union tgsi_exec_channel dst[2];
+ uint i;
+ union tgsi_double_channel temp;
+ const uint execmask = mach->ExecMask;
+
+ if (!inst->Instruction.Saturate) {
+ for (i = 0; i < TGSI_QUAD_SIZE; i++)
+ if (execmask & (1 << i)) {
+ dst[0].u[i] = chan->u[i][0];
+ dst[1].u[i] = chan->u[i][1];
+ }
+ }
+ else {
+ for (i = 0; i < TGSI_QUAD_SIZE; i++)
+ if (execmask & (1 << i)) {
+ if (chan->d[i] < 0.0)
+ temp.d[i] = 0.0;
+ else if (chan->d[i] > 1.0)
+ temp.d[i] = 1.0;
+ else
+ temp.d[i] = chan->d[i];
+
+ dst[0].u[i] = temp.u[i][0];
+ dst[1].u[i] = temp.u[i][1];
+ }
+ }
+
+ store_dest_double(mach, &dst[0], reg, inst, chan_0, TGSI_EXEC_DATA_UINT);
+ if (chan_1 != -1)
+ store_dest_double(mach, &dst[1], reg, inst, chan_1, TGSI_EXEC_DATA_UINT);
+}
+
+static void
+exec_double_unary(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst,
+ micro_dop op)
+{
+ union tgsi_double_channel src;
+ union tgsi_double_channel dst;
+
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) {
+ fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y);
+ op(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y);
+ }
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) {
+ fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W);
+ op(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W);
+ }
+}
+
+static void
+exec_double_binary(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst,
+ micro_dop op,
+ enum tgsi_exec_datatype dst_datatype)
+{
+ union tgsi_double_channel src[2];
+ union tgsi_double_channel dst;
+ int first_dest_chan, second_dest_chan;
+ int wmask;
+
+ wmask = inst->Dst[0].Register.WriteMask;
+ /* these are & because of the way DSLT etc store their destinations */
+ if (wmask & TGSI_WRITEMASK_XY) {
+ first_dest_chan = TGSI_CHAN_X;
+ second_dest_chan = TGSI_CHAN_Y;
+ if (dst_datatype == TGSI_EXEC_DATA_UINT) {
+ first_dest_chan = (wmask & TGSI_WRITEMASK_X) ? TGSI_CHAN_X : TGSI_CHAN_Y;
+ second_dest_chan = -1;
+ }
+
+ fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y);
+ fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_X, TGSI_CHAN_Y);
+ op(&dst, src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, first_dest_chan, second_dest_chan);
+ }
+
+ if (wmask & TGSI_WRITEMASK_ZW) {
+ first_dest_chan = TGSI_CHAN_Z;
+ second_dest_chan = TGSI_CHAN_W;
+ if (dst_datatype == TGSI_EXEC_DATA_UINT) {
+ first_dest_chan = (wmask & TGSI_WRITEMASK_Z) ? TGSI_CHAN_Z : TGSI_CHAN_W;
+ second_dest_chan = -1;
+ }
+
+ fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W);
+ fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_Z, TGSI_CHAN_W);
+ op(&dst, src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, first_dest_chan, second_dest_chan);
+ }
+}
+
+static void
+exec_double_trinary(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst,
+ micro_dop op)
+{
+ union tgsi_double_channel src[3];
+ union tgsi_double_channel dst;
+
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) {
+ fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y);
+ fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_X, TGSI_CHAN_Y);
+ fetch_double_channel(mach, &src[2], &inst->Src[2], TGSI_CHAN_X, TGSI_CHAN_Y);
+ op(&dst, src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y);
+ }
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) {
+ fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W);
+ fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_Z, TGSI_CHAN_W);
+ fetch_double_channel(mach, &src[2], &inst->Src[2], TGSI_CHAN_Z, TGSI_CHAN_W);
+ op(&dst, src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W);
+ }
+}
+
+static void
+exec_f2d(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_exec_channel src;
+ union tgsi_double_channel dst;
+
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) {
+ fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT);
+ micro_f2d(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y);
+ }
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) {
+ fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT);
+ micro_f2d(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W);
+ }
+}
+
+static void
+exec_d2f(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_double_channel src;
+ union tgsi_exec_channel dst;
+ int wm = inst->Dst[0].Register.WriteMask;
+ int i;
+ int bit;
+ for (i = 0; i < 2; i++) {
+ bit = ffs(wm);
+ if (bit) {
+ wm &= ~(1 << (bit - 1));
+ if (i == 0)
+ fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y);
+ else
+ fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W);
+ micro_d2f(&dst, &src);
+ store_dest(mach, &dst, &inst->Dst[0], inst, bit - 1, TGSI_EXEC_DATA_FLOAT);
+ }
+ }
+}
+
+static void
+exec_i2d(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_exec_channel src;
+ union tgsi_double_channel dst;
+
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) {
+ fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_INT);
+ micro_i2d(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y);
+ }
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) {
+ fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_INT);
+ micro_i2d(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W);
+ }
+}
+
+static void
+exec_d2i(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_double_channel src;
+ union tgsi_exec_channel dst;
+ int wm = inst->Dst[0].Register.WriteMask;
+ int i;
+ int bit;
+ for (i = 0; i < 2; i++) {
+ bit = ffs(wm);
+ if (bit) {
+ wm &= ~(1 << (bit - 1));
+ if (i == 0)
+ fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y);
+ else
+ fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W);
+ micro_d2i(&dst, &src);
+ store_dest(mach, &dst, &inst->Dst[0], inst, bit - 1, TGSI_EXEC_DATA_INT);
+ }
+ }
+}
+static void
+exec_u2d(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_exec_channel src;
+ union tgsi_double_channel dst;
+
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) {
+ fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT);
+ micro_u2d(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y);
+ }
+ if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) {
+ fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_UINT);
+ micro_u2d(&dst, &src);
+ store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W);
+ }
+}
+