Add MMVector.ext as internal QFloat state following the register content. Preserve it in full MMVector state transfers, clear it for non-QFloat writes.
Keeping the extended bits separate from the payload lets ordinary HVX ops use VECTOR_SIZE_BYTE while pair layouts use sizeof(MMVector) as their object stride. Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/mmvec/mmvec.h | 55 ++++++++++++++++++++------------ hw/hexagon/hexagon_hvx_context.c | 5 +++ target/hexagon/hex_common.py | 32 +++++++++++++++++++ 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/target/hexagon/mmvec/mmvec.h b/target/hexagon/mmvec/mmvec.h index 28f3224cffb..229e320f75f 100644 --- a/target/hexagon/mmvec/mmvec.h +++ b/target/hexagon/mmvec/mmvec.h @@ -33,29 +33,42 @@ typedef uint32_t QRegMask; /* at least NUM_QREGS bits */ #define VECTOR_SIZE_BYTE (fVECSIZE()) -typedef union { - uint64_t ud[MAX_VEC_SIZE_BYTES / 8]; - int64_t d[MAX_VEC_SIZE_BYTES / 8]; - uint32_t uw[MAX_VEC_SIZE_BYTES / 4]; - int32_t w[MAX_VEC_SIZE_BYTES / 4]; - uint16_t uh[MAX_VEC_SIZE_BYTES / 2]; - int16_t h[MAX_VEC_SIZE_BYTES / 2]; - uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; - int8_t b[MAX_VEC_SIZE_BYTES / 1]; - float32 sf[MAX_VEC_SIZE_BYTES / 4]; - float16 hf[MAX_VEC_SIZE_BYTES / 2]; - bfloat16 bf[MAX_VEC_SIZE_BYTES / 2]; +/* + * Fill value for a vector's qfloat extended-precision bits (MMVector.ext, + * below) whenever an instruction that isn't qfloat-aware writes that + * vector: architecturally the ext bits are unspecified in that case, and + * this repeating, recognizably-not-zero byte pattern is used instead of an + * all-zero fill so stray reads of stale ext state show up distinctly + * rather than silently looking like a valid (all-zero) qfloat result. + */ +#define V_EXTENDED_BYTEVAL 0x0a + +typedef struct { + union { + uint64_t ud[MAX_VEC_SIZE_BYTES / 8]; + int64_t d[MAX_VEC_SIZE_BYTES / 8]; + uint32_t uw[MAX_VEC_SIZE_BYTES / 4]; + int32_t w[MAX_VEC_SIZE_BYTES / 4]; + uint16_t uh[MAX_VEC_SIZE_BYTES / 2]; + int16_t h[MAX_VEC_SIZE_BYTES / 2]; + uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; + int8_t b[MAX_VEC_SIZE_BYTES / 1]; + float32 sf[MAX_VEC_SIZE_BYTES / 4]; + float16 hf[MAX_VEC_SIZE_BYTES / 2]; + bfloat16 bf[MAX_VEC_SIZE_BYTES / 2]; + }; + /* + * Extended precision bits for qfloat: one byte per qf32 element (only + * the low 4 bits, the LREQ nibble, are meaningful); two qf16 elements + * share a byte, 2 bits (LR) each. Any instruction that overwrites this + * vector without itself being qfloat-aware fills these with + * V_EXTENDED_BYTEVAL, since they're only meaningful as the tail end of + * a qfloat computation. + */ + uint8_t ext[MAX_VEC_SIZE_BYTES / 4]; } MMVector; -typedef union { - uint64_t ud[2 * MAX_VEC_SIZE_BYTES / 8]; - int64_t d[2 * MAX_VEC_SIZE_BYTES / 8]; - uint32_t uw[2 * MAX_VEC_SIZE_BYTES / 4]; - int32_t w[2 * MAX_VEC_SIZE_BYTES / 4]; - uint16_t uh[2 * MAX_VEC_SIZE_BYTES / 2]; - int16_t h[2 * MAX_VEC_SIZE_BYTES / 2]; - uint8_t ub[2 * MAX_VEC_SIZE_BYTES / 1]; - int8_t b[2 * MAX_VEC_SIZE_BYTES / 1]; +typedef struct { MMVector v[2]; } MMVectorPair; diff --git a/hw/hexagon/hexagon_hvx_context.c b/hw/hexagon/hexagon_hvx_context.c index 3b73498298e..575ea74fc94 100644 --- a/hw/hexagon/hexagon_hvx_context.c +++ b/hw/hexagon/hexagon_hvx_context.c @@ -15,6 +15,10 @@ static void hexagon_hvx_context_reset_hold(Object *obj, ResetType type) HexagonHVXContextState *s = HEXAGON_HVX_CONTEXT(obj); memset(&s->regs, 0, sizeof(s->regs)); + for (int i = 0; i < NUM_VREGS; i++) { + memset(s->regs.VRegs[i].ext, V_EXTENDED_BYTEVAL, + sizeof(s->regs.VRegs[i].ext)); + } } /* gvec needs VRegs/QRegs 16-aligned within the struct. */ @@ -26,6 +30,7 @@ static const VMStateDescription vmstate_mmvector = { .minimum_version_id = 1, .fields = (const VMStateField[]){ VMSTATE_UINT64_ARRAY(ud, MMVector, MAX_VEC_SIZE_BYTES / 8), + VMSTATE_UINT8_ARRAY(ext, MMVector, MAX_VEC_SIZE_BYTES / 4), VMSTATE_END_OF_LIST() } }; diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index d344284e8a2..1812e024ba7 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -448,6 +448,28 @@ def helper_arg_type(self): return "void *" def helper_arg_name(self): return f"{self.reg_tcg()}_void" + def gen_clear_ext(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()}, + {self.hvx_off()} + offsetof(MMVector, ext), + sizeof_field(MMVector, ext), + sizeof_field(MMVector, ext), + V_EXTENDED_BYTEVAL); + """)) + def gen_clear_ext_pair(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()}, + {self.hvx_off()} + offsetof(MMVector, ext), + sizeof_field(MMVector, ext), + sizeof_field(MMVector, ext), + V_EXTENDED_BYTEVAL); + tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()}, + {self.hvx_off()} + sizeof(MMVector) + + offsetof(MMVector, ext), + sizeof_field(MMVector, ext), + sizeof_field(MMVector, ext), + V_EXTENDED_BYTEVAL); + """)) # # Every register is either Dest or OldSource or NewSource or ReadWrite @@ -793,11 +815,13 @@ def decl_tcg(self, f, tag, regno): """)) if not skip_qemu_helper(tag): self.decl_tcg_ptr(f) + self.gen_clear_ext(f) def gen_zero(self, f): f.write(code_fmt(f"""\ tcg_gen_gvec_dup_imm_var(MO_64, {self.hvx_base()}, {self.hvx_off()}, sizeof(MMVector), sizeof(MMVector), 0); """)) + self.gen_clear_ext(f) def gen_write(self, f, tag): pass def helper_hvx_desc(self, f): @@ -868,11 +892,13 @@ def decl_tcg(self, f, tag, regno): """)) if not skip_qemu_helper(tag): self.decl_tcg_ptr(f) + self.gen_clear_ext(f) def gen_zero(self, f): f.write(code_fmt(f"""\ tcg_gen_gvec_dup_imm_var(MO_64, {self.hvx_base()}, {self.hvx_off()}, sizeof(MMVector), sizeof(MMVector), 0); """)) + self.gen_clear_ext(f) def gen_write(self, f, tag): pass def helper_hvx_desc(self, f): @@ -911,11 +937,13 @@ def decl_tcg(self, f, tag, regno): {self.reg_tcg()}_srcoff, sizeof(MMVector), sizeof(MMVector)); """)) + self.gen_clear_ext(f) def gen_zero(self, f): f.write(code_fmt(f"""\ tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()}, sizeof(MMVector), sizeof(MMVector), 0); """)) + self.gen_clear_ext(f) def gen_write(self, f, tag): f.write(code_fmt(f"""\ gen_vreg_write(ctx, {self.hvx_base()}, {self.hvx_off()}, @@ -948,11 +976,13 @@ def decl_tcg(self, f, tag, regno): """)) if not skip_qemu_helper(tag): self.decl_tcg_ptr(f) + self.gen_clear_ext_pair(f) def gen_zero(self, f): f.write(code_fmt(f"""\ tcg_gen_gvec_dup_imm_var(MO_64, {self.hvx_base()}, {self.hvx_off()}, sizeof(MMVectorPair), sizeof(MMVectorPair), 0); """)) + self.gen_clear_ext_pair(f) def gen_write(self, f, tag): pass def helper_hvx_desc(self, f): @@ -1026,11 +1056,13 @@ def decl_tcg(self, f, tag, regno): """)) if not skip_qemu_helper(tag): self.decl_tcg_ptr(f) + self.gen_clear_ext_pair(f) def gen_zero(self, f): f.write(code_fmt(f"""\ tcg_gen_gvec_dup_imm_var(MO_64, {self.hvx_base()}, {self.hvx_off()}, sizeof(MMVectorPair), sizeof(MMVectorPair), 0); """)) + self.gen_clear_ext_pair(f) def gen_write(self, f, tag): f.write(code_fmt(f"""\ gen_vreg_write_pair(ctx, {self.hvx_base()}, {self.hvx_off()}, -- 2.34.1
