diff options
author | Pan Li <pan2.li@intel.com> | 2024-07-01 16:36:35 +0800 |
---|---|---|
committer | Pan Li <pan2.li@intel.com> | 2024-07-23 09:24:02 +0800 |
commit | 5d2115b850df63b0ecdf56efb720ad848e7afe21 (patch) | |
tree | 6f90005fa8599cae075cb5f9cea094791a764fa7 /gcc | |
parent | d1b25543f93c26a6f4b8dd366792bdd8fd9cf7a7 (diff) | |
download | gcc-5d2115b850df63b0ecdf56efb720ad848e7afe21.zip gcc-5d2115b850df63b0ecdf56efb720ad848e7afe21.tar.gz gcc-5d2115b850df63b0ecdf56efb720ad848e7afe21.tar.bz2 |
RISC-V: Implement the .SAT_TRUNC for scalar
This patch would like to implement the simple .SAT_TRUNC pattern
in the riscv backend. Aka:
Form 1:
#define DEF_SAT_U_TRUC_FMT_1(NT, WT) \
NT __attribute__((noinline)) \
sat_u_truc_##WT##_to_##NT##_fmt_1 (WT x) \
{ \
bool overflow = x > (WT)(NT)(-1); \
return ((NT)x) | (NT)-overflow; \
}
DEF_SAT_U_TRUC_FMT_1(uint32_t, uint64_t)
Before this patch:
__attribute__((noinline))
uint8_t sat_u_truc_uint16_t_to_uint8_t_fmt_1 (uint16_t x)
{
_Bool overflow;
unsigned char _1;
unsigned char _2;
unsigned char _3;
uint8_t _6;
;; basic block 2, loop depth 0
;; pred: ENTRY
overflow_5 = x_4(D) > 255;
_1 = (unsigned char) x_4(D);
_2 = (unsigned char) overflow_5;
_3 = -_2;
_6 = _1 | _3;
return _6;
;; succ: EXIT
}
After this patch:
__attribute__((noinline))
uint8_t sat_u_truc_uint16_t_to_uint8_t_fmt_1 (uint16_t x)
{
uint8_t _6;
;; basic block 2, loop depth 0
;; pred: ENTRY
_6 = .SAT_TRUNC (x_4(D)); [tail call]
return _6;
;; succ: EXIT
}
The below tests suites are passed for this patch
1. The rv64gcv fully regression test.
2. The rv64gcv build with glibc
gcc/ChangeLog:
* config/riscv/iterators.md (ANYI_DOUBLE_TRUNC): Add new iterator
for int double truncation.
(ANYI_DOUBLE_TRUNCATED): Add new attr for int double truncation.
(anyi_double_truncated): Ditto but for lowercase.
* config/riscv/riscv-protos.h (riscv_expand_ustrunc): Add new
func decl for expanding ustrunc
* config/riscv/riscv.cc (riscv_expand_ustrunc): Add new func
impl to expand ustrunc.
* config/riscv/riscv.md (ustrunc<mode><anyi_double_truncated>2): Impl
the new pattern ustrunc<m><n>2 for int.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/sat_arith.h: Add test helper macro.
* gcc.target/riscv/sat_arith_data.h: New test.
* gcc.target/riscv/sat_u_trunc-1.c: New test.
* gcc.target/riscv/sat_u_trunc-2.c: New test.
* gcc.target/riscv/sat_u_trunc-3.c: New test.
* gcc.target/riscv/sat_u_trunc-run-1.c: New test.
* gcc.target/riscv/sat_u_trunc-run-2.c: New test.
* gcc.target/riscv/sat_u_trunc-run-3.c: New test.
* gcc.target/riscv/scalar_sat_unary.h: New test.
Signed-off-by: Pan Li <pan2.li@intel.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/riscv/iterators.md | 10 | ||||
-rw-r--r-- | gcc/config/riscv/riscv-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.cc | 40 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.md | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_arith.h | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_arith_data.h | 56 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_u_trunc-1.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_u_trunc-2.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_u_trunc-3.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-1.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-2.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-3.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/scalar_sat_unary.h | 22 |
13 files changed, 259 insertions, 0 deletions
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index d61ed53..734da04 100644 --- a/gcc/config/riscv/iterators.md +++ b/gcc/config/riscv/iterators.md @@ -65,6 +65,16 @@ ;; Iterator for hardware-supported integer modes. (define_mode_iterator ANYI [QI HI SI (DI "TARGET_64BIT")]) +(define_mode_iterator ANYI_DOUBLE_TRUNC [HI SI (DI "TARGET_64BIT")]) + +(define_mode_attr ANYI_DOUBLE_TRUNCATED [ + (HI "QI") (SI "HI") (DI "SI") +]) + +(define_mode_attr anyi_double_truncated [ + (HI "qi") (SI "hi") (DI "si") +]) + ;; Iterator for hardware-supported floating-point modes. (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT || TARGET_ZFINX") (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX") diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 7c0ea1b..ce5e38d 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -135,6 +135,7 @@ 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_usadd (rtx, rtx, rtx); extern void riscv_expand_ussub (rtx, rtx, rtx); +extern void riscv_expand_ustrunc (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 19b9b2d..1696fa2 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -11636,6 +11636,46 @@ riscv_expand_ussub (rtx dest, rtx x, rtx y) emit_move_insn (dest, gen_lowpart (mode, pmode_dest)); } +/* Implement the unsigned saturation truncation for int mode. + + b = SAT_TRUNC (a); + => + 1. max = half truncated max + 2. lt = a < max + 3. lt = lt - 1 (lt 0, ge -1) + 4. d = a | lt + 5. b = (trunc)d */ + +void +riscv_expand_ustrunc (rtx dest, rtx src) +{ + machine_mode mode = GET_MODE (dest); + rtx xmode_max = gen_reg_rtx (Xmode); + unsigned precision = GET_MODE_PRECISION (mode).to_constant (); + + gcc_assert (precision < 64); + + uint64_t max = ((uint64_t)1u << precision) - 1u; + rtx xmode_src = gen_lowpart (Xmode, src); + rtx xmode_dest = gen_reg_rtx (Xmode); + rtx xmode_lt = gen_reg_rtx (Xmode); + + /* Step-1: max = half truncated max */ + emit_move_insn (xmode_max, gen_int_mode (max, Xmode)); + + /* Step-2: lt = src < max */ + riscv_emit_binary (LTU, xmode_lt, xmode_src, xmode_max); + + /* Step-3: lt = lt - 1 */ + riscv_emit_binary (PLUS, xmode_lt, xmode_lt, CONSTM1_RTX (Xmode)); + + /* Step-4: xmode_dest = lt | src */ + riscv_emit_binary (IOR, xmode_dest, xmode_lt, xmode_src); + + /* Step-5: dest = xmode_dest */ + emit_move_insn (dest, gen_lowpart (mode, xmode_dest)); +} + /* Implement TARGET_C_MODE_FOR_FLOATING_TYPE. Return TFmode for TI_LONG_DOUBLE_TYPE which is for long double type, go with the default one for the others. */ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 46c4603..d9f6c17 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -4315,6 +4315,16 @@ } ) +(define_expand "ustrunc<mode><anyi_double_truncated>2" + [(match_operand:<ANYI_DOUBLE_TRUNCATED> 0 "register_operand") + (match_operand:ANYI_DOUBLE_TRUNC 1 "register_operand")] + "" + { + riscv_expand_ustrunc (operands[0], operands[1]); + DONE; + } +) + ;; These are forms of (x << C1) + C2, potentially canonicalized from ;; ((x + C2') << C1. Depending on the cost to load C2 vs C2' we may ;; want to go ahead and recognize this form as C2 may be cheaper to diff --git a/gcc/testsuite/gcc.target/riscv/sat_arith.h b/gcc/testsuite/gcc.target/riscv/sat_arith.h index 75442c9..37e0a60 100644 --- a/gcc/testsuite/gcc.target/riscv/sat_arith.h +++ b/gcc/testsuite/gcc.target/riscv/sat_arith.h @@ -214,4 +214,20 @@ sat_u_sub_##T##_fmt_12 (T x, T y) \ #define RUN_SAT_U_SUB_FMT_11(T, x, y) sat_u_sub_##T##_fmt_11(x, y) #define RUN_SAT_U_SUB_FMT_12(T, x, y) sat_u_sub_##T##_fmt_12(x, y) +/******************************************************************************/ +/* Saturation Truncate (unsigned and signed) */ +/******************************************************************************/ + +#define DEF_SAT_U_TRUC_FMT_1(NT, WT) \ +NT __attribute__((noinline)) \ +sat_u_truc_##WT##_to_##NT##_fmt_1 (WT x) \ +{ \ + bool overflow = x > (WT)(NT)(-1); \ + return ((NT)x) | (NT)-overflow; \ +} +#define DEF_SAT_U_TRUC_FMT_1_WRAP(NT, WT) DEF_SAT_U_TRUC_FMT_1(NT, WT) + +#define RUN_SAT_U_TRUC_FMT_1(NT, WT, x) sat_u_truc_##WT##_to_##NT##_fmt_1 (x) +#define RUN_SAT_U_TRUC_FMT_1_WRAP(NT, WT, x) RUN_SAT_U_TRUC_FMT_1(NT, WT, x) + #endif diff --git a/gcc/testsuite/gcc.target/riscv/sat_arith_data.h b/gcc/testsuite/gcc.target/riscv/sat_arith_data.h new file mode 100644 index 0000000..b991f8a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_arith_data.h @@ -0,0 +1,56 @@ +#ifndef HAVE_DEFINED_SAT_ARITH_DATA_H +#define HAVE_DEFINED_SAT_ARITH_DATA_H + +#define TEST_UNARY_STRUCT_NAME(T1, T2) test_##T1##_##T2##_s +#define TEST_UNARY_STRUCT_DECL(T1, T2) struct TEST_UNARY_STRUCT_NAME(T1, T2) +#define TEST_UNARY_STRUCT(T1, T2) \ + struct TEST_UNARY_STRUCT_NAME(T1, T2) \ + { \ + T1 to; \ + T2 from; \ + }; + +#define TEST_UNARY_DATA(T1, T2) t_##T1##_##T2##_s +#define TEST_UNARY_DATA_WRAP(T1, T2) TEST_UNARY_DATA(T1, T2) + +TEST_UNARY_STRUCT (uint8_t, uint16_t) +TEST_UNARY_STRUCT (uint16_t, uint32_t) +TEST_UNARY_STRUCT (uint32_t, uint64_t) + +TEST_UNARY_STRUCT_DECL(uint8_t, uint16_t) \ + TEST_UNARY_DATA(uint8_t, uint16_t)[] = +{ + { 0, 0}, + { 2, 2}, + {254, 254}, + {255, 255}, + {255, 256}, + {255, 65534}, + {255, 65535}, +}; + +TEST_UNARY_STRUCT_DECL(uint16_t, uint32_t) \ + TEST_UNARY_DATA(uint16_t, uint32_t)[] = +{ + { 0, 0}, + { 5, 5}, + {65534, 65534}, + {65535, 65535}, + {65535, 65536}, + {65535, 4294967294}, + {65535, 4294967295}, +}; + +TEST_UNARY_STRUCT_DECL(uint32_t, uint64_t) \ + TEST_UNARY_DATA(uint32_t, uint64_t)[] = +{ + { 0, 0}, + { 9, 9}, + {4294967294, 4294967294}, + {4294967295, 4294967295}, + {4294967295, 4294967296}, + {4294967295, 18446744073709551614u}, + {4294967295, 18446744073709551615u}, +}; + +#endif diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_trunc-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-1.c new file mode 100644 index 0000000..3548310 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "sat_arith.h" + +/* +** sat_u_truc_uint16_t_to_uint8_t_fmt_1: +** sltiu\s+[atx][0-9]+,\s*a0,\s*255 +** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1 +** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ +** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff +** ret +*/ +DEF_SAT_U_TRUC_FMT_1(uint8_t, uint16_t) + +/* { dg-final { scan-rtl-dump-times ".SAT_TRUNC " 2 "expand" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_trunc-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-2.c new file mode 100644 index 0000000..0001d8a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "sat_arith.h" + +/* +** sat_u_truc_uint32_t_to_uint16_t_fmt_1: +** li\s+[atx][0-9]+,\s*65536 +** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1 +** sltu\s+[atx][0-9]+,\s*a0,\s*[atx][0-9]+ +** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1 +** 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_U_TRUC_FMT_1(uint16_t, uint32_t) + +/* { dg-final { scan-rtl-dump-times ".SAT_TRUNC " 2 "expand" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_trunc-3.c b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-3.c new file mode 100644 index 0000000..4359935 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-3.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "sat_arith.h" + +/* +** sat_u_truc_uint64_t_to_uint32_t_fmt_1: +** li\s+[atx][0-9]+,\s*-1 +** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*32 +** sltu\s+[atx][0-9]+,\s*a0,\s*[atx][0-9]+ +** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1 +** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+ +** sext.w\s+a0,\s*a0 +** ret +*/ +DEF_SAT_U_TRUC_FMT_1(uint32_t, uint64_t) + +/* { dg-final { scan-rtl-dump-times ".SAT_TRUNC " 2 "expand" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-1.c new file mode 100644 index 0000000..39a5ce2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-1.c @@ -0,0 +1,16 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99" } */ + +#include "sat_arith.h" +#include "sat_arith_data.h" + +#define T1 uint8_t +#define T2 uint16_t + +DEF_SAT_U_TRUC_FMT_1_WRAP(T1, T2) + +#define DATA TEST_UNARY_DATA_WRAP(T1, T2) +#define T TEST_UNARY_STRUCT_DECL(T1, T2) +#define RUN_UNARY(x) RUN_SAT_U_TRUC_FMT_1_WRAP(T1, T2, x) + +#include "scalar_sat_unary.h" diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-2.c new file mode 100644 index 0000000..b98114a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-2.c @@ -0,0 +1,16 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99" } */ + +#include "sat_arith.h" +#include "sat_arith_data.h" + +#define T1 uint16_t +#define T2 uint32_t + +DEF_SAT_U_TRUC_FMT_1_WRAP(T1, T2) + +#define DATA TEST_UNARY_DATA_WRAP(T1, T2) +#define T TEST_UNARY_STRUCT_DECL(T1, T2) +#define RUN_UNARY(x) RUN_SAT_U_TRUC_FMT_1_WRAP(T1, T2, x) + +#include "scalar_sat_unary.h" diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-3.c b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-3.c new file mode 100644 index 0000000..8a92a8c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sat_u_trunc-run-3.c @@ -0,0 +1,16 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99" } */ + +#include "sat_arith.h" +#include "sat_arith_data.h" + +#define T1 uint32_t +#define T2 uint64_t + +DEF_SAT_U_TRUC_FMT_1_WRAP(T1, T2) + +#define DATA TEST_UNARY_DATA_WRAP(T1, T2) +#define T TEST_UNARY_STRUCT_DECL(T1, T2) +#define RUN_UNARY(x) RUN_SAT_U_TRUC_FMT_1_WRAP(T1, T2, x) + +#include "scalar_sat_unary.h" diff --git a/gcc/testsuite/gcc.target/riscv/scalar_sat_unary.h b/gcc/testsuite/gcc.target/riscv/scalar_sat_unary.h new file mode 100644 index 0000000..2ae0587 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/scalar_sat_unary.h @@ -0,0 +1,22 @@ +#ifndef HAVE_DEFINED_SCALAR_SAT_UNARY +#define HAVE_DEFINED_SCALAR_SAT_UNARY + +int +main () +{ + unsigned i; + T d; + + for (i = 0; i < sizeof (DATA) / sizeof (DATA[0]); i++) + { + d = DATA[i]; + + if (RUN_UNARY (d.from) != d.to) + __builtin_abort (); + } + + return 0; +} + +#endif + |