+/* Perform a full swizzle
+ */
+static GLboolean emit_SWZ( struct compilation *cp, union instruction op )
+{
+ struct x86_reg arg0 = get_arg(cp, op.rsw.file0, op.rsw.idx0);
+ struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.rsw.dst);
+ struct x86_reg negs = get_arg(cp, FILE_REG, REG_SWZ);
+ struct x86_reg tmp = get_xmm_reg(cp);
+ GLubyte neg = op.rsw.neg;
+ GLubyte shuf2, swz, savepos, savemask, swizzle[4];
+
+ swizzle[0] = GET_SWZ(op.rsw.swz, 0);
+ swizzle[1] = GET_SWZ(op.rsw.swz, 1);
+ swizzle[2] = GET_SWZ(op.rsw.swz, 2);
+ swizzle[3] = GET_SWZ(op.rsw.swz, 3);
+
+ swz = SHUF((swizzle[0] & 3), (swizzle[1] & 3),
+ (swizzle[2] & 3), (swizzle[3] & 3));
+
+ emit_pshufd(cp, dst, arg0, swz);
+
+ /* can handle negation and replace with zero with the same shuffle/mul */
+ shuf2 = SHUF(swizzle[0] == 4 ? 2 : (neg & 1),
+ swizzle[1] == 4 ? 2 : ((neg & 2) >> 1),
+ swizzle[2] == 4 ? 2 : ((neg & 4) >> 2),
+ swizzle[3] == 4 ? 2 : ((neg & 8) >> 3));
+
+ /* now the hard part is getting those 1's in there... */
+ savepos = 0;
+ savemask = 0;
+ if (swizzle[0] == 5) savepos = 1;
+ if (swizzle[1] == 5) savepos = 2;
+ else savemask |= 1 << 2;
+ if (swizzle[2] == 5) savepos = 3;
+ else savemask |= 2 << 4;
+ if (swizzle[3] == 5) savepos = 4;
+ else savemask |= 3 << 6;
+ if (savepos) {
+ /* need a mov first as movss from memory will overwrite high bits of xmm reg */
+ sse_movups(&cp->func, tmp, negs);
+ /* can only replace lowest 32bits, thus move away that part first */
+ emit_pshufd(cp, dst, dst, savemask);
+ sse_movss(&cp->func, dst, tmp);
+ emit_pshufd(cp, dst, dst, (savepos - 1) | (savemask & 0xfc));
+ }
+
+ if (shuf2) {
+ /* Load 1,-1,0,0
+ * Use neg as arg to pshufd
+ * Multiply
+ */
+ emit_pshufd(cp, tmp, negs, shuf2);
+ sse_mulps(&cp->func, dst, tmp);
+ }
+
+ return GL_TRUE;
+}
+
+/* Helper for writemask:
+ */
+static GLboolean emit_shuf_copy1( struct compilation *cp,
+ struct x86_reg dst,
+ struct x86_reg arg0,
+ struct x86_reg arg1,
+ GLubyte shuf )
+{
+ struct x86_reg tmp = get_xmm_reg(cp);
+ sse_movups(&cp->func, dst, arg1);
+ emit_pshufd(cp, dst, dst, shuf);
+ emit_pshufd(cp, tmp, arg0, shuf);
+
+ sse_movss(&cp->func, dst, tmp);
+
+ emit_pshufd(cp, dst, dst, shuf);
+ return GL_TRUE;
+}
+
+
+/* Helper for writemask:
+ */
+static GLboolean emit_shuf_copy2( struct compilation *cp,
+ struct x86_reg dst,
+ struct x86_reg arg0,
+ struct x86_reg arg1,
+ GLubyte shuf )
+{
+ struct x86_reg tmp = get_xmm_reg(cp);
+ emit_pshufd(cp, dst, arg1, shuf);
+ emit_pshufd(cp, tmp, arg0, shuf);
+
+ sse_shufps(&cp->func, dst, tmp, SHUF(X, Y, Z, W));
+
+ emit_pshufd(cp, dst, dst, shuf);
+ return GL_TRUE;
+}
+
+
+static void emit_x87_ex2( struct compilation *cp )
+{
+ struct x86_reg st0 = x86_make_reg(file_x87, 0);
+ struct x86_reg st1 = x86_make_reg(file_x87, 1);
+ struct x86_reg st3 = x86_make_reg(file_x87, 3);
+
+ set_fpu_round_neg_inf( cp );
+
+ x87_fld(&cp->func, st0); /* a a */
+ x87_fprndint( &cp->func ); /* int(a) a */
+ x87_fld(&cp->func, st0); /* int(a) int(a) a */
+ x87_fstp(&cp->func, st3); /* int(a) a int(a)*/
+ x87_fsubp(&cp->func, st1); /* frac(a) int(a) */
+ x87_f2xm1(&cp->func); /* (2^frac(a))-1 int(a)*/
+ x87_fld1(&cp->func); /* 1 (2^frac(a))-1 int(a)*/
+ x87_faddp(&cp->func, st1); /* 2^frac(a) int(a) */
+ x87_fscale(&cp->func); /* 2^a */
+}
+
+#if 0
+static GLboolean emit_MSK2( struct compilation *cp, union instruction op )
+{
+ struct x86_reg arg0 = get_arg(cp, op.msk.file, op.msk.arg);
+ struct x86_reg arg1 = get_arg(cp, FILE_REG, op.msk.dst); /* NOTE! */
+ struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst);
+
+ /* make full width bitmask in tmp
+ * dst = ~tmp
+ * tmp &= arg0
+ * dst &= arg1
+ * dst |= tmp
+ */
+ emit_pshufd(cp, tmp, get_arg(cp, FILE_REG, REG_NEGS),
+ SHUF((op.msk.mask & 1) ? 2 : 0,
+ (op.msk.mask & 2) ? 2 : 0,
+ (op.msk.mask & 4) ? 2 : 0,
+ (op.msk.mask & 8) ? 2 : 0));
+ sse2_pnot(&cp->func, dst, tmp);
+ sse2_pand(&cp->func, arg0, tmp);
+ sse2_pand(&cp->func, arg1, dst);
+ sse2_por(&cp->func, tmp, dst);
+ return GL_TRUE;
+}
+#endif
+
+