From 00f361dbddbff192f9b22f0b64d1526928aacc18 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 5 Sep 2024 18:25:32 -0700 Subject: [PATCH 1/7] target/hexagon: handle .new values Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 758e5fd12dfed..242dee373166a 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -349,6 +349,12 @@ def helper_arg(self): self.reg_tcg(), f"{self.helper_arg_type()} {self.helper_arg_name()}" ) + def from_subtype(self, subtype): + if subtype == "": + return self + raise Exception( + f"unknown subtype '{subtype}' on generic Register class") + # # Every register is either Single or Pair or Hvx @@ -1070,11 +1076,22 @@ def init_registers(): for reg in new_regs: new_registers[f"{reg.regtype}{reg.regid}"] = reg -def get_register(tag, regtype, regid): - if f"{regtype}{regid}V" in semdict[tag]: - return registers[f"{regtype}{regid}"] - else: - return new_registers[f"{regtype}{regid}"] +def is_new_reg(tag, regid): + if regid[0] in "NO": + return True + return regid[0] == "P" and \ + f"{regid}N" in semdict[tag] and \ + f"{regid}V" not in semdict[tag] + +def get_register(tag, regtype, regid, subtype=""): + regid = f"{regtype}{regid}" + is_new = is_new_reg(tag, regid) + try: + reg = new_registers[regid] if is_new else registers[regid] + except KeyError: + raise Exception(f"Unknown {'new ' if is_new else ''}register {regid}" +\ + f"from '{tag}' with syntax '{semdict[tag]}'") from None + return reg.from_subtype(subtype) def helper_ret_type(tag, regs): ## If there is a scalar result, it is the return type From f4551f97b36c0ea0621cdd3aee54779b5be53641 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 8 Aug 2024 11:17:57 -0700 Subject: [PATCH 2/7] target/hexagon: Fix badva reference, delete CAUSE The BADVA reg is referred to with the wrong identifier. The CAUSE reg field of SSR is not yet modeled, we will dump the SSR in a subsequent commit. Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 0b7fc98f6ce19..9ebed4dd86e14 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -216,8 +216,7 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags) qemu_fprintf(f, " cs0 = 0x00000000\n"); qemu_fprintf(f, " cs1 = 0x00000000\n"); #else - print_reg(f, env, HEX_REG_CAUSE); - print_reg(f, env, HEX_REG_BADVA); + print_reg(f, env, HEX_SREG_BADVA); print_reg(f, env, HEX_REG_CS0); print_reg(f, env, HEX_REG_CS1); #endif From c11ccc821692121c0f7434205471aceff0681604 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 19:50:15 -0700 Subject: [PATCH 3/7] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 242dee373166a..85eabc98766f6 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -247,8 +247,11 @@ def need_next_PC(tag): def need_pkt_has_multi_cof(tag): - return "A_COF" in attribdict[tag] - + return ( + "A_JUMP" in attribdict[tag] + or "A_CALL" in attribdict[tag] + or "J2_rte" == tag + ) and tag != "J2_hintjumpr" def need_pkt_need_commit(tag): return 'A_IMPLICIT_WRITES_USR' in attribdict[tag] From 193c29506be0e618989b5698e8e4a5644405cd32 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 09:42:54 -0700 Subject: [PATCH 4/7] target/hexagon: s/pkt_has_store/pkt_has_scalar_store To remove any confusion with HVX or other potential store instructions, we'll qualify this context var with "scalar". Signed-off-by: Brian Cain --- target/hexagon/decode.c | 4 ++-- target/hexagon/gen_helper_funcs.py | 2 +- target/hexagon/genptr.c | 3 ++- target/hexagon/idef-parser/README.rst | 2 +- target/hexagon/idef-parser/parser-helpers.c | 4 ++-- target/hexagon/insn.h | 4 ++-- target/hexagon/macros.h | 8 ++++---- target/hexagon/op_helper.c | 4 ++-- target/hexagon/translate.c | 9 +++++---- 9 files changed, 21 insertions(+), 19 deletions(-) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 23deba2426f84..b5ece604505b6 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -236,9 +236,9 @@ static void decode_set_insn_attr_fields(Packet *pkt) if (GET_ATTRIB(opcode, A_SCALAR_STORE) && !GET_ATTRIB(opcode, A_MEMSIZE_0B)) { if (pkt->insn[i].slot == 0) { - pkt->pkt_has_store_s0 = true; + pkt->pkt_has_scalar_store_s0 = true; } else { - pkt->pkt_has_store_s1 = true; + pkt->pkt_has_scalar_store_s1 = true; } } } diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py index c1f806ac4b25b..a9c0e27a801ff 100755 --- a/target/hexagon/gen_helper_funcs.py +++ b/target/hexagon/gen_helper_funcs.py @@ -69,7 +69,7 @@ def gen_helper_function(f, tag, tagregs, tagimms): if hex_common.need_slot(tag): if "A_LOAD" in hex_common.attribdict[tag]: f.write(hex_common.code_fmt(f"""\ - bool pkt_has_store_s1 = slotval & 0x1; + bool pkt_has_scalar_store_s1 = slotval & 0x1; """)) f.write(hex_common.code_fmt(f"""\ uint32_t slot = slotval >> 1; diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 2c5e15cfcf6f9..7c73772e40189 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -395,7 +395,8 @@ static inline void gen_store_conditional8(DisasContext *ctx, #ifndef CONFIG_HEXAGON_IDEF_PARSER static TCGv gen_slotval(DisasContext *ctx) { - int slotval = (ctx->pkt->pkt_has_store_s1 & 1) | (ctx->insn->slot << 1); + int slotval = + (ctx->pkt->pkt_has_scalar_store_s1 & 1) | (ctx->insn->slot << 1); return tcg_constant_tl(slotval); } #endif diff --git a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-parser/README.rst index 7199177ee33e6..235e3debee3c3 100644 --- a/target/hexagon/idef-parser/README.rst +++ b/target/hexagon/idef-parser/README.rst @@ -637,7 +637,7 @@ tinycode for the Hexagon ``add`` instruction :: ---- 00021094 - mov_i32 pkt_has_store_s1,$0x0 + mov_i32 pkt_has_scalar_store_s1,$0x0 add_i32 tmp0,r2,r2 mov_i32 loc2,tmp0 mov_i32 new_r1,loc2 diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c index a7dcd85fe43d9..3316c230f8a5f 100644 --- a/target/hexagon/idef-parser/parser-helpers.c +++ b/target/hexagon/idef-parser/parser-helpers.c @@ -1725,7 +1725,7 @@ void gen_cancel(Context *c, YYLTYPE *locp) void gen_load_cancel(Context *c, YYLTYPE *locp) { - OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n"); + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_scalar_store_s1) {\n"); OUT(c, locp, "ctx->s1_store_processed = false;\n"); OUT(c, locp, "process_store(ctx, 1);\n"); OUT(c, locp, "}\n"); @@ -1750,7 +1750,7 @@ void gen_load(Context *c, YYLTYPE *locp, HexValue *width, /* Lookup the effective address EA */ find_variable(c, locp, ea, ea); - OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n"); + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_scalar_store_s1) {\n"); OUT(c, locp, "probe_noshuf_load(", ea, ", ", width, ", ctx->mem_idx);\n"); OUT(c, locp, "process_store(ctx, 1);\n"); OUT(c, locp, "}\n"); diff --git a/target/hexagon/insn.h b/target/hexagon/insn.h index 24dcf7fe9f385..5d59430da9e12 100644 --- a/target/hexagon/insn.h +++ b/target/hexagon/insn.h @@ -66,8 +66,8 @@ struct Packet { bool pkt_has_dczeroa; - bool pkt_has_store_s0; - bool pkt_has_store_s1; + bool pkt_has_scalar_store_s0; + bool pkt_has_scalar_store_s1; bool pkt_has_hvx; Insn *vhist_insn; diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index ee3d4c88e7bdf..b6e5c8aae251f 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -82,7 +82,7 @@ */ #define CHECK_NOSHUF(VA, SIZE) \ do { \ - if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + if (insn->slot == 0 && ctx->pkt->pkt_has_scalar_store_s1) { \ probe_noshuf_load(VA, SIZE, ctx->mem_idx); \ process_store(ctx, 1); \ } \ @@ -93,11 +93,11 @@ TCGLabel *noshuf_label = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, PRED, 0, noshuf_label); \ GET_EA; \ - if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + if (insn->slot == 0 && ctx->pkt->pkt_has_scalar_store_s1) { \ probe_noshuf_load(EA, SIZE, ctx->mem_idx); \ } \ gen_set_label(noshuf_label); \ - if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + if (insn->slot == 0 && ctx->pkt->pkt_has_scalar_store_s1) { \ process_store(ctx, 1); \ } \ } while (0) @@ -524,7 +524,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #define fLOAD(NUM, SIZE, SIGN, EA, DST) \ do { \ - check_noshuf(env, pkt_has_store_s1, slot, EA, SIZE, GETPC()); \ + check_noshuf(env, pkt_has_scalar_store_s1, slot, EA, SIZE, GETPC()); \ DST = (size##SIZE##SIGN##_t)MEM_LOAD##SIZE(env, EA, GETPC()); \ } while (0) #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 6da8db8ea5c59..6ff37680d9653 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -463,11 +463,11 @@ void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask) * If the load is in slot 0 and there is a store in slot1 (that * wasn't cancelled), we have to do the store first. */ -static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1, +static void check_noshuf(CPUHexagonState *env, bool pkt_has_scalar_store_s1, uint32_t slot, target_ulong vaddr, int size, uintptr_t ra) { - if (slot == 0 && pkt_has_store_s1 && + if (slot == 0 && pkt_has_scalar_store_s1 && ((env->slot_cancelled & (1 << 1)) == 0)) { probe_read(env, vaddr, size, MMU_USER_IDX, ra); commit_store(env, 1, ra); diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index fe7858703c8cb..eaafb16582405 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -693,11 +693,11 @@ static void process_store_log(DisasContext *ctx) * the memory accesses overlap. */ Packet *pkt = ctx->pkt; - if (pkt->pkt_has_store_s1) { + if (pkt->pkt_has_scalar_store_s1) { g_assert(!pkt->pkt_has_dczeroa); process_store(ctx, 1); } - if (pkt->pkt_has_store_s0) { + if (pkt->pkt_has_scalar_store_s0) { g_assert(!pkt->pkt_has_dczeroa); process_store(ctx, 0); } @@ -822,8 +822,9 @@ static void gen_commit_packet(DisasContext *ctx) * involved in committing the packet. */ Packet *pkt = ctx->pkt; - bool has_store_s0 = pkt->pkt_has_store_s0; - bool has_store_s1 = (pkt->pkt_has_store_s1 && !ctx->s1_store_processed); + bool has_store_s0 = pkt->pkt_has_scalar_store_s0; + bool has_store_s1 = + (pkt->pkt_has_scalar_store_s1 && !ctx->s1_store_processed); bool has_hvx_store = pkt_has_hvx_store(pkt); if (pkt->pkt_has_dczeroa) { /* From d7a851cb8ad53fc5feb78562491654fd3e711416 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Mon, 26 Sep 2022 15:46:03 -0300 Subject: [PATCH 5/7] target/hexagon: raise exception on multiple writes to same reg As specified by the PRM, we should raise an exception when a packet contains multiple writes to the same register. Lets introduce a bitmap at the CPUArchState, looking for writes to already written registers and properly generate an exception when needed. Also add a test case to tests/tcg/system. The added test shows a scenario in which multiple writes are performed to the same register but qemu fails to detect that and throw the appropriated exception. This happens because we are not cleaning hex_slot_cancelled as frequently as we should, so an old state is used and the packet that should raise an exception is considered as cancelled by the code that would detect the multiple writes issue. Let's fix that by cleaning hex_slot_canceled on all conditional instructions instead, which should cover all cases where the variable is used to detect multiple writes. Signed-off-by: Matheus Tavares Bernardino --- target/hexagon/cpu.h | 4 +++ target/hexagon/cpu_bits.h | 2 ++ target/hexagon/genptr.c | 3 ++ target/hexagon/helper.h | 4 +++ target/hexagon/op_helper.c | 44 +++++++++++++++++++++++++++++ target/hexagon/translate.c | 9 ++++-- target/hexagon/translate.h | 1 + tests/tcg/hexagon/Makefile.target | 4 +++ tests/tcg/hexagon/multiple-writes.S | 32 +++++++++++++++++++++ 9 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/hexagon/multiple-writes.S diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 79e60d4bfa1b0..afe4d2808cdd9 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -28,6 +28,7 @@ #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 +#define NUM_GPREGS 32 #define SLOTS_MAX 4 #define STORES_MAX 2 @@ -78,6 +79,9 @@ typedef struct CPUArchState { uint8_t slot_cancelled; target_ulong new_value_usr; + target_ulong gpreg_written; + QEMU_BUILD_BUG_MSG(NUM_GPREGS > CHAR_BIT * sizeof(target_ulong), + "Hexagon's CPUArchState.gpreg_written type is too small"); MemLog mem_log_stores[STORES_MAX]; diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index ff596e2a94c98..cc15e33358183 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -26,6 +26,7 @@ enum hex_event { HEX_EVENT_NONE = -1, HEX_EVENT_TRAP0 = 0x008, + HEX_EVENT_PRECISE = 0x2, }; enum hex_cause { @@ -34,6 +35,7 @@ enum hex_cause { HEX_CAUSE_FETCH_NO_UPAGE = 0x012, HEX_CAUSE_INVALID_PACKET = 0x015, HEX_CAUSE_INVALID_OPCODE = 0x015, + HEX_CAUSE_REG_WRITE_CONFLICT = 0x01d, HEX_CAUSE_PC_NOT_ALIGNED = 0x01e, HEX_CAUSE_PRIV_NO_UREAD = 0x024, HEX_CAUSE_PRIV_NO_UWRITE = 0x025, diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 7c73772e40189..fa312c6fef72d 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -100,6 +100,7 @@ void gen_log_reg_write(DisasContext *ctx, int rnum, TCGv val) gen_masked_reg_write(val, hex_gpr[rnum], reg_mask); tcg_gen_mov_tl(get_result_gpr(ctx, rnum), val); + gen_helper_check_reg_write(tcg_env, tcg_constant_tl(rnum)); } static void gen_log_reg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val) @@ -113,6 +114,8 @@ static void gen_log_reg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val) /* High word */ tcg_gen_extrh_i64_i32(val32, val); gen_log_reg_write(ctx, rnum + 1, val32); + + gen_helper_check_reg_write_pair(tcg_env, tcg_constant_tl(rnum)); } TCGv get_result_pred(DisasContext *ctx, int pnum) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index f8baa599c88cd..5bf072502235f 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -30,6 +30,10 @@ DEF_HELPER_5(vacsh_val, s64, env, s64, s64, s64, i32) DEF_HELPER_FLAGS_4(vacsh_pred, TCG_CALL_NO_RWG_SE, s32, env, s64, s64, s64) DEF_HELPER_FLAGS_2(cabacdecbin_val, TCG_CALL_NO_RWG_SE, s64, s64, s64) DEF_HELPER_FLAGS_2(cabacdecbin_pred, TCG_CALL_NO_RWG_SE, s32, s64, s64) +DEF_HELPER_2(check_reg_write, void, env, int) +DEF_HELPER_3(check_cond_reg_write, void, env, int, int) +DEF_HELPER_2(check_reg_write_pair, void, env, int) +DEF_HELPER_3(check_cond_reg_write_pair, void, env, int, int) /* Floating point */ DEF_HELPER_2(conv_sf2df, f64, env, f32) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 6ff37680d9653..1d5bc7782a8d4 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -59,6 +59,24 @@ void log_store32(CPUHexagonState *env, target_ulong addr, env->mem_log_stores[slot].data32 = val; } +static void do_check_reg_write(CPUHexagonState *env, int rnum) +{ + target_ulong mask = 1 << rnum; + if (rnum >= NUM_GPREGS) { + return; + } + if ((env->gpreg_written & mask) == 0) { + env->gpreg_written |= mask; + return; + } +#ifdef CONFIG_USER_ONLY + hexagon_raise_exception_err(env, HEX_CAUSE_REG_WRITE_CONFLICT, 0); +#else + env->cause_code = HEX_CAUSE_REG_WRITE_CONFLICT; + hexagon_raise_exception_err(env, HEX_EVENT_PRECISE, 0); +#endif +} + void log_store64(CPUHexagonState *env, target_ulong addr, int64_t val, int width, int slot) { @@ -67,6 +85,32 @@ void log_store64(CPUHexagonState *env, target_ulong addr, env->mem_log_stores[slot].data64 = val; } +void HELPER(check_reg_write)(CPUHexagonState *env, int rnum) +{ + do_check_reg_write(env, rnum); +} + +void HELPER(check_cond_reg_write)(CPUHexagonState *env, int rnum, int skip) +{ + if (!skip) { + do_check_reg_write(env, rnum); + } +} + +void HELPER(check_reg_write_pair)(CPUHexagonState *env, int rnum) +{ + do_check_reg_write(env, rnum); + do_check_reg_write(env, rnum + 1); +} + +void HELPER(check_cond_reg_write_pair)(CPUHexagonState *env, int rnum, int skip) +{ + if (!skip) { + do_check_reg_write(env, rnum); + do_check_reg_write(env, rnum + 1); + } +} + static void commit_store(CPUHexagonState *env, int slot_num, uintptr_t ra) { uint8_t width = env->mem_log_stores[slot_num].width; diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index eaafb16582405..5b0bb79b66112 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -50,6 +50,7 @@ TCGv hex_gpr[TOTAL_PER_THREAD_REGS]; TCGv hex_pred[NUM_PREGS]; TCGv hex_slot_cancelled; TCGv hex_new_value_usr; +TCGv hex_gpreg_written; TCGv hex_store_addr[STORES_MAX]; TCGv hex_store_width[STORES_MAX]; TCGv hex_store_val32[STORES_MAX]; @@ -234,11 +235,9 @@ static bool check_for_attrib(Packet *pkt, int attrib) static bool need_slot_cancelled(Packet *pkt) { - /* We only need slot_cancelled for conditional store instructions */ for (int i = 0; i < pkt->num_insns; i++) { uint16_t opcode = pkt->insn[i].opcode; - if (GET_ATTRIB(opcode, A_CONDEXEC) && - GET_ATTRIB(opcode, A_SCALAR_STORE)) { + if (GET_ATTRIB(opcode, A_CONDEXEC)) { return true; } } @@ -440,6 +439,7 @@ static void gen_start_packet(DisasContext *ctx) * gen phase, so clear it again. */ bitmap_zero(ctx->pregs_written, NUM_PREGS); + tcg_gen_movi_tl(hex_gpreg_written, 0); /* Initialize the runtime state for packet semantics */ if (need_slot_cancelled(pkt)) { @@ -1059,6 +1059,9 @@ void hexagon_translate_init(void) hex_new_value_usr = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, new_value_usr), "new_value_usr"); + hex_gpreg_written = tcg_global_mem_new(tcg_env, + offsetof(CPUHexagonState, gpreg_written), "gpreg_written"); + for (i = 0; i < NUM_PREGS; i++) { hex_pred[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, pred[i]), diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index d251e2233fda7..74ebf81c62e56 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -270,6 +270,7 @@ extern TCGv hex_gpr[TOTAL_PER_THREAD_REGS]; extern TCGv hex_pred[NUM_PREGS]; extern TCGv hex_slot_cancelled; extern TCGv hex_new_value_usr; +extern TCGv hex_gpreg_written; extern TCGv hex_store_addr[STORES_MAX]; extern TCGv hex_store_width[STORES_MAX]; extern TCGv hex_store_val32[STORES_MAX]; diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index e5182c01d8a0c..2c0e8d9494e7b 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -52,6 +52,7 @@ HEX_TESTS += hvx_misc HEX_TESTS += hvx_histogram HEX_TESTS += invalid-slots HEX_TESTS += unaligned_pc +HEX_TESTS += multiple-writes run-and-check-exception = $(call run-test,$2,$3 2>$2.stderr; \ test $$? -eq 1 && grep -q "exception $(strip $1)" $2.stderr) @@ -59,6 +60,9 @@ run-and-check-exception = $(call run-test,$2,$3 2>$2.stderr; \ run-invalid-slots: invalid-slots $(call run-and-check-exception, 0x15, $@, $(QEMU) $(QEMU_OPTS) $<) +run-multiple-writes: multiple-writes + $(call run-and-check-exception, 0x1d, $@, $(QEMU) $(QEMU_OPTS) $<) + HEX_TESTS += test_abs HEX_TESTS += test_bitcnt HEX_TESTS += test_bitsplit diff --git a/tests/tcg/hexagon/multiple-writes.S b/tests/tcg/hexagon/multiple-writes.S new file mode 100644 index 0000000000000..2e8b240be7d09 --- /dev/null +++ b/tests/tcg/hexagon/multiple-writes.S @@ -0,0 +1,32 @@ +/* + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ + + .text +.global _start +_start: + r2 = #0 + p0 = !cmp.eq(r2,r2) // False + p1 = cmp.eq(r2,r2) // True + + /* + * This instruction will use slot 0 and get cancelled. The cancellation + * state should be cleaned for the next packet. + */ + if (p0) memw(r2) = r2 + + /* + * This packet is crafted so that there are two conditional writes to + * the same register and also an instruction that uses slot 0. The idea + * is that, if the cancellation state is not properly cleaned from the + * previous packet, we may end up considering this packet as cancelled as + * well (due to r1 = #0) and fail to detect the multiple writes to r6. + */ + { + r1 = #0 + if (p1) r6 = r2 + if (!p0) r6 = r2 + } + + jump pass From 6cff5f95a8ba6bbbf12a983fb769563e1390e018 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 21:22:23 -0700 Subject: [PATCH 6/7] target/hexagon: Remove unreachable We should raise an exception in the event that we encounter a packet that can't be correctly decoded, not fault. Signed-off-by: Brian Cain --- target/hexagon/decode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index b5ece604505b6..1db7f1950f741 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -489,7 +489,6 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding) insn->iclass = iclass_bits(encoding); return 1; } - g_assert_not_reached(); } else { uint32_t iclass = get_duplex_iclass(encoding); unsigned int slot0_subinsn = get_slot0_subinsn(encoding); @@ -512,6 +511,11 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding) } g_assert_not_reached(); } + /* + * invalid/unrecognized opcode; return 1 and let gen_insn() raise an + * exception when it sees this empty insn. + */ + return 1; } static void decode_add_endloop_insn(Insn *insn, int loopnum) From 23b38791011e78d2d92897797ce9ae47e05f91d7 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 19 May 2024 21:52:51 -0500 Subject: [PATCH 7/7] target/hexagon: Add memory order definition Signed-off-by: Brian Cain --- target/hexagon/cpu-param.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h index 45ee7b46409c7..ccaf6a9d28d6f 100644 --- a/target/hexagon/cpu-param.h +++ b/target/hexagon/cpu-param.h @@ -23,4 +23,9 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +/* + * Hexagon processors have a strong memory model. + */ +#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL) + #endif