target/hexagon/cpu: add HVX IEEE FP extension
This flag will be used to control the HVX IEEE float instructions, which are only available at some Hexagon cores. When unavailable, the instruction effectively only set the destination registers to 0. Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/10fb5b86db60a465e51db2cf73185307a1ec0895.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Matheus Tavares Bernardino committed
Apr 16, 2026 at 04:38 UTC
e1245d0ea4552895429a10e6eb51f148cea4d4c0
7 files changed
+44
target/hexagon/attribs_def.h.inc
+3
@@ -196,5 +196,8 @@ DEF_ATTRIB(NOTE_SHIFT_RESOURCE, "Uses the HVX shift resource.", "", "")
196
DEF_ATTRIB(RESTRICT_NOSLOT1_STORE, "Packet must not have slot 1 store", "", "")
197
DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "")
198
199
+/* HVX IEEE FP extension attributes */
200
+DEF_ATTRIB(HVX_IEEE_FP, "HVX IEEE FP extension instruction", "", "")
201
+
202
/* Keep this as the last attribute: */
203
DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "")
target/hexagon/cpu.c
+1
@@ -75,6 +75,7 @@ static const Property hexagon_cpu_properties[] = {
75
DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0,
76
qdev_prop_uint32, target_ulong),
77
DEFINE_PROP_BOOL("short-circuit", HexagonCPU, short_circuit, true),
78
+ DEFINE_PROP_BOOL("ieee-fp", HexagonCPU, ieee_fp_extension, true),
79
};
80
81
const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
target/hexagon/cpu.h
+1
@@ -194,6 +194,7 @@ struct ArchCPU {
194
bool lldb_compat;
195
target_ulong lldb_stack_adjust;
196
bool short_circuit;
197
+ bool ieee_fp_extension;
198
#ifndef CONFIG_USER_ONLY
199
HexagonTLBState *tlb;
200
uint32_t boot_addr;
target/hexagon/gen_tcg_funcs.py
+12
@@ -23,6 +23,15 @@ import string
23
import hex_common
24
from textwrap import dedent
25
26
+def gen_disabled_ieee_insn(f, tag, regs):
27
+ f.write(" if (!ctx->ieee_fp_extension) {\n")
28
+ for regtype, regid in regs:
29
+ reg = hex_common.get_register(tag, regtype, regid)
30
+ if reg.is_hvx_reg() and reg.is_written():
31
+ reg.gen_zero(f)
32
+ f.write(" return;\n")
33
+ f.write(" }\n")
34
+
35
##
36
## Generate the TCG code to call the helper
37
## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
@@ -74,6 +83,9 @@ def gen_tcg_func(f, tag, regs, imms):
83
i = 1 if immlett.isupper() else 0
84
f.write(f" int {hex_common.imm_name(immlett)} = insn->immed[{i}];\n")
85
86
+ if "A_HVX_IEEE_FP" in hex_common.attribdict[tag]:
87
+ gen_disabled_ieee_insn(f, tag, regs)
88
+
89
if hex_common.is_idef_parser_enabled(tag):
90
gpr_operands = [
91
hex_common.get_register(tag, regtype, regid)
target/hexagon/hex_common.py
+25
@@ -784,6 +784,11 @@ class VRegDest(Register, Hvx, Dest):
784
TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
785
tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
786
"""))
787
+ def gen_zero(self, f):
788
+ f.write(code_fmt(f"""\
789
+ tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()},
790
+ sizeof(MMVector), sizeof(MMVector), 0);
791
+ """))
792
def gen_write(self, f, tag):
793
pass
794
def helper_hvx_desc(self, f):
@@ -850,6 +855,11 @@ class VRegReadWrite(Register, Hvx, ReadWrite):
855
TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
856
tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
857
"""))
858
+ def gen_zero(self, f):
859
+ f.write(code_fmt(f"""\
860
+ tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()},
861
+ sizeof(MMVector), sizeof(MMVector), 0);
862
+ """))
863
def gen_write(self, f, tag):
864
pass
865
def helper_hvx_desc(self, f):
@@ -882,6 +892,11 @@ class VRegTmp(Register, Hvx, ReadWrite):
892
vreg_src_off(ctx, {self.reg_num}),
893
sizeof(MMVector), sizeof(MMVector));
894
"""))
895
+ def gen_zero(self, f):
896
+ f.write(code_fmt(f"""\
897
+ tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()},
898
+ sizeof(MMVector), sizeof(MMVector), 0);
899
+ """))
900
def gen_write(self, f, tag):
901
f.write(code_fmt(f"""\
902
gen_vreg_write(ctx, {self.hvx_off()}, {self.reg_num},
@@ -915,6 +930,11 @@ class VRegPairDest(Register, Hvx, Dest):
930
TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
931
tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
932
"""))
933
+ def gen_zero(self, f):
934
+ f.write(code_fmt(f"""\
935
+ tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()},
936
+ sizeof(MMVectorPair), sizeof(MMVectorPair), 0);
937
+ """))
938
def gen_write(self, f, tag):
939
pass
940
def helper_hvx_desc(self, f):
@@ -974,6 +994,11 @@ class VRegPairReadWrite(Register, Hvx, ReadWrite):
994
TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
995
tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
996
"""))
997
+ def gen_zero(self, f):
998
+ f.write(code_fmt(f"""\
999
+ tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()},
1000
+ sizeof(MMVectorPair), sizeof(MMVectorPair), 0);
1001
+ """))
1002
def gen_write(self, f, tag):
1003
f.write(code_fmt(f"""\
1004
gen_vreg_write_pair(ctx, {self.hvx_off()}, {self.reg_num},
target/hexagon/translate.c
+1
@@ -1211,6 +1211,7 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase,
1211
ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP);
1212
ctx->short_circuit = hex_cpu->short_circuit;
1213
ctx->hex_def = HEXAGON_CPU_GET_CLASS(hex_cpu)->hex_def;
1214
+ ctx->ieee_fp_extension = hex_cpu->ieee_fp_extension;
1215
#ifndef CONFIG_USER_ONLY
1216
ctx->num_cycles = 0;
1217
ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED);
target/hexagon/translate.h
+1
@@ -81,6 +81,7 @@ typedef struct DisasContext {
81
target_ulong branch_dest;
82
bool is_tight_loop;
83
bool short_circuit;
84
+ bool ieee_fp_extension;
85
bool read_after_write;
86
bool has_hvx_overlap;
87
TCGv new_value[TOTAL_PER_THREAD_REGS];