This patch covers signed and unsigned additions. The generated code would be something along these lines:
signed: add.f r0, r1, r2 b.v @label unsigned: add.f r0, r1, r2 b.c @label gcc/ChangeLog: * config/arc/arc-modes.def: Add CC_V mode. * config/arc/predicates.md (proper_comparison_operator): Handle E_CC_Vmode. (equality_comparison_operator): Exclude CC_Vmode from eq/ne. (cc_set_register): Handle CC_Vmode. (cc_use_register): Likewise. * config/arc/arc.md (addsi3_v): New insn. (addvsi4): New expand. (addsi3_c): New insn. (uaddvsi4): New expand. * config/arc/arc-protos.h (arc_gen_unlikely_cbranch): New. * config/arc/arc.cc (arc_gen_unlikely_cbranch): New. (get_arc_condition_code): Handle E_CC_Vmode. (arc_init_reg_tables): Handle CC_Vmode. gcc/testsuite/ChangeLog: * gcc.target/arc/overflow-1.c: New. Signed-off-by: Shahab Vahedi <sha...@synopsys.com> --- gcc/config/arc/arc-modes.def | 1 + gcc/config/arc/arc-protos.h | 1 + gcc/config/arc/arc.cc | 26 +++++- gcc/config/arc/arc.md | 49 +++++++++++ gcc/config/arc/predicates.md | 14 ++- gcc/testsuite/gcc.target/arc/overflow-1.c | 100 ++++++++++++++++++++++ 6 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arc/overflow-1.c diff --git a/gcc/config/arc/arc-modes.def b/gcc/config/arc/arc-modes.def index 763e880317d..69eeec5935a 100644 --- a/gcc/config/arc/arc-modes.def +++ b/gcc/config/arc/arc-modes.def @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see CC_MODE (CC_ZN); CC_MODE (CC_Z); +CC_MODE (CC_V); CC_MODE (CC_C); CC_MODE (CC_FP_GT); CC_MODE (CC_FP_GE); diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h index 4f2db7ffb59..bc78fb0b370 100644 --- a/gcc/config/arc/arc-protos.h +++ b/gcc/config/arc/arc-protos.h @@ -50,6 +50,7 @@ extern bool arc_check_mov_const (HOST_WIDE_INT ); extern bool arc_split_mov_const (rtx *); extern bool arc_can_use_return_insn (void); extern bool arc_split_move_p (rtx *); +extern void arc_gen_unlikely_cbranch (enum rtx_code, machine_mode, rtx); #endif /* RTX_CODE */ extern bool arc_ccfsm_branch_deleted_p (void); diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc index f8c9bf17e2c..ec93d40aeb9 100644 --- a/gcc/config/arc/arc.cc +++ b/gcc/config/arc/arc.cc @@ -1538,6 +1538,13 @@ get_arc_condition_code (rtx comparison) case GEU : return ARC_CC_NC; default : gcc_unreachable (); } + case E_CC_Vmode: + switch (GET_CODE (comparison)) + { + case EQ : return ARC_CC_NV; + case NE : return ARC_CC_V; + default : gcc_unreachable (); + } case E_CC_FP_GTmode: if (TARGET_ARGONAUT_SET && TARGET_SPFP) switch (GET_CODE (comparison)) @@ -1868,7 +1875,7 @@ arc_init_reg_tables (void) /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so we must explicitly check for them here. */ if (i == (int) CCmode || i == (int) CC_ZNmode || i == (int) CC_Zmode - || i == (int) CC_Cmode + || i == (int) CC_Cmode || i == (int) CC_Vmode || i == CC_FP_GTmode || i == CC_FP_GEmode || i == CC_FP_ORDmode || i == CC_FPUmode || i == CC_FPUEmode || i == CC_FPU_UNEQmode) arc_mode_class[i] = 1 << (int) C_MODE; @@ -11852,6 +11859,23 @@ arc_libm_function_max_error (unsigned cfn, machine_mode mode, return default_libm_function_max_error (cfn, mode, boundary_p); } +/* Generate RTL for conditional branch with rtx comparison CODE in mode + CC_MODE. */ + +void +arc_gen_unlikely_cbranch (enum rtx_code cmp, machine_mode cc_mode, rtx label) +{ + rtx cc_reg, x; + + cc_reg = gen_rtx_REG (cc_mode, CC_REG); + label = gen_rtx_LABEL_REF (VOIDmode, label); + + x = gen_rtx_fmt_ee (cmp, VOIDmode, cc_reg, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx); + + emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); +} + #undef TARGET_USE_ANCHORS_FOR_SYMBOL_P #define TARGET_USE_ANCHORS_FOR_SYMBOL_P arc_use_anchors_for_symbol_p diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md index d37ecbf4292..9d011f6b4a9 100644 --- a/gcc/config/arc/arc.md +++ b/gcc/config/arc/arc.md @@ -2725,6 +2725,55 @@ archs4x, archs4xd" } ") +(define_insn "addsi3_v" + [(set (match_operand:SI 0 "register_operand" "=r,r,r, r") + (plus:SI (match_operand:SI 1 "register_operand" "r,r,0, r") + (match_operand:SI 2 "nonmemory_operand" "r,L,I,C32"))) + (set (reg:CC_V CC_REG) + (compare:CC_V (sign_extend:DI (plus:SI (match_dup 1) + (match_dup 2))) + (plus:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2)))))] + "" + "add.f\\t%0,%1,%2" + [(set_attr "cond" "set") + (set_attr "type" "compare") + (set_attr "length" "4,4,4,8")]) + +(define_expand "addvsi4" + [(match_operand:SI 0 "register_operand") + (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "nonmemory_operand") + (label_ref (match_operand 3 "" ""))] + "" + "emit_insn (gen_addsi3_v (operands[0], operands[1], operands[2])); + arc_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]); + DONE;") + +(define_insn "addsi3_c" + [(set (match_operand:SI 0 "register_operand" "=r,r,r, r") + (plus:SI (match_operand:SI 1 "register_operand" "r,r,0, r") + (match_operand:SI 2 "nonmemory_operand" "r,L,I,C32"))) + (set (reg:CC_C CC_REG) + (compare:CC_C (plus:SI (match_dup 1) + (match_dup 2)) + (match_dup 1)))] + "" + "add.f\\t%0,%1,%2" + [(set_attr "cond" "set") + (set_attr "type" "compare") + (set_attr "length" "4,4,4,8")]) + +(define_expand "uaddvsi4" + [(match_operand:SI 0 "register_operand") + (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "nonmemory_operand") + (label_ref (match_operand 3 "" ""))] + "" + "emit_insn (gen_addsi3_c (operands[0], operands[1], operands[2])); + arc_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]); + DONE;") + (define_expand "adddi3" [(set (match_operand:DI 0 "register_operand" "") (plus:DI (match_operand:DI 1 "register_operand" "") diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md index 7650e47694d..9a4ecee9bbd 100644 --- a/gcc/config/arc/predicates.md +++ b/gcc/config/arc/predicates.md @@ -426,6 +426,8 @@ return code == EQ || code == NE; case E_CC_Cmode: return code == LTU || code == GEU; + case E_CC_Vmode: + return code == EQ || code == NE; case E_CC_FP_GTmode: return code == GT || code == UNLE; case E_CC_FP_GEmode: @@ -458,7 +460,12 @@ }) (define_predicate "equality_comparison_operator" - (match_code "eq, ne")) + (match_code "eq, ne") + { + machine_mode opmode = GET_MODE (XEXP (op, 0)); + return opmode != CC_Vmode; + } +) (define_predicate "ge_lt_comparison_operator" (match_code "ge, lt")) @@ -511,7 +518,8 @@ || (mode == CC_ZNmode && rmode == CC_Zmode) || (mode == CCmode && rmode == CC_Zmode) || (mode == CCmode && rmode == CC_ZNmode) - || (mode == CCmode && rmode == CC_Cmode)) + || (mode == CCmode && rmode == CC_Cmode) + || (mode == CCmode && rmode == CC_Vmode)) return TRUE; return FALSE; @@ -531,7 +539,7 @@ if (GET_MODE (op) == CC_ZNmode) return 1; /* Fall through. */ - case E_CC_ZNmode: case E_CC_Cmode: + case E_CC_ZNmode: case E_CC_Cmode: case E_CC_Vmode: return GET_MODE (op) == CCmode; default: gcc_unreachable (); diff --git a/gcc/testsuite/gcc.target/arc/overflow-1.c b/gcc/testsuite/gcc.target/arc/overflow-1.c new file mode 100644 index 00000000000..01b3e8ad0fa --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/overflow-1.c @@ -0,0 +1,100 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include <stdbool.h> +#include <stdint.h> + +/* + * add.f r0,r0,r1 + * st_s r0,[r2] + * mov_s r0,1 + * j_s.d [blink] + * mov.nv r0,0 + */ +bool add_overflow (int32_t a, int32_t b, int32_t *res) +{ + return __builtin_add_overflow (a, b, res); +} + +/* + * add.f r0,r0,-1234 + * st_s r0,[r1] + * mov_s r0,1 + * j_s.d [blink] + * mov.nv r0,0 + */ +bool addi_overflow (int32_t a, int32_t *res) +{ + return __builtin_add_overflow (a, -1234, res); +} + +/* + * add.f r0,r0,r1 + * st_s r0,[r2] + * mov_s r0,1 + * j_s.d [blink] + * mov.hs r0,0 + */ +bool uadd_overflow (uint32_t a, uint32_t b, uint32_t *res) +{ + return __builtin_add_overflow (a, b, res); +} + +/* + * add.f r2,r0, 4321 + * seths r0,r0,-4321 + * j_s.d [blink] + * st_s r2,[r1] + */ +bool uaddi_overflow (uint32_t a, uint32_t *res) +{ + return __builtin_add_overflow (a, 4321, res); +} + +/* + * add.f r0,r0,r1 + * mov_s r0,1 + * j_s.d [blink] + * mov.nv r0,0 + */ +bool add_overflow_p (int32_t a, int32_t b, int32_t res) +{ + return __builtin_add_overflow_p (a, b, res); +} + +/* + * add.f r0,r0,-1000 + * mov_s r0,1 + * j_s.d [blink] + * mov.nv r0,0 + */ +bool addi_overflow_p (int32_t a, int32_t res) +{ + return __builtin_add_overflow_p (a, -1000, res); +} + +/* + * add.f 0,r0,r1 + * mov_s r0,1 + * j_s.d [blink] + * mov.hs r0,0 + */ +bool uadd_overflow_p (uint32_t a, uint32_t b, uint32_t res) +{ + return __builtin_add_overflow_p (a, b, res); +} + +/* + * j_s.d [blink] + * seths r0,r0,-2000 + */ +bool uaddi_overflow_p (uint32_t a, uint32_t res) +{ + return __builtin_add_overflow_p (a, 2000, res); +} + +/* { dg-final { scan-assembler-times "add.f\\s\+" 7 } } */ +/* { dg-final { scan-assembler-times "mov\.nv\\s\+" 4 } } */ +/* { dg-final { scan-assembler-times "mov\.hs\\s\+" 2 } } */ +/* { dg-final { scan-assembler-times "seths\\s\+" 2 } } */ +/* { dg-final { scan-assembler-not "cmp" } } */ -- 2.42.0