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);
+ """))
#
# Every register is either Dest or OldSource or NewSource or ReadWrite
@@ -793,11 +812,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 +889,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 +934,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 +973,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 +1053,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