[Mesa-dev] [PATCH 12/22] spirv/nir: implement DF conversions
Juan A. Suarez Romero
jasuarez at igalia.com
Fri Nov 25 08:52:42 UTC 2016
From: Samuel Iglesias Gonsálvez <siglesias at igalia.com>
SPIR-V does not have special opcodes for DF conversions. We need to identify
them by checking the bit size of the operand and the result.
Signed-off-by: Samuel Iglesias Gonsálvez <siglesias at igalia.com>
---
src/compiler/spirv/spirv_to_nir.c | 29 ++++++++++++++++++++++-------
src/compiler/spirv/vtn_alu.c | 37 +++++++++++++++++++++++++++----------
src/compiler/spirv/vtn_private.h | 3 ++-
3 files changed, 51 insertions(+), 18 deletions(-)
diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index a13f72a..81c73da 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -1211,12 +1211,21 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
default: {
bool swap;
- nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
-
- unsigned num_components = glsl_get_vector_elements(val->const_type);
unsigned bit_size =
glsl_get_bit_size(val->const_type);
+ bool is_double_dst = bit_size == 64;
+ bool is_double_src = is_double_dst;
+ /* We assume there is no double conversion here */
+ assert(bit_size != 64 ||
+ (opcode != SpvOpConvertFToU && opcode != SpvOpConvertFToS &&
+ opcode != SpvOpConvertSToF && opcode != SpvOpConvertUToF &&
+ opcode != SpvOpFConvert));
+ nir_op op =
+ vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+ is_double_dst, is_double_src);
+
+ unsigned num_components = glsl_get_vector_elements(val->const_type);
nir_const_value src[4];
assert(count <= 7);
for (unsigned i = 0; i < count - 4; i++) {
@@ -1224,16 +1233,22 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
vtn_value(b, w[4 + i], vtn_value_type_constant)->constant;
unsigned j = swap ? 1 - i : i;
- assert(bit_size == 32);
for (unsigned k = 0; k < num_components; k++)
- src[j].u32[k] = c->value.u[k];
+ if (!is_double_src)
+ src[j].u32[k] = c->value.u[k];
+ else
+ src[j].f64[k] = c->value.d[k];
}
nir_const_value res = nir_eval_const_opcode(op, num_components,
bit_size, src);
- for (unsigned k = 0; k < num_components; k++)
- val->constant->value.u[k] = res.u32[k];
+ for (unsigned k = 0; k < num_components; k++) {
+ if (!is_double_dst)
+ val->constant->value.u[k] = res.u32[k];
+ else
+ val->constant->value.d[k] = res.f64[k];
+ }
break;
} /* default */
diff --git a/src/compiler/spirv/vtn_alu.c b/src/compiler/spirv/vtn_alu.c
index 95ff2b1..e444d3f 100644
--- a/src/compiler/spirv/vtn_alu.c
+++ b/src/compiler/spirv/vtn_alu.c
@@ -211,7 +211,8 @@ vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode,
}
nir_op
-vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap)
+vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
+ bool is_double_dst, bool is_double_src)
{
/* Indicates that the first two arguments should be swapped. This is
* used for implementing greater-than and less-than-or-equal.
@@ -284,16 +285,21 @@ vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap)
case SpvOpFUnordGreaterThanEqual: return nir_op_fge;
/* Conversions: */
- case SpvOpConvertFToU: return nir_op_f2u;
- case SpvOpConvertFToS: return nir_op_f2i;
- case SpvOpConvertSToF: return nir_op_i2f;
- case SpvOpConvertUToF: return nir_op_u2f;
+ case SpvOpConvertFToU: return is_double_src ? nir_op_d2u : nir_op_f2u;
+ case SpvOpConvertFToS: return is_double_src ? nir_op_d2i : nir_op_f2i;
+ case SpvOpConvertSToF: return is_double_dst ? nir_op_i2d : nir_op_i2f;
+ case SpvOpConvertUToF: return is_double_dst ? nir_op_u2d : nir_op_u2f;
case SpvOpBitcast: return nir_op_imov;
case SpvOpUConvert:
case SpvOpQuantizeToF16: return nir_op_fquantize2f16;
- /* TODO: NIR is 32-bit only; these are no-ops. */
+ /* TODO: int64 is not supported yet. This is a no-op. */
case SpvOpSConvert: return nir_op_imov;
- case SpvOpFConvert: return nir_op_fmov;
+ case SpvOpFConvert:
+ if (is_double_src && !is_double_dst)
+ return nir_op_d2f;
+ if (!is_double_src && is_double_dst)
+ return nir_op_f2d;
+ return nir_op_fmov;
/* Derivatives: */
case SpvOpDPdx: return nir_op_fddx;
@@ -457,7 +463,10 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
case SpvOpFUnordLessThanEqual:
case SpvOpFUnordGreaterThanEqual: {
bool swap;
- nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
+ bool is_double_src = src[0]->bit_size;
+ bool is_double_dst = glsl_get_bit_size(val->ssa->type);
+ nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+ is_double_dst, is_double_src);
if (swap) {
nir_ssa_def *tmp = src[0];
@@ -481,7 +490,10 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
case SpvOpFOrdLessThanEqual:
case SpvOpFOrdGreaterThanEqual: {
bool swap;
- nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
+ bool is_double_src = src[0]->bit_size;
+ bool is_double_dst = glsl_get_bit_size(val->ssa->type);
+ nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+ is_double_dst, is_double_src);
if (swap) {
nir_ssa_def *tmp = src[0];
@@ -500,7 +512,12 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
default: {
bool swap;
- nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
+ bool is_double_src = src[0]->bit_size == 64;
+ bool is_double_dst =
+ glsl_get_bit_size(val->ssa->type) == 64;
+
+ nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+ is_double_dst, is_double_src);
if (swap) {
nir_ssa_def *tmp = src[0];
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 47579fe..7159f8b 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -480,7 +480,8 @@ typedef void (*vtn_execution_mode_foreach_cb)(struct vtn_builder *,
void vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value,
vtn_execution_mode_foreach_cb cb, void *data);
-nir_op vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap);
+nir_op vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
+ bool is_double_dst, bool is_double_src);
void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count);
--
2.7.4
More information about the mesa-dev
mailing list