gallium: Add support for 32x32 muls with 64 bit results
authorZack Rusin <zackr@vmware.com>
Tue, 8 Oct 2013 19:11:02 +0000 (15:11 -0400)
committerZack Rusin <zackr@vmware.com>
Wed, 9 Oct 2013 22:30:20 +0000 (18:30 -0400)
The code introduces two new 32bit integer multiplication opcodes which
can be used to produce correct 64 bit results. GLSL, OpenCL and D3D10+
require them. We use two seperate opcodes, because they match the
behavior of GLSL and OpenCL, are a lot easier to add than a single
opcode with multiple destinations and because there's not much (any)
difference wrt code-generation.

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: José Fonseca <jfonseca@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
src/gallium/auxiliary/tgsi/tgsi_exec.c
src/gallium/auxiliary/tgsi/tgsi_info.c
src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h
src/gallium/auxiliary/tgsi/tgsi_util.c
src/gallium/docs/source/tgsi.rst
src/gallium/include/pipe/p_shader_tokens.h
src/gallium/tests/graw/vertex-shader/vert-imul_hi.sh [new file with mode: 0644]
src/gallium/tests/graw/vertex-shader/vert-umul_hi.sh [new file with mode: 0644]

index 0750a502f1697131b815929e849aa0b9ac4e8596..6db1238a60da9953cfa97dbe32275729ab86e8c1 100644 (file)
@@ -3477,6 +3477,32 @@ micro_umul(union tgsi_exec_channel *dst,
    dst->u[3] = src0->u[3] * src1->u[3];
 }
 
+static void
+micro_imul_hi(union tgsi_exec_channel *dst,
+              const union tgsi_exec_channel *src0,
+              const union tgsi_exec_channel *src1)
+{
+#define I64M(x, y) ((((int64_t)x) * ((int64_t)y)) >> 32)
+   dst->i[0] = I64M(src0->i[0], src1->i[0]);
+   dst->i[1] = I64M(src0->i[1], src1->i[1]);
+   dst->i[2] = I64M(src0->i[2], src1->i[2]);
+   dst->i[3] = I64M(src0->i[3], src1->i[3]);
+#undef I64M
+}
+
+static void
+micro_umul_hi(union tgsi_exec_channel *dst,
+              const union tgsi_exec_channel *src0,
+              const union tgsi_exec_channel *src1)
+{
+#define U64M(x, y) ((((uint64_t)x) * ((uint64_t)y)) >> 32)
+   dst->u[0] = U64M(src0->u[0], src1->u[0]);
+   dst->u[1] = U64M(src0->u[1], src1->u[1]);
+   dst->u[2] = U64M(src0->u[2], src1->u[2]);
+   dst->u[3] = U64M(src0->u[3], src1->u[3]);
+#undef U64M
+}
+
 static void
 micro_useq(union tgsi_exec_channel *dst,
            const union tgsi_exec_channel *src0,
@@ -4277,6 +4303,14 @@ exec_instruction(
       exec_vector_binary(mach, inst, micro_umul, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT);
       break;
 
+   case TGSI_OPCODE_IMUL_HI:
+      exec_vector_binary(mach, inst, micro_imul_hi, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT);
+      break;
+
+   case TGSI_OPCODE_UMUL_HI:
+      exec_vector_binary(mach, inst, micro_umul_hi, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT);
+      break;
+
    case TGSI_OPCODE_USEQ:
       exec_vector_binary(mach, inst, micro_useq, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT);
       break;
index 7a5d18f59c54e80954e248bde16e21a1c00fc969..0beef44454dd121ef606de6b7dcc3efce62c7bf7 100644 (file)
@@ -219,6 +219,8 @@ static const struct tgsi_opcode_info opcode_info[TGSI_OPCODE_LAST] =
    { 1, 3, 1, 0, 0, 0, OTHR, "TEX2", TGSI_OPCODE_TEX2 },
    { 1, 3, 1, 0, 0, 0, OTHR, "TXB2", TGSI_OPCODE_TXB2 },
    { 1, 3, 1, 0, 0, 0, OTHR, "TXL2", TGSI_OPCODE_TXL2 },
+   { 1, 2, 0, 0, 0, 0, COMP, "IMUL_HI", TGSI_OPCODE_IMUL_HI },
+   { 1, 2, 0, 0, 0, 0, COMP, "UMUL_HI", TGSI_OPCODE_UMUL_HI },
 };
 
 const struct tgsi_opcode_info *
@@ -297,6 +299,7 @@ tgsi_opcode_infer_type( uint opcode )
    case TGSI_OPCODE_USLT:
    case TGSI_OPCODE_USNE:
    case TGSI_OPCODE_SVIEWINFO:
+   case TGSI_OPCODE_UMUL_HI:
       return TGSI_TYPE_UNSIGNED;
    case TGSI_OPCODE_ARL:
    case TGSI_OPCODE_ARR:
@@ -317,6 +320,7 @@ tgsi_opcode_infer_type( uint opcode )
    case TGSI_OPCODE_UARL:
    case TGSI_OPCODE_IABS:
    case TGSI_OPCODE_ISSG:
+   case TGSI_OPCODE_IMUL_HI:
       return TGSI_TYPE_SIGNED;
    default:
       return TGSI_TYPE_FLOAT;
@@ -339,7 +343,9 @@ tgsi_opcode_infer_src_type( uint opcode )
    case TGSI_OPCODE_CASE:
    case TGSI_OPCODE_SAMPLE_I:
    case TGSI_OPCODE_SAMPLE_I_MS:
+   case TGSI_OPCODE_UMUL_HI:
       return TGSI_TYPE_UNSIGNED;
+   case TGSI_OPCODE_IMUL_HI:
    case TGSI_OPCODE_I2F:
       return TGSI_TYPE_SIGNED;
    case TGSI_OPCODE_ARL:
index b8144a8916b6fce01b54ca628d130f2639c66d94..1ef78ddcc8fe05831f76c155e85c61e800114c38 100644 (file)
@@ -204,6 +204,9 @@ OP12(SAMPLE_INFO)
 
 OP13(UCMP)
 
+OP12(IMUL_HI)
+OP12(UMUL_HI)
+
 #undef OP00
 #undef OP01
 #undef OP10
index b3bc8f283a49130454f82e1df990d480206a2037..73a0667fd06f6db8d64b2c90912c4747071ac474 100644 (file)
@@ -243,6 +243,8 @@ tgsi_util_get_inst_usage_mask(const struct tgsi_full_instruction *inst,
    case TGSI_OPCODE_USHR:
    case TGSI_OPCODE_USLT:
    case TGSI_OPCODE_USNE:
+   case TGSI_OPCODE_IMUL_HI:
+   case TGSI_OPCODE_UMUL_HI:
       /* Channel-wise operations */
       read_mask = write_mask;
       break;
index 41f2798d7043ecdda6ae53f1155bc752a24a9366..f80c08d31759b506e6363a909d1d24971c29c0a9 100644 (file)
@@ -1103,6 +1103,36 @@ Support for these opcodes indicated by PIPE_SHADER_CAP_INTEGERS (all of them?)
   dst.w = src0.w \times src1.w
 
 
+.. opcode:: IMUL_HI - Signed Integer Multiply High Bits
+
+   The high 32bits of the multiplication of 2 signed integers are returned.
+
+.. math::
+
+  dst.x = (src0.x \times src1.x) >> 32
+
+  dst.y = (src0.y \times src1.y) >> 32
+
+  dst.z = (src0.z \times src1.z) >> 32
+
+  dst.w = (src0.w \times src1.w) >> 32
+
+
+.. opcode:: UMUL_HI - Unsigned Integer Multiply High Bits
+
+   The high 32bits of the multiplication of 2 unsigned integers are returned.
+
+.. math::
+
+  dst.x = (src0.x \times src1.x) >> 32
+
+  dst.y = (src0.y \times src1.y) >> 32
+
+  dst.z = (src0.z \times src1.z) >> 32
+
+  dst.w = (src0.w \times src1.w) >> 32
+
+
 .. opcode:: IDIV - Signed Integer Division
 
    TBD: behavior for division by zero.
index 1beec054c1bd2a1ffd5ff49162ff014657124488..801090204fad95a5c39c42e1b5c4cbe1f15a3824 100644 (file)
@@ -450,7 +450,10 @@ struct tgsi_property_data {
 #define TGSI_OPCODE_TXB2                178
 #define TGSI_OPCODE_TXL2                179
 
-#define TGSI_OPCODE_LAST                180
+#define TGSI_OPCODE_IMUL_HI             180
+#define TGSI_OPCODE_UMUL_HI             181
+
+#define TGSI_OPCODE_LAST                182
 
 #define TGSI_SAT_NONE            0  /* do not saturate */
 #define TGSI_SAT_ZERO_ONE        1  /* clamp to [0,1] */
diff --git a/src/gallium/tests/graw/vertex-shader/vert-imul_hi.sh b/src/gallium/tests/graw/vertex-shader/vert-imul_hi.sh
new file mode 100644 (file)
index 0000000..60e2d80
--- /dev/null
@@ -0,0 +1,13 @@
+VERT
+DCL IN[0]
+DCL IN[1]
+DCL OUT[0], POSITION
+DCL OUT[1], COLOR
+DCL TEMP[0]
+DCL TEMP[1]
+IMM[0] INT32 {-2147483648, 2, 0, -1}
+MOV OUT[0], IN[0]
+IMUL_HI TEMP[0], IMM[0].xzzx, IMM[0].yzzy
+UMUL TEMP[0], TEMP[0], IMM[0].wwww
+I2F OUT[1], TEMP[0]
+END
diff --git a/src/gallium/tests/graw/vertex-shader/vert-umul_hi.sh b/src/gallium/tests/graw/vertex-shader/vert-umul_hi.sh
new file mode 100644 (file)
index 0000000..4aa79fe
--- /dev/null
@@ -0,0 +1,11 @@
+VERT
+DCL IN[0]
+DCL IN[1]
+DCL OUT[0], POSITION
+DCL OUT[1], COLOR
+DCL TEMP[0]
+IMM[0] INT32 {4, 1073741824, 0, 1}
+MOV OUT[0], IN[0]
+UMUL_HI TEMP[0], IMM[0].xzzx, IMM[0].yzzy
+I2F OUT[1], TEMP[0]
+END