diff options
-rw-r--r-- | target/hexagon/attribs_def.h.inc | 1 | ||||
-rwxr-xr-x | target/hexagon/hex_common.py | 2 | ||||
-rw-r--r-- | target/hexagon/macros.h | 2 | ||||
-rw-r--r-- | target/hexagon/translate.c | 9 | ||||
-rw-r--r-- | tests/tcg/hexagon/Makefile.target | 1 | ||||
-rw-r--r-- | tests/tcg/hexagon/overflow.c | 107 |
6 files changed, 120 insertions, 2 deletions
diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index 3815509..e44a7ea 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -64,6 +64,7 @@ DEF_ATTRIB(IMPLICIT_WRITES_P1, "Writes Predicate 1", "", "UREG.P1") DEF_ATTRIB(IMPLICIT_WRITES_P2, "Writes Predicate 1", "", "UREG.P2") DEF_ATTRIB(IMPLICIT_WRITES_P3, "May write Predicate 3", "", "UREG.P3") DEF_ATTRIB(IMPLICIT_READS_PC, "Reads the PC register", "", "") +DEF_ATTRIB(IMPLICIT_WRITES_USR, "May write USR", "", "") DEF_ATTRIB(WRITES_PRED_REG, "Writes a predicate register", "", "") DEF_ATTRIB(CRSLOT23, "Can execute in slot 2 or slot 3 (CR)", "", "") diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index b3b5340..a84b003 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -73,6 +73,8 @@ def calculate_attribs(): add_qemu_macro_attrib('fWRITE_P1', 'A_WRITES_PRED_REG') add_qemu_macro_attrib('fWRITE_P2', 'A_WRITES_PRED_REG') add_qemu_macro_attrib('fWRITE_P3', 'A_WRITES_PRED_REG') + add_qemu_macro_attrib('fSET_OVERFLOW', 'A_IMPLICIT_WRITES_USR') + add_qemu_macro_attrib('fSET_LPCFG', 'A_IMPLICIT_WRITES_USR') # Recurse down macros, find attributes from sub-macros macroValues = list(macros.values()) diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index 5c19cde..13e957b 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -62,7 +62,7 @@ reg_field_info[FIELD].offset) #define SET_USR_FIELD(FIELD, VAL) \ - fINSERT_BITS(env->gpr[HEX_REG_USR], reg_field_info[FIELD].width, \ + fINSERT_BITS(env->new_value[HEX_REG_USR], reg_field_info[FIELD].width, \ reg_field_info[FIELD].offset, (VAL)) #endif diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 724b4fc..e10ef36 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -204,7 +204,12 @@ static void mark_implicit_reg_write(DisasContext *ctx, Insn *insn, int attrib, int rnum) { if (GET_ATTRIB(insn->opcode, attrib)) { - bool is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC); + /* + * USR is used to set overflow and FP exceptions, + * so treat it as conditional + */ + bool is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC) || + rnum == HEX_REG_USR; if (is_predicated && !is_preloaded(ctx, rnum)) { tcg_gen_mov_tl(hex_new_value[rnum], hex_gpr[rnum]); } @@ -230,6 +235,8 @@ static void mark_implicit_reg_writes(DisasContext *ctx, Insn *insn) mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0); mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1); mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1); + mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_USR, HEX_REG_USR); + mark_implicit_reg_write(ctx, insn, A_FPOP, HEX_REG_USR); } static void mark_implicit_pred_writes(DisasContext *ctx, Insn *insn) diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index c1e1650..8b07a28 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -40,5 +40,6 @@ HEX_TESTS += load_unpack HEX_TESTS += load_align HEX_TESTS += atomics HEX_TESTS += fpstuff +HEX_TESTS += overflow TESTS += $(HEX_TESTS) diff --git a/tests/tcg/hexagon/overflow.c b/tests/tcg/hexagon/overflow.c new file mode 100644 index 0000000..196fcf7 --- /dev/null +++ b/tests/tcg/hexagon/overflow.c @@ -0,0 +1,107 @@ +/* + * Copyright(c) 2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <setjmp.h> +#include <signal.h> + + +int err; + +static void __check(const char *filename, int line, int x, int expect) +{ + if (x != expect) { + printf("ERROR %s:%d - %d != %d\n", + filename, line, x, expect); + err++; + } +} + +#define check(x, expect) __check(__FILE__, __LINE__, (x), (expect)) + +static int satub(int src, int *p, int *ovf_result) +{ + int result; + int usr; + + /* + * This instruction can set bit 0 (OVF/overflow) in usr + * Clear the bit first, then return that bit to the caller + * + * We also store the src into *p in the same packet, so we + * can ensure the overflow doesn't get set when an exception + * is generated. + */ + asm volatile("r2 = usr\n\t" + "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */ + "usr = r2\n\t" + "{\n\t" + " %0 = satub(%2)\n\t" + " memw(%3) = %2\n\t" + "}\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) + : "r"(src), "r"(p) + : "r2", "usr", "memory"); + *ovf_result = (usr & 1); + return result; +} + +int read_usr_overflow(void) +{ + int result; + asm volatile("%0 = usr\n\t" : "=r"(result)); + return result & 1; +} + + +jmp_buf jmp_env; +int usr_overflow; + +static void sig_segv(int sig, siginfo_t *info, void *puc) +{ + usr_overflow = read_usr_overflow(); + longjmp(jmp_env, 1); +} + +int main() +{ + struct sigaction act; + int ovf; + + /* SIGSEGV test */ + act.sa_sigaction = sig_segv; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &act, NULL); + if (setjmp(jmp_env) == 0) { + satub(300, 0, &ovf); + } + + act.sa_handler = SIG_DFL; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + check(usr_overflow, 0); + + puts(err ? "FAIL" : "PASS"); + return err ? EXIT_FAILURE : EXIT_SUCCESS; +} |