Thanks Richard for comments. > I'll note that on RTL we already have SS_PLUS/US_PLUS and friends and > the corresponding ssadd/usadd optabs. There's not much documentation > unfortunately besides the use of gen_*_fixed_libfunc usage where the comment > suggests this is used for fixed-point operations. It looks like arm uses > fractional/accumulator modes for this but for example bfin has ssaddsi3.
I find the related description about plus family in GCC internals doc but it doesn't mention anything about mode m here. (plus:m x y) (ss_plus:m x y) (us_plus:m x y) These three expressions all represent the sum of the values represented by x and y carried out in machine mode m. They diff er in their behavior on overflow of integer modes. plus wraps round modulo the width of m; ss_plus saturates at the maximum signed value representable in m; us_plus saturates at the maximum unsigned value. > The natural thing is to use direct optab internal functions (that's what you > basically did, but you added a new optab, IMO without good reason). That makes sense to me, I will try to leverage US_PLUS instead here. > More GIMPLE-like would be to let the types involved decide whether > it's signed or unsigned saturation. That's actually what I'd prefer here > and if we don't map 1:1 to optabs then instead use tree codes like > S_PLUS_EXPR (mimicing RTL here). Sorry I don't get the point here for GIMPLE-like way. For the .SAT_ADDU, I add one restriction like unsigned_p (type) in match.pd. Looks we have a better way here. > Any other opinions? Anyone knows more about fixed-point and RTL/modes? AFAIK, the scalar of the riscv backend doesn't have fixed-point but the vector does have. They share the same mode as vector integer. For example, RVVM1SI in vector-iterators.md. Kito and Juzhe can help to correct me if any misunderstandings. Pan -----Original Message----- From: Richard Biener <richard.guent...@gmail.com> Sent: Monday, February 19, 2024 3:36 PM To: Li, Pan2 <pan2...@intel.com> Cc: gcc-patches@gcc.gnu.org; juzhe.zh...@rivai.ai; Wang, Yanzhang <yanzhang.w...@intel.com>; kito.ch...@gmail.com; tamar.christ...@arm.com Subject: Re: [PATCH v1] Internal-fn: Add new internal function SAT_ADDU On Sat, Feb 17, 2024 at 11:30 AM <pan2...@intel.com> wrote: > > From: Pan Li <pan2...@intel.com> > > This patch would like to add the middle-end presentation for the > unsigned saturation add. Aka set the result of add to the max > when overflow. It will take the pattern similar as below. > > SAT_ADDU (x, y) => (x + y) | (-(TYPE)((TYPE)(x + y) < x)) > > Take uint8_t as example, we will have: > > * SAT_ADDU (1, 254) => 255. > * SAT_ADDU (1, 255) => 255. > * SAT_ADDU (2, 255) => 255. > * SAT_ADDU (255, 255) => 255. > > The patch also implement the SAT_ADDU in the riscv backend as > the sample. Given below example: > > uint64_t sat_add_u64 (uint64_t x, uint64_t y) > { > return (x + y) | (- (uint64_t)((uint64_t)(x + y) < x)); > } > > Before this patch: > > uint64_t sat_add_uint64_t (uint64_t x, uint64_t y) > { > long unsigned int _1; > _Bool _2; > long unsigned int _3; > long unsigned int _4; > uint64_t _7; > long unsigned int _10; > __complex__ long unsigned int _11; > > ;; basic block 2, loop depth 0 > ;; pred: ENTRY > _11 = .ADD_OVERFLOW (x_5(D), y_6(D)); > _1 = REALPART_EXPR <_11>; > _10 = IMAGPART_EXPR <_11>; > _2 = _10 != 0; > _3 = (long unsigned int) _2; > _4 = -_3; > _7 = _1 | _4; > return _7; > ;; succ: EXIT > > } > > After this patch: > > uint64_t sat_add_uint64_t (uint64_t x, uint64_t y) > { > uint64_t _7; > > ;; basic block 2, loop depth 0 > ;; pred: ENTRY > _7 = .SAT_ADDU (x_5(D), y_6(D)); [tail call] > return _7; > ;; succ: EXIT > > } > > Then we will have the middle-end representation like .SAT_ADDU after > this patch. I'll note that on RTL we already have SS_PLUS/US_PLUS and friends and the corresponding ssadd/usadd optabs. There's not much documentation unfortunately besides the use of gen_*_fixed_libfunc usage where the comment suggests this is used for fixed-point operations. It looks like arm uses fractional/accumulator modes for this but for example bfin has ssaddsi3. So the question is whether the fixed-point case can be distinguished from the integer case based on mode. There's also FIXED_POINT_TYPE on the GENERIC/GIMPLE side and no special tree operator codes for them. So compared to what appears to be the case on RTL we'd need a way to represent saturating integer operations on GIMPLE. The natural thing is to use direct optab internal functions (that's what you basically did, but you added a new optab, IMO without good reason). More GIMPLE-like would be to let the types involved decide whether it's signed or unsigned saturation. That's actually what I'd prefer here and if we don't map 1:1 to optabs then instead use tree codes like S_PLUS_EXPR (mimicing RTL here). Any other opinions? Anyone knows more about fixed-point and RTL/modes? Richard. > PR target/51492 > PR target/112600 > > gcc/ChangeLog: > > * config/riscv/riscv-protos.h (riscv_expand_saturation_addu): > New func decl for the SAT_ADDU expand. > * config/riscv/riscv.cc (riscv_expand_saturation_addu): New func > impl for the SAT_ADDU expand. > * config/riscv/riscv.md (sat_addu_<mode>3): New pattern to impl > the standard name SAT_ADDU. > * doc/md.texi: Add doc for SAT_ADDU. > * internal-fn.cc (commutative_binary_fn_p): Add type IFN_SAT_ADDU. > * internal-fn.def (SAT_ADDU): Add SAT_ADDU. > * match.pd: Add simplify pattern patch for SAT_ADDU. > * optabs.def (OPTAB_D): Add sat_addu_optab. > > gcc/testsuite/ChangeLog: > > * gcc.target/riscv/sat_addu-1.c: New test. > * gcc.target/riscv/sat_addu-2.c: New test. > * gcc.target/riscv/sat_addu-3.c: New test. > * gcc.target/riscv/sat_addu-4.c: New test. > * gcc.target/riscv/sat_addu-run-1.c: New test. > * gcc.target/riscv/sat_addu-run-2.c: New test. > * gcc.target/riscv/sat_addu-run-3.c: New test. > * gcc.target/riscv/sat_addu-run-4.c: New test. > * gcc.target/riscv/sat_arith.h: New test. > > Signed-off-by: Pan Li <pan2...@intel.com> > --- > gcc/config/riscv/riscv-protos.h | 1 + > gcc/config/riscv/riscv.cc | 46 +++++++++++++++++ > gcc/config/riscv/riscv.md | 11 +++++ > gcc/doc/md.texi | 11 +++++ > gcc/internal-fn.cc | 1 + > gcc/internal-fn.def | 1 + > gcc/match.pd | 22 +++++++++ > gcc/optabs.def | 2 + > gcc/testsuite/gcc.target/riscv/sat_addu-1.c | 18 +++++++ > gcc/testsuite/gcc.target/riscv/sat_addu-2.c | 20 ++++++++ > gcc/testsuite/gcc.target/riscv/sat_addu-3.c | 17 +++++++ > gcc/testsuite/gcc.target/riscv/sat_addu-4.c | 16 ++++++ > .../gcc.target/riscv/sat_addu-run-1.c | 42 ++++++++++++++++ > .../gcc.target/riscv/sat_addu-run-2.c | 42 ++++++++++++++++ > .../gcc.target/riscv/sat_addu-run-3.c | 42 ++++++++++++++++ > .../gcc.target/riscv/sat_addu-run-4.c | 49 +++++++++++++++++++ > gcc/testsuite/gcc.target/riscv/sat_arith.h | 15 ++++++ > 17 files changed, 356 insertions(+) > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-1.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-2.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-3.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-4.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-run-1.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-run-2.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-run-3.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_addu-run-4.c > create mode 100644 gcc/testsuite/gcc.target/riscv/sat_arith.h > > diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h > index ae1685850ac..f201b2384f9 100644 > --- a/gcc/config/riscv/riscv-protos.h > +++ b/gcc/config/riscv/riscv-protos.h > @@ -132,6 +132,7 @@ extern void riscv_asm_output_external (FILE *, const > tree, const char *); > extern bool > riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT, int); > extern void riscv_legitimize_poly_move (machine_mode, rtx, rtx, rtx); > +extern void riscv_expand_saturation_addu (rtx, rtx, rtx); > > #ifdef RTX_CODE > extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool > *invert_ptr = 0); > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index 799d7919a4a..84e86eb5d49 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -10657,6 +10657,52 @@ riscv_vector_mode_supported_any_target_p > (machine_mode) > return true; > } > > +/* Emit insn for the saturation addu, aka (x + y) | - ((x + y) < x). */ > +void > +riscv_expand_saturation_addu (rtx dest, rtx x, rtx y) > +{ > + machine_mode mode = GET_MODE (dest); > + rtx pmode_sum = gen_reg_rtx (Pmode); > + rtx pmode_lt = gen_reg_rtx (Pmode); > + rtx pmode_x = gen_lowpart (Pmode, x); > + rtx pmode_y = gen_lowpart (Pmode, y); > + rtx pmode_dest = gen_reg_rtx (Pmode); > + > + /* Step-1: sum = x + y */ > + if (mode == SImode && mode != Pmode) > + { /* Take addw to avoid the sum truncate. */ > + rtx simode_sum = gen_reg_rtx (SImode); > + riscv_emit_binary (PLUS, simode_sum, x, y); > + emit_move_insn (pmode_sum, gen_lowpart (Pmode, simode_sum)); > + } > + else > + riscv_emit_binary (PLUS, pmode_sum, pmode_x, pmode_y); > + > + /* Step-1.1: truncate sum for HI and QI as we have no insn for add QI/HI. > */ > + if (mode == HImode || mode == QImode) > + { > + int shift_bits = GET_MODE_BITSIZE (Pmode) > + - GET_MODE_BITSIZE (mode).to_constant (); > + > + gcc_assert (shift_bits > 0); > + > + riscv_emit_binary (ASHIFT, pmode_sum, pmode_sum, GEN_INT (shift_bits)); > + riscv_emit_binary (LSHIFTRT, pmode_sum, pmode_sum, GEN_INT > (shift_bits)); > + } > + > + /* Step-2: lt = sum < x */ > + riscv_emit_binary (LTU, pmode_lt, pmode_sum, pmode_x); > + > + /* Step-3: lt = -lt */ > + riscv_emit_unary (NEG, pmode_lt, pmode_lt); > + > + /* Step-4: pmode_dest = sum | lt */ > + riscv_emit_binary (IOR, pmode_dest, pmode_lt, pmode_sum); > + > + /* Step-5: dest = pmode_dest */ > + emit_move_insn (dest, gen_lowpart (mode, pmode_dest)); > +} > + > /* Initialize the GCC target structure. */ > #undef TARGET_ASM_ALIGNED_HI_OP > #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md > index 39b29795cd6..03cbe5a2ca9 100644 > --- a/gcc/config/riscv/riscv.md > +++ b/gcc/config/riscv/riscv.md > @@ -3841,6 +3841,17 @@ (define_insn "*large_load_address" > [(set_attr "type" "load") > (set (attr "length") (const_int 8))]) > > +(define_expand "sat_addu_<mode>3" > + [(match_operand:ANYI 0 "register_operand") > + (match_operand:ANYI 1 "register_operand") > + (match_operand:ANYI 2 "register_operand")] > + "" > + { > + riscv_expand_saturation_addu (operands[0], operands[1], operands[2]); > + DONE; > + } > +) > + > (include "bitmanip.md") > (include "crypto.md") > (include "sync.md") > diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi > index b0c61925120..5867afdb1a0 100644 > --- a/gcc/doc/md.texi > +++ b/gcc/doc/md.texi > @@ -6653,6 +6653,17 @@ The operation is only supported for vector modes > @var{m}. > > This pattern is not allowed to @code{FAIL}. > > +@cindex @code{sat_addu_@var{m}3} instruction pattern > +@item @samp{sat_addu_@var{m}3} > +Perform the saturation unsigned add for the operand 1 and operand 2 and > +store the result into the operand 0. All operands have mode @var{m}, > +which is a scalar integer mode. > + > +@smallexample > + typedef unsigned char uint8_t; > + uint8_t sat_addu (uint8_t x, uint8_t y) => return (x + y) | -((x + y) < x); > +@end smallexample > + > @cindex @code{cmla@var{m}4} instruction pattern > @item @samp{cmla@var{m}4} > Perform a vector multiply and accumulate that is semantically the same as > diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc > index a07f25f3aee..dee73dbc614 100644 > --- a/gcc/internal-fn.cc > +++ b/gcc/internal-fn.cc > @@ -4159,6 +4159,7 @@ commutative_binary_fn_p (internal_fn fn) > case IFN_VEC_WIDEN_PLUS_HI: > case IFN_VEC_WIDEN_PLUS_EVEN: > case IFN_VEC_WIDEN_PLUS_ODD: > + case IFN_SAT_ADDU: > return true; > > default: > diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def > index c14d30365c1..a04592fc779 100644 > --- a/gcc/internal-fn.def > +++ b/gcc/internal-fn.def > @@ -428,6 +428,7 @@ DEF_INTERNAL_WIDENING_OPTAB_FN (VEC_WIDEN_ABD, > binary) > DEF_INTERNAL_OPTAB_FN (VEC_FMADDSUB, ECF_CONST, vec_fmaddsub, ternary) > DEF_INTERNAL_OPTAB_FN (VEC_FMSUBADD, ECF_CONST, vec_fmsubadd, ternary) > +DEF_INTERNAL_OPTAB_FN (SAT_ADDU, ECF_CONST | ECF_NOTHROW, sat_addu, binary) > > /* FP scales. */ > DEF_INTERNAL_FLT_FN (LDEXP, ECF_CONST, ldexp, binary) > diff --git a/gcc/match.pd b/gcc/match.pd > index 711c3a10c3f..9de1106adcf 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -1994,6 +1994,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > ) > ) > > +#if GIMPLE > + > +/* Saturation add unsigned, aka: > + SAT_ADDU = (X + Y) | - ((X + Y) < X) or > + SAT_ADDU = (X + Y) | - ((X + Y) < Y). */ > +(simplify > + (bit_ior:c (plus:c@2 @0 @1) (negate (convert (lt @2 @0)))) > + (if (optimize > + && INTEGRAL_TYPE_P (type) > + && TYPE_UNSIGNED (TREE_TYPE (@0)) > + && types_match (type, TREE_TYPE (@0)) > + && types_match (type, TREE_TYPE (@1)) > + && direct_internal_fn_supported_p (IFN_SAT_ADDU, type, > OPTIMIZE_FOR_BOTH)) > + (IFN_SAT_ADDU @0 @1))) > + > +/* SAT_ADDU (X, 0) = X */ > +(simplify > + (IFN_SAT_ADDU:c @0 integer_zerop) > + @0) > + > +#endif > + > /* A few cases of fold-const.cc negate_expr_p predicate. */ > (match negate_expr_p > INTEGER_CST > diff --git a/gcc/optabs.def b/gcc/optabs.def > index ad14f9328b9..a2c11b7707b 100644 > --- a/gcc/optabs.def > +++ b/gcc/optabs.def > @@ -300,6 +300,8 @@ OPTAB_D (usubc5_optab, "usubc$I$a5") > OPTAB_D (addptr3_optab, "addptr$a3") > OPTAB_D (spaceship_optab, "spaceship$a3") > > +OPTAB_D (sat_addu_optab, "sat_addu_$a3") > + > OPTAB_D (smul_highpart_optab, "smul$a3_highpart") > OPTAB_D (umul_highpart_optab, "umul$a3_highpart") > > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-1.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-1.c > new file mode 100644 > index 00000000000..229abef0faa > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-1.c > @@ -0,0 +1,18 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fno-schedule-insns > -fno-schedule-insns2" } */ > +/* { dg-skip-if "" { *-*-* } { "-flto" } } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include "sat_arith.h" > + > +/* > +** sat_addu_uint8_t: > +** add\s+[atx][0-9]+,\s*a0,\s*a1 > +** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff > +** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** neg\s+[atx][0-9]+,\s*[atx][0-9]+ > +** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** andi\s+a0,\s*a0,\s*0xff > +** ret > +*/ > +DEF_SAT_ADDU(uint8_t) > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-2.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-2.c > new file mode 100644 > index 00000000000..4023b030811 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-2.c > @@ -0,0 +1,20 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fno-schedule-insns > -fno-schedule-insns2" } */ > +/* { dg-skip-if "" { *-*-* } { "-flto" } } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include "sat_arith.h" > + > +/* > +** sat_addu_uint16_t: > +** add\s+[atx][0-9]+,\s*a0,\s*a1 > +** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48 > +** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48 > +** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** neg\s+[atx][0-9]+,\s*[atx][0-9]+ > +** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** slli\s+a0,\s*a0,\s*48 > +** srli\s+a0,\s*a0,\s*48 > +** ret > +*/ > +DEF_SAT_ADDU(uint16_t) > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-3.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-3.c > new file mode 100644 > index 00000000000..4d0af97fb67 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-3.c > @@ -0,0 +1,17 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fno-schedule-insns > -fno-schedule-insns2" } */ > +/* { dg-skip-if "" { *-*-* } { "-flto" } } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include "sat_arith.h" > + > +/* > +** sat_addu_uint32_t: > +** addw\s+[atx][0-9]+,\s*a0,\s*a1 > +** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** neg\s+[atx][0-9]+,\s*[atx][0-9]+ > +** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** sext.w\s+a0,\s*a0 > +** ret > +*/ > +DEF_SAT_ADDU(uint32_t) > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-4.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-4.c > new file mode 100644 > index 00000000000..926f31266e3 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-4.c > @@ -0,0 +1,16 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fno-schedule-insns > -fno-schedule-insns2" } */ > +/* { dg-skip-if "" { *-*-* } { "-flto" } } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include "sat_arith.h" > + > +/* > +** sat_addu_uint64_t: > +** add\s+[atx][0-9]+,\s*a0,\s*a1 > +** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** neg\s+[atx][0-9]+,\s*[atx][0-9]+ > +** or\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+ > +** ret > +*/ > +DEF_SAT_ADDU(uint64_t) > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-run-1.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-run-1.c > new file mode 100644 > index 00000000000..b19515c39d1 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-run-1.c > @@ -0,0 +1,42 @@ > +/* { dg-do run { target { riscv_v } } } */ > +/* { dg-additional-options "-std=c99" } */ > + > +#include "sat_arith.h" > + > +DEF_SAT_ADDU(uint8_t) > + > +int > +main () > +{ > + if (RUN_SAT_ADDU (uint8_t, 0, 0) != 0) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 0, 1) != 1) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 1, 1) != 2) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 0, 254) != 254) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 1, 254) != 255) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 2, 254) != 255) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 0, 255) != 255) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 1, 255) != 255) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 2, 255) != 255) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint8_t, 255, 255) != 255) > + __builtin_abort (); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-run-2.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-run-2.c > new file mode 100644 > index 00000000000..90073fbe4ba > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-run-2.c > @@ -0,0 +1,42 @@ > +/* { dg-do run { target { riscv_v } } } */ > +/* { dg-additional-options "-std=c99" } */ > + > +#include "sat_arith.h" > + > +DEF_SAT_ADDU(uint16_t) > + > +int > +main () > +{ > + if (RUN_SAT_ADDU (uint16_t, 0, 0) != 0) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 0, 1) != 1) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 1, 1) != 2) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 0, 65534) != 65534) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 1, 65534) != 65535) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 2, 65534) != 65535) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 0, 65535) != 65535) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 1, 65535) != 65535) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 2, 65535) != 65535) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint16_t, 65535, 65535) != 65535) > + __builtin_abort (); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-run-3.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-run-3.c > new file mode 100644 > index 00000000000..996dd3de737 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-run-3.c > @@ -0,0 +1,42 @@ > +/* { dg-do run { target { riscv_v } } } */ > +/* { dg-additional-options "-std=c99" } */ > + > +#include "sat_arith.h" > + > +DEF_SAT_ADDU(uint32_t) > + > +int > +main () > +{ > + if (RUN_SAT_ADDU (uint32_t, 0, 0) != 0) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 0, 1) != 1) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 1, 1) != 2) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 0, 4294967294) != 4294967294) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 1, 4294967294) != 4294967295) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 2, 4294967294) != 4294967295) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 0, 4294967295) != 4294967295) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 1, 4294967295) != 4294967295) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 2, 4294967295) != 4294967295) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint32_t, 4294967295, 4294967295) != 4294967295) > + __builtin_abort (); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/riscv/sat_addu-run-4.c > b/gcc/testsuite/gcc.target/riscv/sat_addu-run-4.c > new file mode 100644 > index 00000000000..51a5421577b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_addu-run-4.c > @@ -0,0 +1,49 @@ > +/* { dg-do run { target { riscv_v } } } */ > +/* { dg-additional-options "-std=c99" } */ > + > +#include "sat_arith.h" > + > +DEF_SAT_ADDU(uint64_t) > + > +int > +main () > +{ > + if (RUN_SAT_ADDU (uint64_t, 0, 0) != 0) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 0, 1) != 1) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 1, 1) != 2) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 0, 18446744073709551614u) > + != 18446744073709551614u) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 1, 18446744073709551614u) > + != 18446744073709551615u) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 2, 18446744073709551614u) > + != 18446744073709551615u) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 0, 18446744073709551615u) > + != 18446744073709551615u) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 1, 18446744073709551615u) > + != 18446744073709551615u) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 2, 18446744073709551615u) > + != 18446744073709551615u) > + __builtin_abort (); > + > + if (RUN_SAT_ADDU (uint64_t, 18446744073709551615u, 18446744073709551615u) > + != 18446744073709551615u) > + __builtin_abort (); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/riscv/sat_arith.h > b/gcc/testsuite/gcc.target/riscv/sat_arith.h > new file mode 100644 > index 00000000000..4c00157685e > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/sat_arith.h > @@ -0,0 +1,15 @@ > +#ifndef HAVE_SAT_ARITH > +#define HAVE_SAT_ARITH > + > +#include <stdint.h> > + > +#define DEF_SAT_ADDU(TYPE) \ > +TYPE __attribute__((noinline)) \ > +sat_addu_##TYPE (TYPE x, TYPE y) \ > +{ \ > + return (x + y) | (-(TYPE)((TYPE)(x + y) < x)); \ > +} > + > +#define RUN_SAT_ADDU(TYPE, x, y) sat_addu_##TYPE(x, y) > + > +#endif > -- > 2.34.1 >