On 23 May 2016 at 14:28, Prathamesh Kulkarni <prathamesh.kulka...@linaro.org> wrote: > Hi, > This patch overrides expand_divmod_libfunc for ARM port and adds test-cases. > I separated the SImode tests into separate file from DImode tests > because certain arm configs (cortex-15) have hardware div insn for > SImode but not for DImode, > and for that config we want SImode tests to be disabled but not DImode tests. > The patch therefore has two target-effective checks: divmod and divmod_simode. > Cross-tested on arm*-*-*. > Bootstrap+test on arm-linux-gnueabihf in progress. > Does this patch look OK ? Hi, This version adds couple of more test-cases and fixes typo in divmod-3-simode.c, divmod-4-simode.c
Thanks, Prathamesh > > Thanks, > Prathamesh
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 12060ba..1310006 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -61,6 +61,7 @@ #include "builtins.h" #include "tm-constrs.h" #include "rtl-iter.h" +#include "optabs-libfuncs.h" /* This file should be included last. */ #include "target-def.h" @@ -300,6 +301,7 @@ static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void); static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*); static bool arm_can_output_mi_thunk (const_tree, HOST_WIDE_INT, HOST_WIDE_INT, const_tree); +static void arm_expand_divmod_libfunc (bool, machine_mode, rtx, rtx, rtx *, rtx *); /* Table of machine attributes. */ @@ -730,6 +732,9 @@ static const struct attribute_spec arm_attribute_table[] = #undef TARGET_SCHED_FUSION_PRIORITY #define TARGET_SCHED_FUSION_PRIORITY arm_sched_fusion_priority +#undef TARGET_EXPAND_DIVMOD_LIBFUNC +#define TARGET_EXPAND_DIVMOD_LIBFUNC arm_expand_divmod_libfunc + struct gcc_target targetm = TARGET_INITIALIZER; /* Obstack for minipool constant handling. */ @@ -30354,6 +30359,37 @@ arm_sched_fusion_priority (rtx_insn *insn, int max_pri, return; } +/* Expand call to __aeabi_[mode]divmod (op0, op1). */ + +static void +arm_expand_divmod_libfunc (bool unsignedp, machine_mode mode, + rtx op0, rtx op1, + rtx *quot_p, rtx *rem_p) +{ + if (mode == SImode) + gcc_assert (!TARGET_IDIV); + + optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab; + rtx libfunc = optab_libfunc (tab, mode); + gcc_assert (libfunc); + + machine_mode libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode), + MODE_INT); + + rtx libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST, + libval_mode, 2, + op0, GET_MODE (op0), + op1, GET_MODE (op1)); + + rtx quotient = simplify_gen_subreg (mode, libval, libval_mode, 0); + rtx remainder = simplify_gen_subreg (mode, libval, libval_mode, GET_MODE_SIZE (mode)); + + gcc_assert (quotient); + gcc_assert (remainder); + + *quot_p = quotient; + *rem_p = remainder; +} /* Construct and return a PARALLEL RTX vector with elements numbering the lanes of either the high (HIGH == TRUE) or low (HIGH == FALSE) half of diff --git a/gcc/testsuite/gcc.dg/divmod-1-simode.c b/gcc/testsuite/gcc.dg/divmod-1-simode.c new file mode 100644 index 0000000..7405f66 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-1-simode.c @@ -0,0 +1,22 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* div dominates mod. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype q = x / y; \ + if (cond) \ + foo (); \ + bigtype r = x % y; \ + return q + r; \ +} + +FOO(int, int, 1) +FOO(int, unsigned, 2) +FOO(unsigned, unsigned, 5) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-1.c b/gcc/testsuite/gcc.dg/divmod-1.c new file mode 100644 index 0000000..40aec74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-1.c @@ -0,0 +1,26 @@ +/* { dg-require-effective-target divmod } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* div dominates mod. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype q = x / y; \ + if (cond) \ + foo (); \ + bigtype r = x % y; \ + return q + r; \ +} + +FOO(int, long long, 3) +FOO(int, unsigned long long, 4) +FOO(unsigned, long long, 6) +FOO(unsigned, unsigned long long, 7) +FOO(long long, long long, 8) +FOO(long long, unsigned long long, 9) +FOO(unsigned long long, unsigned long long, 10) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-2-simode.c b/gcc/testsuite/gcc.dg/divmod-2-simode.c new file mode 100644 index 0000000..7c8313b --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-2-simode.c @@ -0,0 +1,22 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* mod dominates div. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype r = x % y; \ + if (cond) \ + foo (); \ + bigtype q = x / y; \ + return q + r; \ +} + +FOO(int, int, 1) +FOO(int, unsigned, 2) +FOO(unsigned, unsigned, 5) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-2.c b/gcc/testsuite/gcc.dg/divmod-2.c new file mode 100644 index 0000000..6a2216c --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-2.c @@ -0,0 +1,26 @@ +/* { dg-require-effective-target divmod } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* mod dominates div. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype r = x % y; \ + if (cond) \ + foo (); \ + bigtype q = x / y; \ + return q + r; \ +} + +FOO(int, long long, 3) +FOO(int, unsigned long long, 4) +FOO(unsigned, long long, 6) +FOO(unsigned, unsigned long long, 7) +FOO(long long, long long, 8) +FOO(long long, unsigned long long, 9) +FOO(unsigned long long, unsigned long long, 10) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-3-simode.c b/gcc/testsuite/gcc.dg/divmod-3-simode.c new file mode 100644 index 0000000..6f0f63d --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-3-simode.c @@ -0,0 +1,20 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* div comes before mod in same bb. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype q = x / y; \ + bigtype r = x % y; \ + return q + r; \ +} + +FOO(int, int, 1) +FOO(int, unsigned, 2) +FOO(unsigned, unsigned, 5) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-3.c b/gcc/testsuite/gcc.dg/divmod-3.c new file mode 100644 index 0000000..9fe6f64 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-3.c @@ -0,0 +1,24 @@ +/* { dg-require-effective-target divmod } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* div comes before mod in same bb. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype q = x / y; \ + bigtype r = x % y; \ + return q + r; \ +} + +FOO(int, long long, 3) +FOO(int, unsigned long long, 4) +FOO(unsigned, long long, 6) +FOO(unsigned, unsigned long long, 7) +FOO(long long, long long, 8) +FOO(long long, unsigned long long, 9) +FOO(unsigned long long, unsigned long long, 10) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-4-simode.c b/gcc/testsuite/gcc.dg/divmod-4-simode.c new file mode 100644 index 0000000..9c326f2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-4-simode.c @@ -0,0 +1,20 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* mod comes before div in same bb. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype r = x % y; \ + bigtype q = x / y; \ + return q + r; \ +} + +FOO(int, int, 1) +FOO(int, unsigned, 2) +FOO(unsigned, unsigned, 5) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-4.c b/gcc/testsuite/gcc.dg/divmod-4.c new file mode 100644 index 0000000..a5686cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-4.c @@ -0,0 +1,24 @@ +/* { dg-require-effective-target divmod } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* mod comes before div in same bb. */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype r = x % y; \ + bigtype q = x / y; \ + return q + r; \ +} + +FOO(int, long long, 3) +FOO(int, unsigned long long, 4) +FOO(unsigned, long long, 6) +FOO(unsigned, unsigned long long, 7) +FOO(long long, long long, 8) +FOO(long long, unsigned long long, 9) +FOO(unsigned long long, unsigned long long, 10) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-5.c b/gcc/testsuite/gcc.dg/divmod-5.c new file mode 100644 index 0000000..8a8cee5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-5.c @@ -0,0 +1,19 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ +/* div and mod are not in same bb and + bb's containing div and mod don't dominate each other. */ + +int f(int x, int y) +{ + int q = 0; + int r = 0; + extern int cond; + + if (cond) + q = x / y; + + r = x % y; + return q + r; +} + +/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-6-simode.c b/gcc/testsuite/gcc.dg/divmod-6-simode.c new file mode 100644 index 0000000..3bf6fa3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-6-simode.c @@ -0,0 +1,24 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ + + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype q = x / y; \ + bigtype r1 = 0, r2 = 0; \ + if (cond) \ + r1 = x % y; \ + else \ + r2 = x % y; \ + return q + r1 + r2; \ +} + +FOO(int, int, 1) +FOO(int, unsigned, 2) +FOO(unsigned, unsigned, 5) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-6.c b/gcc/testsuite/gcc.dg/divmod-6.c new file mode 100644 index 0000000..70e4321 --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-6.c @@ -0,0 +1,27 @@ +/* { dg-require-effective-target divmod } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ + +extern int cond; +void foo(void); + +#define FOO(smalltype, bigtype, no) \ +bigtype f_##no(smalltype x, bigtype y) \ +{ \ + bigtype q = x / y; \ + bigtype r1 = 0, r2 = 0; \ + if (cond) \ + r1 = x % y; \ + else \ + r2 = x % y; \ + return q + r1 + r2; \ +} + +FOO(int, long long, 3) +FOO(int, unsigned long long, 4) +FOO(unsigned, long long, 6) +FOO(unsigned, unsigned long long, 7) +FOO(long long, long long, 8) +FOO(long long, unsigned long long, 9) +FOO(unsigned long long, unsigned long long, 10) + +/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */ diff --git a/gcc/testsuite/gcc.dg/divmod-7.c b/gcc/testsuite/gcc.dg/divmod-7.c new file mode 100644 index 0000000..a6e7fcd --- /dev/null +++ b/gcc/testsuite/gcc.dg/divmod-7.c @@ -0,0 +1,21 @@ +/* { dg-require-effective-target divmod_simode } */ +/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */ + +int f(int x, int y) +{ + int q = 0, r1 = 0, r2 = 0; + extern int cond; + + if (cond) + q = x / y; + else + { + r1 = x % y; + return q + r1; + } + + r2 = x % y; + return q + r2; +} + +/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 04ca176..ad7c487 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6986,3 +6986,32 @@ proc check_effective_target_offload_hsa { } { int main () {return 0;} } "-foffload=hsa" ] } + +# For ARM configs defining __ARM_ARCH_EXT_IDIV__, disable divmod_simode test-cases. + +proc check_effective_target_arm_divmod_simode { } { + return [check_no_compiler_messages arm_divmod assembly { + #ifdef __ARM_ARCH_EXT_IDIV__ + #error has div insn + #endif + int i; + }] +} + +proc check_effective_target_divmod { } { + #TODO: Add checks for all targets that have either hardware divmod insn + # or define libfunc for divmod. + if { [istarget arm*-*-*] + || [istarget x86_64-*-*] } { + return 1 + } + return 0 +} + +proc check_effective_target_divmod_simode { } { + if { [istarget arm*-*-*] } { + return [check_effective_target_arm_divmod_simode] + } + + return [check_effective_target_divmod] +}
ChangeLog-part2
Description: Binary data