On 10/4/2026 8:26 PM, Brian Cain wrote: > 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 | 29 +++++++++++++++++ > 3 files changed, 68 insertions(+), 21 deletions(-) > > diff --git a/target/hexagon/mmvec/mmvec.h b/target/hexagon/mmvec/mmvec.h > index 662f9d1597e..462d66b686b 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..b418aa716b8 100755 > --- a/target/hexagon/hex_common.py > +++ b/target/hexagon/hex_common.py > @@ -448,6 +448,25 @@ 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), > + MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4, > + 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), > + MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4, > + V_EXTENDED_BYTEVAL); > + tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()}, > + {self.hvx_off()} + sizeof(MMVector) > + + offsetof(MMVector, ext), > + MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4, > + V_EXTENDED_BYTEVAL); > + """)) >
According to previous patch, do we want to use sizeof(MMVector) here?
