aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2017-12-29 13:49:43 -0800
committerJason Ekstrand <[email protected]>2018-12-13 17:49:48 +0000
commit9525971e2bec379bdbc187bfd325e7f6ded01eb5 (patch)
tree4652ca35b0d247d353363ee2ec955894d2f43ff6
parenta95ec13879d4f04d01fc04a62503578e85c846a8 (diff)
nir: Allow [iu]mul_high on non-32-bit types
Reviewed-by: Ian Romanick [email protected]
-rw-r--r--src/compiler/nir/nir_constant_expressions.py1
-rw-r--r--src/compiler/nir/nir_opcodes.py43
2 files changed, 40 insertions, 4 deletions
diff --git a/src/compiler/nir/nir_constant_expressions.py b/src/compiler/nir/nir_constant_expressions.py
index 0cd4ffcf558..459610e7c24 100644
--- a/src/compiler/nir/nir_constant_expressions.py
+++ b/src/compiler/nir/nir_constant_expressions.py
@@ -61,6 +61,7 @@ template = """\
#include <math.h>
#include "util/rounding.h" /* for _mesa_roundeven */
#include "util/half_float.h"
+#include "util/bigmath.h"
#include "nir_constant_expressions.h"
/**
diff --git a/src/compiler/nir/nir_opcodes.py b/src/compiler/nir/nir_opcodes.py
index 55b2ff0f678..ac2bb9cf711 100644
--- a/src/compiler/nir/nir_opcodes.py
+++ b/src/compiler/nir/nir_opcodes.py
@@ -468,12 +468,47 @@ binop("isub", tint, "", "src0 - src1")
binop("fmul", tfloat, commutative + associative, "src0 * src1")
# low 32-bits of signed/unsigned integer multiply
binop("imul", tint, commutative + associative, "src0 * src1")
+
# high 32-bits of signed integer multiply
-binop("imul_high", tint32, commutative,
- "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)")
+binop("imul_high", tint, commutative, """
+if (bit_size == 64) {
+ /* We need to do a full 128-bit x 128-bit multiply in order for the sign
+ * extension to work properly. The casts are kind-of annoying but needed
+ * to prevent compiler warnings.
+ */
+ uint32_t src0_u32[4] = {
+ src0,
+ (int64_t)src0 >> 32,
+ (int64_t)src0 >> 63,
+ (int64_t)src0 >> 63,
+ };
+ uint32_t src1_u32[4] = {
+ src1,
+ (int64_t)src1 >> 32,
+ (int64_t)src1 >> 63,
+ (int64_t)src1 >> 63,
+ };
+ uint32_t prod_u32[4];
+ ubm_mul_u32arr(prod_u32, src0_u32, src1_u32);
+ dst = (uint64_t)prod_u32[2] | ((uint64_t)prod_u32[3] << 32);
+} else {
+ dst = ((int64_t)src0 * (int64_t)src1) >> bit_size;
+}
+""")
+
# high 32-bits of unsigned integer multiply
-binop("umul_high", tuint32, commutative,
- "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)")
+binop("umul_high", tuint, commutative, """
+if (bit_size == 64) {
+ /* The casts are kind-of annoying but needed to prevent compiler warnings. */
+ uint32_t src0_u32[2] = { src0, (uint64_t)src0 >> 32 };
+ uint32_t src1_u32[2] = { src1, (uint64_t)src1 >> 32 };
+ uint32_t prod_u32[4];
+ ubm_mul_u32arr(prod_u32, src0_u32, src1_u32);
+ dst = (uint64_t)prod_u32[2] | ((uint64_t)prod_u32[3] << 32);
+} else {
+ dst = ((uint64_t)src0 * (uint64_t)src1) >> bit_size;
+}
+""")
binop("fdiv", tfloat, "", "src0 / src1")
binop("idiv", tint, "", "src1 == 0 ? 0 : (src0 / src1)")