From 2cca9751700946f1398fc3bcb96d529bb2964f0f Mon Sep 17 00:00:00 2001 From: Matthew Malcomson Date: Tue, 10 Nov 2020 17:14:47 +0000 Subject: opts: Change `is incompatible with` messages to have standard parametrised form Hello, In a recent review for one of the hwasan patches Richard S. noticed there are quite a few errors of the form "% is incompatible with ". https://gcc.gnu.org/pipermail/gcc-patches/2020-October/556137.html In order to avoid this creating extra work for translators we would like to change these error messages to use the form "%qs is incompatible with %qs" and pass the flag as format arguments. This patch implements that change. There is only one change in the output the compiler produces from this patch, an error message of "-fsanitize=address and -fsanitize=kernel-address are incompatible with -fsanitize=thread" has been changed to "-fsanitize=thread is incompatible with -fsanitize=address|kernel-address". This matches the similar error messages for live patching which use the messages "-f is incompatible with -flive-patching=inline-only-static|inline-clone". Ok for trunk? gcc/ChangeLog: * opts.c (control_options_for_live_patching): Reform 'is incompatible with' error messages to use a standard message with differing format arguments. (finish_options): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/ubsan/sanitize-recover-7.c: Update testcase. --- gcc/opts.c | 106 ++++++++++----------- .../c-c++-common/ubsan/sanitize-recover-7.c | 2 +- 2 files changed, 51 insertions(+), 57 deletions(-) (limited to 'gcc') diff --git a/gcc/opts.c b/gcc/opts.c index 96291e8..ac9972d 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -688,30 +688,26 @@ control_options_for_live_patching (struct gcc_options *opts, { case LIVE_PATCHING_INLINE_ONLY_STATIC: if (opts_set->x_flag_ipa_cp_clone && opts->x_flag_ipa_cp_clone) - error_at (loc, - "%<-fipa-cp-clone%> is incompatible with " - "%<-flive-patching=inline-only-static%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-cp-clone", "-flive-patching=inline-only-static"); else opts->x_flag_ipa_cp_clone = 0; if (opts_set->x_flag_ipa_sra && opts->x_flag_ipa_sra) - error_at (loc, - "%<-fipa-sra%> is incompatible with " - "%<-flive-patching=inline-only-static%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-sra", "-flive-patching=inline-only-static"); else opts->x_flag_ipa_sra = 0; if (opts_set->x_flag_partial_inlining && opts->x_flag_partial_inlining) - error_at (loc, - "%<-fpartial-inlining%> is incompatible with " - "%<-flive-patching=inline-only-static%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fpartial-inlining", "-flive-patching=inline-only-static"); else opts->x_flag_partial_inlining = 0; if (opts_set->x_flag_ipa_cp && opts->x_flag_ipa_cp) - error_at (loc, - "%<-fipa-cp%> is incompatible with " - "%<-flive-patching=inline-only-static%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-cp", "-flive-patching=inline-only-static"); else opts->x_flag_ipa_cp = 0; @@ -719,9 +715,9 @@ control_options_for_live_patching (struct gcc_options *opts, case LIVE_PATCHING_INLINE_CLONE: /* live patching should disable whole-program optimization. */ if (opts_set->x_flag_whole_program && opts->x_flag_whole_program) - error_at (loc, - "%<-fwhole-program%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fwhole-program", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_whole_program = 0; @@ -730,65 +726,65 @@ control_options_for_live_patching (struct gcc_options *opts, && !flag_partial_inlining. */ if (opts_set->x_flag_ipa_pta && opts->x_flag_ipa_pta) - error_at (loc, - "%<-fipa-pta%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-pta", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_pta = 0; if (opts_set->x_flag_ipa_reference && opts->x_flag_ipa_reference) - error_at (loc, - "%<-fipa-reference%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-reference", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_reference = 0; if (opts_set->x_flag_ipa_ra && opts->x_flag_ipa_ra) - error_at (loc, - "%<-fipa-ra%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-ra", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_ra = 0; if (opts_set->x_flag_ipa_icf && opts->x_flag_ipa_icf) - error_at (loc, - "%<-fipa-icf%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-icf", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_icf = 0; if (opts_set->x_flag_ipa_icf_functions && opts->x_flag_ipa_icf_functions) - error_at (loc, - "%<-fipa-icf-functions%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-icf-functions", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_icf_functions = 0; if (opts_set->x_flag_ipa_icf_variables && opts->x_flag_ipa_icf_variables) - error_at (loc, - "%<-fipa-icf-variables%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-icf-variables", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_icf_variables = 0; if (opts_set->x_flag_ipa_bit_cp && opts->x_flag_ipa_bit_cp) - error_at (loc, - "%<-fipa-bit-cp%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-bit-cp", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_bit_cp = 0; if (opts_set->x_flag_ipa_vrp && opts->x_flag_ipa_vrp) - error_at (loc, - "%<-fipa-vrp%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-vrp", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_vrp = 0; if (opts_set->x_flag_ipa_pure_const && opts->x_flag_ipa_pure_const) - error_at (loc, - "%<-fipa-pure-const%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-pure-const", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_pure_const = 0; @@ -804,18 +800,18 @@ control_options_for_live_patching (struct gcc_options *opts, /* discovery of functions/variables with no address taken. */ if (opts_set->x_flag_ipa_reference_addressable && opts->x_flag_ipa_reference_addressable) - error_at (loc, - "%<-fipa-reference-addressable%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-reference-addressable", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_reference_addressable = 0; /* ipa stack alignment propagation. */ if (opts_set->x_flag_ipa_stack_alignment && opts->x_flag_ipa_stack_alignment) - error_at (loc, - "%<-fipa-stack-alignment%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fipa-stack-alignment", + "-flive-patching=inline-only-static|inline-clone"); else opts->x_flag_ipa_stack_alignment = 0; break; @@ -1081,21 +1077,19 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, /* Userspace and kernel ASan conflict with each other. */ if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS) && (opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS)) - error_at (loc, - "%<-fsanitize=address%> is incompatible with " - "%<-fsanitize=kernel-address%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fsanitize=address", "-fsanitize=kernel-address"); /* And with TSan. */ if ((opts->x_flag_sanitize & SANITIZE_ADDRESS) && (opts->x_flag_sanitize & SANITIZE_THREAD)) - error_at (loc, - "%<-fsanitize=address%> and %<-fsanitize=kernel-address%> " - "are incompatible with %<-fsanitize=thread%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fsanitize=thread", "-fsanitize=address|kernel-address"); if ((opts->x_flag_sanitize & SANITIZE_LEAK) && (opts->x_flag_sanitize & SANITIZE_THREAD)) - error_at (loc, - "%<-fsanitize=leak%> is incompatible with %<-fsanitize=thread%>"); + error_at (loc, "%qs is incompatible with %qs", + "-fsanitize=leak", "-fsanitize=thread"); /* Check error recovery for -fsanitize-recover option. */ for (int i = 0; sanitizer_opts[i].name != NULL; ++i) diff --git a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-7.c b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-7.c index a571f2b..f325a74 100644 --- a/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-7.c +++ b/gcc/testsuite/c-c++-common/ubsan/sanitize-recover-7.c @@ -3,4 +3,4 @@ int i; -/* { dg-error ".-fsanitize=address. and .-fsanitize=kernel-address. are incompatible with .-fsanitize=thread." "" { target *-*-* } 0 } */ +/* { dg-error ".-fsanitize=thread. is incompatible with .-fsanitize=address|kernel-address." "" { target *-*-* } 0 } */ -- cgit v1.1 From e929ef532ad52cde873dfc0849907b020ffc5afd Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 10 Nov 2020 18:28:18 +0100 Subject: Fortran: OpenMP 5.0 (in_,task_)reduction clause extensions gcc/fortran/ChangeLog: * dump-parse-tree.c (show_omp_clauses): Handle new reduction enums. * gfortran.h (OMP_LIST_REDUCTION_INSCAN, OMP_LIST_REDUCTION_TASK, OMP_LIST_IN_REDUCTION, OMP_LIST_TASK_REDUCTION): Add enums. * openmp.c (enum omp_mask1): Add OMP_CLAUSE_IN_REDUCTION and OMP_CLAUSE_TASK_REDUCTION. (gfc_match_omp_clause_reduction): Extend reduction handling; moved from ... (gfc_match_omp_clauses): ... here. Add calls to it. (OMP_TASK_CLAUSES, OMP_TARGET_CLAUSES, OMP_TASKLOOP_CLAUSES): Add OMP_CLAUSE_IN_REDUCTION. (gfc_match_omp_taskgroup): Add task_reduction matching. (resolve_omp_clauses): Update for new reduction clause changes; remove removed nonmonotonic-schedule restrictions. (gfc_resolve_omp_parallel_blocks): Add new enums to switch. * trans-openmp.c (gfc_omp_clause_default_ctor, gfc_trans_omp_reduction_list, gfc_trans_omp_clauses, gfc_split_omp_clauses): Handle updated reduction clause. gcc/ChangeLog: * gimplify.c (gimplify_scan_omp_clauses, gimplify_omp_loop): Use 'do' instead of 'for' in error messages for Fortran. * omp-low.c (check_omp_nesting_restrictions): Likewise gcc/testsuite/ChangeLog: * gfortran.dg/gomp/schedule-modifiers-2.f90: Remove some dg-error. * gfortran.dg/gomp/reduction4.f90: New test. * gfortran.dg/gomp/reduction5.f90: New test. * gfortran.dg/gomp/workshare-reduction-1.f90: New test. * gfortran.dg/gomp/workshare-reduction-2.f90: New test. * gfortran.dg/gomp/workshare-reduction-3.f90: New test. * gfortran.dg/gomp/workshare-reduction-4.f90: New test. * gfortran.dg/gomp/workshare-reduction-5.f90: New test. * gfortran.dg/gomp/workshare-reduction-6.f90: New test. * gfortran.dg/gomp/workshare-reduction-7.f90: New test. * gfortran.dg/gomp/workshare-reduction-8.f90: New test. * gfortran.dg/gomp/workshare-reduction-9.f90: New test. * gfortran.dg/gomp/workshare-reduction-10.f90: New test. * gfortran.dg/gomp/workshare-reduction-11.f90: New test. * gfortran.dg/gomp/workshare-reduction-12.f90: New test. * gfortran.dg/gomp/workshare-reduction-13.f90: New test. * gfortran.dg/gomp/workshare-reduction-14.f90: New test. * gfortran.dg/gomp/workshare-reduction-15.f90: New test. * gfortran.dg/gomp/workshare-reduction-16.f90: New test. * gfortran.dg/gomp/workshare-reduction-17.f90: New test. * gfortran.dg/gomp/workshare-reduction-18.f90: New test. * gfortran.dg/gomp/workshare-reduction-19.f90: New test. * gfortran.dg/gomp/workshare-reduction-20.f90: New test. * gfortran.dg/gomp/workshare-reduction-21.f90: New test. * gfortran.dg/gomp/workshare-reduction-22.f90: New test. * gfortran.dg/gomp/workshare-reduction-23.f90: New test. * gfortran.dg/gomp/workshare-reduction-24.f90: New test. * gfortran.dg/gomp/workshare-reduction-25.f90: New test. * gfortran.dg/gomp/workshare-reduction-26.f90: New test. * gfortran.dg/gomp/workshare-reduction-27.f90: New test. * gfortran.dg/gomp/workshare-reduction-28.f90: New test. * gfortran.dg/gomp/workshare-reduction-29.f90: New test. * gfortran.dg/gomp/workshare-reduction-30.f90: New test. * gfortran.dg/gomp/workshare-reduction-31.f90: New test. * gfortran.dg/gomp/workshare-reduction-32.f90: New test. * gfortran.dg/gomp/workshare-reduction-33.f90: New test. * gfortran.dg/gomp/workshare-reduction-34.f90: New test. * gfortran.dg/gomp/workshare-reduction-35.f90: New test. * gfortran.dg/gomp/workshare-reduction-36.f90: New test. * gfortran.dg/gomp/workshare-reduction-37.f90: New test. * gfortran.dg/gomp/workshare-reduction-38.f90: New test. * gfortran.dg/gomp/workshare-reduction-39.f90: New test. * gfortran.dg/gomp/workshare-reduction-40.f90: New test. * gfortran.dg/gomp/workshare-reduction-41.f90: New test. * gfortran.dg/gomp/workshare-reduction-42.f90: New test. * gfortran.dg/gomp/workshare-reduction-43.f90: New test. * gfortran.dg/gomp/workshare-reduction-44.f90: New test. * gfortran.dg/gomp/workshare-reduction-45.f90: New test. * gfortran.dg/gomp/workshare-reduction-46.f90: New test. * gfortran.dg/gomp/workshare-reduction-47.f90: New test. * gfortran.dg/gomp/workshare-reduction-48.f90: New test. * gfortran.dg/gomp/workshare-reduction-49.f90: New test. * gfortran.dg/gomp/workshare-reduction-50.f90: New test. * gfortran.dg/gomp/workshare-reduction-51.f90: New test. * gfortran.dg/gomp/workshare-reduction-52.f90: New test. * gfortran.dg/gomp/workshare-reduction-53.f90: New test. * gfortran.dg/gomp/workshare-reduction-54.f90: New test. * gfortran.dg/gomp/workshare-reduction-55.f90: New test. * gfortran.dg/gomp/workshare-reduction-56.f90: New test. * gfortran.dg/gomp/workshare-reduction-57.f90: New test. * gfortran.dg/gomp/workshare-reduction-58.f90: New test. --- gcc/fortran/dump-parse-tree.c | 10 +- gcc/fortran/gfortran.h | 4 + gcc/fortran/openmp.c | 377 +++++++++++++-------- gcc/fortran/trans-openmp.c | 71 +++- gcc/gimplify.c | 6 +- gcc/omp-low.c | 3 +- gcc/testsuite/gfortran.dg/gomp/reduction4.f90 | 171 ++++++++++ gcc/testsuite/gfortran.dg/gomp/reduction5.f90 | 41 +++ .../gfortran.dg/gomp/schedule-modifiers-2.f90 | 8 +- .../gfortran.dg/gomp/workshare-reduction-1.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-10.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-11.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-12.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-13.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-14.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-15.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-16.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-17.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-18.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-19.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-2.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-20.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-21.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-22.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-23.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-24.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-25.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-26.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-27.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-28.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-29.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-3.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-30.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-31.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-32.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-33.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-34.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-35.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-36.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-37.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-38.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-39.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-4.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-40.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-41.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-42.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-43.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-44.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-45.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-46.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-47.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-48.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-49.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-5.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-50.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-51.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-52.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-53.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-54.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-55.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-56.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-57.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-58.f90 | 35 ++ .../gfortran.dg/gomp/workshare-reduction-6.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-7.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-8.f90 | 31 ++ .../gfortran.dg/gomp/workshare-reduction-9.f90 | 31 ++ 67 files changed, 2349 insertions(+), 172 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/reduction4.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/reduction5.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90 (limited to 'gcc') diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 43b97ba..cab0fb2 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1587,7 +1587,11 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) case OMP_LIST_MAP: type = "MAP"; break; case OMP_LIST_TO: type = "TO"; break; case OMP_LIST_FROM: type = "FROM"; break; - case OMP_LIST_REDUCTION: type = "REDUCTION"; break; + case OMP_LIST_REDUCTION: + case OMP_LIST_REDUCTION_INSCAN: + case OMP_LIST_REDUCTION_TASK: type = "REDUCTION"; break; + case OMP_LIST_IN_REDUCTION: type = "IN_REDUCTION"; break; + case OMP_LIST_TASK_REDUCTION: type = "TASK_REDUCTION"; break; case OMP_LIST_DEVICE_RESIDENT: type = "DEVICE_RESIDENT"; break; case OMP_LIST_LINK: type = "LINK"; break; case OMP_LIST_USE_DEVICE: type = "USE_DEVICE"; break; @@ -1600,6 +1604,10 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) gcc_unreachable (); } fprintf (dumpfile, " %s(", type); + if (list_type == OMP_LIST_REDUCTION_INSCAN) + fputs ("inscan, ", dumpfile); + if (list_type == OMP_LIST_REDUCTION_TASK) + fputs ("task, ", dumpfile); show_omp_namelist (list_type, omp_clauses->lists[list_type]); fputc (')', dumpfile); } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index dfd7796..6467985 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1278,6 +1278,10 @@ enum OMP_LIST_TO, OMP_LIST_FROM, OMP_LIST_REDUCTION, + OMP_LIST_REDUCTION_INSCAN, + OMP_LIST_REDUCTION_TASK, + OMP_LIST_IN_REDUCTION, + OMP_LIST_TASK_REDUCTION, OMP_LIST_DEVICE_RESIDENT, OMP_LIST_LINK, OMP_LIST_USE_DEVICE, diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 2270c85..68d0b65 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -762,6 +762,8 @@ enum omp_mask1 OMP_CLAUSE_SHARED, OMP_CLAUSE_COPYIN, OMP_CLAUSE_REDUCTION, + OMP_CLAUSE_IN_REDUCTION, + OMP_CLAUSE_TASK_REDUCTION, OMP_CLAUSE_IF, OMP_CLAUSE_NUM_THREADS, OMP_CLAUSE_SCHEDULE, @@ -959,6 +961,163 @@ gfc_match_omp_map_clause (gfc_omp_namelist **list, gfc_omp_map_op map_op, return false; } +/* reduction ( reduction-modifier, reduction-operator : variable-list ) + in_reduction ( reduction-operator : variable-list ) + task_reduction ( reduction-operator : variable-list ) */ + +static match +gfc_match_omp_clause_reduction (char pc, gfc_omp_clauses *c, bool openacc, + bool allow_derived) +{ + if (pc == 'r' && gfc_match ("reduction ( ") != MATCH_YES) + return MATCH_NO; + else if (pc == 'i' && gfc_match ("in_reduction ( ") != MATCH_YES) + return MATCH_NO; + else if (pc == 't' && gfc_match ("task_reduction ( ") != MATCH_YES) + return MATCH_NO; + + locus old_loc = gfc_current_locus; + int list_idx = 0; + + if (pc == 'r' && !openacc) + { + if (gfc_match ("inscan") == MATCH_YES) + list_idx = OMP_LIST_REDUCTION_INSCAN; + else if (gfc_match ("task") == MATCH_YES) + list_idx = OMP_LIST_REDUCTION_TASK; + else if (gfc_match ("default") == MATCH_YES) + list_idx = OMP_LIST_REDUCTION; + if (list_idx != 0 && gfc_match (", ") != MATCH_YES) + { + gfc_error ("Comma expected at %C"); + gfc_current_locus = old_loc; + return MATCH_NO; + } + if (list_idx == 0) + list_idx = OMP_LIST_REDUCTION; + } + else if (pc == 'i') + list_idx = OMP_LIST_IN_REDUCTION; + else if (pc == 't') + list_idx = OMP_LIST_TASK_REDUCTION; + else + list_idx = OMP_LIST_REDUCTION; + + gfc_omp_reduction_op rop = OMP_REDUCTION_NONE; + char buffer[GFC_MAX_SYMBOL_LEN + 3]; + if (gfc_match_char ('+') == MATCH_YES) + rop = OMP_REDUCTION_PLUS; + else if (gfc_match_char ('*') == MATCH_YES) + rop = OMP_REDUCTION_TIMES; + else if (gfc_match_char ('-') == MATCH_YES) + rop = OMP_REDUCTION_MINUS; + else if (gfc_match (".and.") == MATCH_YES) + rop = OMP_REDUCTION_AND; + else if (gfc_match (".or.") == MATCH_YES) + rop = OMP_REDUCTION_OR; + else if (gfc_match (".eqv.") == MATCH_YES) + rop = OMP_REDUCTION_EQV; + else if (gfc_match (".neqv.") == MATCH_YES) + rop = OMP_REDUCTION_NEQV; + if (rop != OMP_REDUCTION_NONE) + snprintf (buffer, sizeof buffer, "operator %s", + gfc_op2string ((gfc_intrinsic_op) rop)); + else if (gfc_match_defined_op_name (buffer + 1, 1) == MATCH_YES) + { + buffer[0] = '.'; + strcat (buffer, "."); + } + else if (gfc_match_name (buffer) == MATCH_YES) + { + gfc_symbol *sym; + const char *n = buffer; + + gfc_find_symbol (buffer, NULL, 1, &sym); + if (sym != NULL) + { + if (sym->attr.intrinsic) + n = sym->name; + else if ((sym->attr.flavor != FL_UNKNOWN + && sym->attr.flavor != FL_PROCEDURE) + || sym->attr.external + || sym->attr.generic + || sym->attr.entry + || sym->attr.result + || sym->attr.dummy + || sym->attr.subroutine + || sym->attr.pointer + || sym->attr.target + || sym->attr.cray_pointer + || sym->attr.cray_pointee + || (sym->attr.proc != PROC_UNKNOWN + && sym->attr.proc != PROC_INTRINSIC) + || sym->attr.if_source != IFSRC_UNKNOWN + || sym == sym->ns->proc_name) + { + sym = NULL; + n = NULL; + } + else + n = sym->name; + } + if (n == NULL) + rop = OMP_REDUCTION_NONE; + else if (strcmp (n, "max") == 0) + rop = OMP_REDUCTION_MAX; + else if (strcmp (n, "min") == 0) + rop = OMP_REDUCTION_MIN; + else if (strcmp (n, "iand") == 0) + rop = OMP_REDUCTION_IAND; + else if (strcmp (n, "ior") == 0) + rop = OMP_REDUCTION_IOR; + else if (strcmp (n, "ieor") == 0) + rop = OMP_REDUCTION_IEOR; + if (rop != OMP_REDUCTION_NONE + && sym != NULL + && ! sym->attr.intrinsic + && ! sym->attr.use_assoc + && ((sym->attr.flavor == FL_UNKNOWN + && !gfc_add_flavor (&sym->attr, FL_PROCEDURE, + sym->name, NULL)) + || !gfc_add_intrinsic (&sym->attr, NULL))) + rop = OMP_REDUCTION_NONE; + } + else + buffer[0] = '\0'; + gfc_omp_udr *udr = (buffer[0] ? gfc_find_omp_udr (gfc_current_ns, buffer, NULL) + : NULL); + gfc_omp_namelist **head = NULL; + if (rop == OMP_REDUCTION_NONE && udr) + rop = OMP_REDUCTION_USER; + + if (gfc_match_omp_variable_list (" :", &c->lists[list_idx], false, NULL, + &head, openacc, allow_derived) != MATCH_YES) + { + gfc_current_locus = old_loc; + return MATCH_NO; + } + gfc_omp_namelist *n; + if (rop == OMP_REDUCTION_NONE) + { + n = *head; + *head = NULL; + gfc_error_now ("!$OMP DECLARE REDUCTION %s not found at %L", + buffer, &old_loc); + gfc_free_omp_namelist (n); + } + else + for (n = *head; n; n = n->next) + { + n->u.reduction_op = rop; + if (udr) + { + n->udr = gfc_get_omp_namelist_udr (); + n->udr->udr = udr; + } + } + return MATCH_YES; +} + /* Match OpenMP and OpenACC directive clauses. MASK is a bitmask of clauses that are allowed for a particular directive. */ @@ -1379,6 +1538,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, needs_space = true; continue; } + if ((mask & OMP_CLAUSE_IN_REDUCTION) + && gfc_match_omp_clause_reduction (pc, c, openacc, + allow_derived) == MATCH_YES) + continue; if ((mask & OMP_CLAUSE_INBRANCH) && !c->inbranch && !c->notinbranch @@ -1717,124 +1880,24 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, continue; } if ((mask & OMP_CLAUSE_REDUCTION) - && gfc_match ("reduction ( ") == MATCH_YES) + && gfc_match_omp_clause_reduction (pc, c, openacc, + allow_derived) == MATCH_YES) + continue; + if ((mask & OMP_CLAUSE_MEMORDER) + && c->memorder == OMP_MEMORDER_UNSET + && gfc_match ("relaxed") == MATCH_YES) { - gfc_omp_reduction_op rop = OMP_REDUCTION_NONE; - char buffer[GFC_MAX_SYMBOL_LEN + 3]; - if (gfc_match_char ('+') == MATCH_YES) - rop = OMP_REDUCTION_PLUS; - else if (gfc_match_char ('*') == MATCH_YES) - rop = OMP_REDUCTION_TIMES; - else if (gfc_match_char ('-') == MATCH_YES) - rop = OMP_REDUCTION_MINUS; - else if (gfc_match (".and.") == MATCH_YES) - rop = OMP_REDUCTION_AND; - else if (gfc_match (".or.") == MATCH_YES) - rop = OMP_REDUCTION_OR; - else if (gfc_match (".eqv.") == MATCH_YES) - rop = OMP_REDUCTION_EQV; - else if (gfc_match (".neqv.") == MATCH_YES) - rop = OMP_REDUCTION_NEQV; - if (rop != OMP_REDUCTION_NONE) - snprintf (buffer, sizeof buffer, "operator %s", - gfc_op2string ((gfc_intrinsic_op) rop)); - else if (gfc_match_defined_op_name (buffer + 1, 1) == MATCH_YES) - { - buffer[0] = '.'; - strcat (buffer, "."); - } - else if (gfc_match_name (buffer) == MATCH_YES) - { - gfc_symbol *sym; - const char *n = buffer; - - gfc_find_symbol (buffer, NULL, 1, &sym); - if (sym != NULL) - { - if (sym->attr.intrinsic) - n = sym->name; - else if ((sym->attr.flavor != FL_UNKNOWN - && sym->attr.flavor != FL_PROCEDURE) - || sym->attr.external - || sym->attr.generic - || sym->attr.entry - || sym->attr.result - || sym->attr.dummy - || sym->attr.subroutine - || sym->attr.pointer - || sym->attr.target - || sym->attr.cray_pointer - || sym->attr.cray_pointee - || (sym->attr.proc != PROC_UNKNOWN - && sym->attr.proc != PROC_INTRINSIC) - || sym->attr.if_source != IFSRC_UNKNOWN - || sym == sym->ns->proc_name) - { - sym = NULL; - n = NULL; - } - else - n = sym->name; - } - if (n == NULL) - rop = OMP_REDUCTION_NONE; - else if (strcmp (n, "max") == 0) - rop = OMP_REDUCTION_MAX; - else if (strcmp (n, "min") == 0) - rop = OMP_REDUCTION_MIN; - else if (strcmp (n, "iand") == 0) - rop = OMP_REDUCTION_IAND; - else if (strcmp (n, "ior") == 0) - rop = OMP_REDUCTION_IOR; - else if (strcmp (n, "ieor") == 0) - rop = OMP_REDUCTION_IEOR; - if (rop != OMP_REDUCTION_NONE - && sym != NULL - && ! sym->attr.intrinsic - && ! sym->attr.use_assoc - && ((sym->attr.flavor == FL_UNKNOWN - && !gfc_add_flavor (&sym->attr, FL_PROCEDURE, - sym->name, NULL)) - || !gfc_add_intrinsic (&sym->attr, NULL))) - rop = OMP_REDUCTION_NONE; - } - else - buffer[0] = '\0'; - gfc_omp_udr *udr - = (buffer[0] - ? gfc_find_omp_udr (gfc_current_ns, buffer, NULL) : NULL); - gfc_omp_namelist **head = NULL; - if (rop == OMP_REDUCTION_NONE && udr) - rop = OMP_REDUCTION_USER; - - if (gfc_match_omp_variable_list (" :", - &c->lists[OMP_LIST_REDUCTION], - false, NULL, &head, openacc, - allow_derived) == MATCH_YES) - { - gfc_omp_namelist *n; - if (rop == OMP_REDUCTION_NONE) - { - n = *head; - *head = NULL; - gfc_error_now ("!$OMP DECLARE REDUCTION %s not found " - "at %L", buffer, &old_loc); - gfc_free_omp_namelist (n); - } - else - for (n = *head; n; n = n->next) - { - n->u.reduction_op = rop; - if (udr) - { - n->udr = gfc_get_omp_namelist_udr (); - n->udr->udr = udr; - } - } - continue; - } - else - gfc_current_locus = old_loc; + c->memorder = OMP_MEMORDER_RELAXED; + needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_MEMORDER) + && c->memorder == OMP_MEMORDER_UNSET + && gfc_match ("release") == MATCH_YES) + { + c->memorder = OMP_MEMORDER_RELEASE; + needs_space = true; + continue; } if ((mask & OMP_CLAUSE_MEMORDER) && c->memorder == OMP_MEMORDER_UNSET @@ -1962,6 +2025,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, } break; case 't': + if ((mask & OMP_CLAUSE_TASK_REDUCTION) + && gfc_match_omp_clause_reduction (pc, c, openacc, + allow_derived) == MATCH_YES) + continue; if ((mask & OMP_CLAUSE_THREAD_LIMIT) && c->thread_limit == NULL && gfc_match ("thread_limit ( %e )", @@ -2696,18 +2763,19 @@ cleanup: (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE \ | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT \ | OMP_CLAUSE_UNTIED | OMP_CLAUSE_FINAL | OMP_CLAUSE_MERGEABLE \ - | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY) + | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY | OMP_CLAUSE_IN_REDUCTION) #define OMP_TASKLOOP_CLAUSES \ (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE \ | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF \ | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED | OMP_CLAUSE_FINAL \ | OMP_CLAUSE_MERGEABLE | OMP_CLAUSE_PRIORITY | OMP_CLAUSE_GRAINSIZE \ - | OMP_CLAUSE_NUM_TASKS | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_NOGROUP) + | OMP_CLAUSE_NUM_TASKS | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_NOGROUP \ + | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_IN_REDUCTION) #define OMP_TARGET_CLAUSES \ (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF \ | OMP_CLAUSE_DEPEND | OMP_CLAUSE_NOWAIT | OMP_CLAUSE_PRIVATE \ | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULTMAP \ - | OMP_CLAUSE_IS_DEVICE_PTR) + | OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION) #define OMP_TARGET_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF \ | OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR) @@ -4228,12 +4296,12 @@ gfc_match_omp_barrier (void) match gfc_match_omp_taskgroup (void) { - if (gfc_match_omp_eos () != MATCH_YES) - { - gfc_error ("Unexpected junk after $OMP TASKGROUP statement at %C"); - return MATCH_ERROR; - } + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OMP_CLAUSE_TASK_REDUCTION, true, true) + != MATCH_YES) + return MATCH_ERROR; new_st.op = EXEC_OMP_TASKGROUP; + new_st.ext.omp_clauses = c; return MATCH_YES; } @@ -4560,7 +4628,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, static const char *clause_names[] = { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED", "COPYIN", "UNIFORM", "ALIGNED", "LINEAR", "DEPEND", "MAP", - "TO", "FROM", "REDUCTION", "DEVICE_RESIDENT", "LINK", "USE_DEVICE", + "TO", "FROM", "REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/, + "IN_REDUCTION", "TASK_REDUCTION", + "DEVICE_RESIDENT", "LINK", "USE_DEVICE", "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR", "NONTEMPORAL" }; STATIC_ASSERT (ARRAY_SIZE (clause_names) == OMP_LIST_NUM); @@ -4727,21 +4797,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, if (omp_clauses->sched_kind != OMP_SCHED_NONE && omp_clauses->sched_nonmonotonic) { - if (omp_clauses->sched_kind != OMP_SCHED_DYNAMIC - && omp_clauses->sched_kind != OMP_SCHED_GUIDED) - { - const char *p; - switch (omp_clauses->sched_kind) - { - case OMP_SCHED_STATIC: p = "STATIC"; break; - case OMP_SCHED_RUNTIME: p = "RUNTIME"; break; - case OMP_SCHED_AUTO: p = "AUTO"; break; - default: gcc_unreachable (); - } - gfc_error ("NONMONOTONIC modifier specified for %s schedule kind " - "at %L", p, &code->loc); - } - else if (omp_clauses->sched_monotonic) + if (omp_clauses->sched_monotonic) gfc_error ("Both MONOTONIC and NONMONOTONIC schedule modifiers " "specified at %L", &code->loc); else if (omp_clauses->ordered) @@ -4818,7 +4874,11 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, && (list != OMP_LIST_MAP || openacc) && list != OMP_LIST_FROM && list != OMP_LIST_TO - && (list != OMP_LIST_REDUCTION || !openacc)) + && (list != OMP_LIST_REDUCTION || !openacc) + && list != OMP_LIST_REDUCTION_INSCAN + && list != OMP_LIST_REDUCTION_TASK + && list != OMP_LIST_IN_REDUCTION + && list != OMP_LIST_TASK_REDUCTION) for (n = omp_clauses->lists[list]; n; n = n->next) { bool component_ref_p = false; @@ -5224,6 +5284,11 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, for (; n != NULL; n = n->next) { bool bad = false; + bool is_reduction = (list == OMP_LIST_REDUCTION + || list == OMP_LIST_REDUCTION_INSCAN + || list == OMP_LIST_REDUCTION_TASK + || list == OMP_LIST_IN_REDUCTION + || list == OMP_LIST_TASK_REDUCTION); if (n->sym->attr.threadprivate) gfc_error ("THREADPRIVATE object %qs in %s clause at %L", n->sym->name, name, &n->where); @@ -5233,15 +5298,15 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, if (n->sym->attr.associate_var) gfc_error ("ASSOCIATE name %qs in %s clause at %L", n->sym->name, name, &n->where); - if (list != OMP_LIST_PRIVATE) + if (list != OMP_LIST_PRIVATE && is_reduction) { - if (n->sym->attr.proc_pointer && list == OMP_LIST_REDUCTION) + if (n->sym->attr.proc_pointer) gfc_error ("Procedure pointer %qs in %s clause at %L", n->sym->name, name, &n->where); - if (n->sym->attr.pointer && list == OMP_LIST_REDUCTION) + if (n->sym->attr.pointer) gfc_error ("POINTER object %qs in %s clause at %L", n->sym->name, name, &n->where); - if (n->sym->attr.cray_pointer && list == OMP_LIST_REDUCTION) + if (n->sym->attr.cray_pointer) gfc_error ("Cray pointer %qs in %s clause at %L", n->sym->name, name, &n->where); } @@ -5253,7 +5318,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, else if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE) gfc_error ("Assumed size array %qs in %s clause at %L", n->sym->name, name, &n->where); - if (n->sym->attr.in_namelist && list != OMP_LIST_REDUCTION) + if (n->sym->attr.in_namelist && !is_reduction) gfc_error ("Variable %qs in %s clause is used in " "NAMELIST statement at %L", n->sym->name, name, &n->where); @@ -5273,7 +5338,21 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, switch (list) { + case OMP_LIST_REDUCTION_INSCAN: + case OMP_LIST_REDUCTION_TASK: + if (code && (code->op == EXEC_OMP_TASKLOOP + || code->op == EXEC_OMP_TEAMS + || code->op == EXEC_OMP_TEAMS_DISTRIBUTE)) + { + gfc_error ("Only DEFAULT permitted as reduction-" + "modifier in REDUCTION clause at %L", + &n->where); + break; + } + gcc_fallthrough (); case OMP_LIST_REDUCTION: + case OMP_LIST_IN_REDUCTION: + case OMP_LIST_TASK_REDUCTION: switch (n->u.reduction_op) { case OMP_REDUCTION_PLUS: @@ -6102,6 +6181,10 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns) case OMP_LIST_FIRSTPRIVATE: case OMP_LIST_LASTPRIVATE: case OMP_LIST_REDUCTION: + case OMP_LIST_REDUCTION_INSCAN: + case OMP_LIST_REDUCTION_TASK: + case OMP_LIST_IN_REDUCTION: + case OMP_LIST_TASK_REDUCTION: case OMP_LIST_LINEAR: for (n = omp_clauses->lists[list]; n; n = n->next) ctx.sharing_clauses->add (n->sym); diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 1d652a0..d2559bd 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -626,6 +626,8 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer) case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_LINEAR: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_IN_REDUCTION: + case OMP_CLAUSE_TASK_REDUCTION: break; default: gcc_unreachable (); @@ -699,7 +701,9 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer) then_b = gfc_finish_block (&cond_block); /* Reduction clause requires allocated ALLOCATABLE. */ - if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_REDUCTION) + if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_REDUCTION + && OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_IN_REDUCTION + && OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_TASK_REDUCTION) { gfc_init_block (&cond_block); if (GFC_DESCRIPTOR_TYPE_P (type)) @@ -2029,9 +2033,25 @@ gfc_trans_omp_array_reduction_or_udr (tree c, gfc_omp_namelist *n, locus where) } static tree -gfc_trans_omp_reduction_list (gfc_omp_namelist *namelist, tree list, +gfc_trans_omp_reduction_list (int kind, gfc_omp_namelist *namelist, tree list, locus where, bool mark_addressable) { + omp_clause_code clause = OMP_CLAUSE_REDUCTION; + switch (kind) + { + case OMP_LIST_REDUCTION: + case OMP_LIST_REDUCTION_INSCAN: + case OMP_LIST_REDUCTION_TASK: + break; + case OMP_LIST_IN_REDUCTION: + clause = OMP_CLAUSE_IN_REDUCTION; + break; + case OMP_LIST_TASK_REDUCTION: + clause = OMP_CLAUSE_TASK_REDUCTION; + break; + default: + gcc_unreachable (); + } for (; namelist != NULL; namelist = namelist->next) if (namelist->sym->attr.referenced) { @@ -2039,10 +2059,14 @@ gfc_trans_omp_reduction_list (gfc_omp_namelist *namelist, tree list, if (t != error_mark_node) { tree node = build_omp_clause (gfc_get_location (&namelist->where), - OMP_CLAUSE_REDUCTION); + clause); OMP_CLAUSE_DECL (node) = t; if (mark_addressable) TREE_ADDRESSABLE (t) = 1; + if (kind == OMP_LIST_REDUCTION_INSCAN) + OMP_CLAUSE_REDUCTION_INSCAN (node) = 1; + if (kind == OMP_LIST_REDUCTION_TASK) + OMP_CLAUSE_REDUCTION_TASK (node) = 1; switch (namelist->u.reduction_op) { case OMP_REDUCTION_PLUS: @@ -2267,10 +2291,14 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, switch (list) { case OMP_LIST_REDUCTION: + case OMP_LIST_REDUCTION_INSCAN: + case OMP_LIST_REDUCTION_TASK: + case OMP_LIST_IN_REDUCTION: + case OMP_LIST_TASK_REDUCTION: /* An OpenACC async clause indicates the need to set reduction arguments addressable, to allow asynchronous copy-out. */ - omp_clauses = gfc_trans_omp_reduction_list (n, omp_clauses, where, - clauses->async); + omp_clauses = gfc_trans_omp_reduction_list (list, n, omp_clauses, + where, clauses->async); break; case OMP_LIST_PRIVATE: clause_code = OMP_CLAUSE_PRIVATE; @@ -5207,18 +5235,27 @@ gfc_split_omp_clauses (gfc_code *code, /* Reduction is allowed on simd, do, parallel and teams. Duplicate it on all of them, but omit on do if parallel is present. */ - if (mask & GFC_OMP_MASK_TEAMS) - clausesa[GFC_OMP_SPLIT_TEAMS].lists[OMP_LIST_REDUCTION] - = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION]; - if (mask & GFC_OMP_MASK_PARALLEL) - clausesa[GFC_OMP_SPLIT_PARALLEL].lists[OMP_LIST_REDUCTION] - = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION]; - else if (mask & GFC_OMP_MASK_DO) - clausesa[GFC_OMP_SPLIT_DO].lists[OMP_LIST_REDUCTION] - = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION]; - if (mask & GFC_OMP_MASK_SIMD) - clausesa[GFC_OMP_SPLIT_SIMD].lists[OMP_LIST_REDUCTION] - = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION]; + for (int i = OMP_LIST_REDUCTION; i <= OMP_LIST_REDUCTION_TASK; i++) + { + if (mask & GFC_OMP_MASK_TEAMS) + clausesa[GFC_OMP_SPLIT_TEAMS].lists[i] + = code->ext.omp_clauses->lists[i]; + if (mask & GFC_OMP_MASK_PARALLEL) + clausesa[GFC_OMP_SPLIT_PARALLEL].lists[i] + = code->ext.omp_clauses->lists[i]; + else if (mask & GFC_OMP_MASK_DO) + clausesa[GFC_OMP_SPLIT_DO].lists[i] + = code->ext.omp_clauses->lists[i]; + if (mask & GFC_OMP_MASK_SIMD) + clausesa[GFC_OMP_SPLIT_SIMD].lists[i] + = code->ext.omp_clauses->lists[i]; + } + if (mask & GFC_OMP_MASK_TARGET) + clausesa[GFC_OMP_SPLIT_TARGET].lists[OMP_LIST_IN_REDUCTION] + = code->ext.omp_clauses->lists[OMP_LIST_IN_REDUCTION]; + if (mask & GFC_OMP_MASK_TASKLOOP) + clausesa[GFC_OMP_SPLIT_TASKLOOP].lists[OMP_LIST_IN_REDUCTION] + = code->ext.omp_clauses->lists[OMP_LIST_IN_REDUCTION]; /* Linear clause is supported on do and simd, put it on the innermost one. */ clausesa[innermost].lists[OMP_LIST_LINEAR] diff --git a/gcc/gimplify.c b/gcc/gimplify.c index b2c623b..d18c43e 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8672,7 +8672,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, { error_at (OMP_CLAUSE_LOCATION (c), "invalid % reduction modifier on construct " - "other than %, % or %"); + "other than %, %qs or %", + lang_GNU_Fortran () ? "do" : "for"); OMP_CLAUSE_REDUCTION_TASK (c) = 0; } } @@ -12703,7 +12704,8 @@ gimplify_omp_loop (tree *expr_p, gimple_seq *pre_p) { error_at (OMP_CLAUSE_LOCATION (*pc), "invalid % reduction modifier on construct " - "other than %, % or %"); + "other than %, %qs or %", + lang_GNU_Fortran () ? "do" : "for"); OMP_CLAUSE_REDUCTION_TASK (*pc) = 0; } pc = &OMP_CLAUSE_CHAIN (*pc); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 447d7db..83ca5fc 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -2937,7 +2937,8 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) { error_at (gimple_location (stmt), "% must be closely " - "nested inside of % region"); + "nested inside of %<%s simd%> region", + lang_GNU_Fortran () ? "do" : "for"); return false; } return true; diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 new file mode 100644 index 0000000..af8c91b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 @@ -0,0 +1,171 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } +! +! (in_)reduction clause +! Test all in-principle valid combinations, even if +! not valid in this context (some fail at ME level) +! +implicit none +integer :: a, b, i +a = 0 + +! ------------ parallel ------------ +!$omp parallel reduction(+:a) +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +!$omp parallel reduction(default,+:a) +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +!$omp parallel reduction(task,+:a) +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +!$omp parallel reduction(inscan,+:a) ! { dg-error "'inscan' 'reduction' clause on 'parallel' construct" } +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +! ------------ simd ------------ +!$omp simd reduction(+:a) +do i=1,10 + a = a + 1 +end do + +!$omp simd reduction(default,+:a) +do i=1,10 + a = a + 1 +end do + +!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" } +do i=1,10 + a = a + 1 +end do + +!$omp simd reduction(inscan,+:a) ! { dg-error "'inscan' 'reduction' clause but not in 'scan' directive clause" } +do i=1,10 + a = a + 1 +end do + +! ------------ do ------------ +!$omp parallel +!$omp do reduction(+:a) +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +!$omp parallel +!$omp do reduction(default,+:a) +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +!$omp parallel +!$omp do reduction(task,+:a) +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +!$omp parallel +!$omp do reduction(inscan,+:a) ! { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } +do i=1,10 + a = a + 1 +end do +!$omp end parallel + +! ------------ section ------------ +!$omp parallel +!$omp sections reduction(+:a) + !$omp section + a = a + 1 +!$omp end sections +!$omp end parallel + +!$omp parallel +!$omp sections reduction(default,+:a) + !$omp section + a = a + 1 +!$omp end sections +!$omp end parallel + +!$omp parallel +!$omp sections reduction(task,+:a) + !$omp section + a = a + 1 +!$omp end sections +!$omp end parallel + +!$omp parallel +!$omp sections reduction(inscan,+:a) ! { dg-error "'inscan' 'reduction' clause on 'sections' construct" } + !$omp section + a = a + 1 +!$omp end sections +!$omp end parallel + +! ------------ task ------------ +!$omp task in_reduction(+:a) + a = a + 1 +!$omp end task + +! ------------ taskloop ------------ +!$omp taskloop reduction(+:a) in_reduction(+:b) +do i=1,10 + a = a + 1 +end do + +!$omp taskloop reduction(default,+:a) in_reduction(+:b) +do i=1,10 + a = a + 1 +end do + +! ------------ target ------------ +!$omp target in_reduction(+:b) + a = a + 1 +!$omp end target + +! ------------ teams ------------ +!$omp teams reduction(+:b) + a = a + 1 +!$omp end teams + +!$omp teams reduction(default, +:b) + a = a + 1 +!$omp end teams + +! ------------ taskgroup -------- + +!$omp taskgroup task_reduction(+:b) + a = a + 1 +!$omp end taskgroup + +end + +! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(\\\+:a\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(inscan,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(task,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp parallel\[\n\r\]" 8 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(\\\+:a\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(task,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp section\[\n\r\]" 4 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(\\\+:a\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(inscan,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(task,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(\\\+:a\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(task,\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target in_reduction\\(\\\+:b\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp task in_reduction\\(\\\+:a\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp teams reduction\\(\\\+:b\\)" 2 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp taskloop reduction\\(\\\+:a\\) in_reduction\\(\\\+:b\\)" 2 "original" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 new file mode 100644 index 0000000..df915f1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 @@ -0,0 +1,41 @@ +! { dg-do compile } +! +implicit none +integer :: a, b, i +a = 0 + +!$omp parallel reduction(foo,+:a) ! { dg-error "26: Failed to match clause" } +do i=1,10 + a = a + 1 +end do +!$omp end parallel ! { dg-error "Unexpected !.OMP END PARALLEL statement" } + +!$omp parallel reduction(task +:a) ! { dg-error "30: Comma expected at" } +do i=1,10 + a = a + 1 +end do +!$omp end parallel ! { dg-error "Unexpected !.OMP END PARALLEL statement" } + +!$omp task in_reduction(foo,+:a) ! { dg-error "25: Failed to match clause" } + a = a + 1 +!$omp end task ! { dg-error "Unexpected !.OMP END TASK statement" } + +!$omp taskloop reduction(inscan,+:a) in_reduction(+:b) ! { dg-error "34: Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } +do i=1,10 + a = a + 1 +end do + +!$omp taskloop reduction(task,+:a) in_reduction(+:b) ! { dg-error "32: Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } +do i=1,10 + a = a + 1 +end do + +!$omp teams reduction(inscan,+:b) ! { dg-error "31: Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + a = a + 1 +!$omp end teams + +!$omp teams reduction(task, +:b) ! { dg-error "30: Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + a = a + 1 +!$omp end teams + +end diff --git a/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90 b/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90 index 0be53cc..537fba2 100644 --- a/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90 @@ -3,16 +3,16 @@ subroutine foo integer :: i - !$omp do schedule (nonmonotonic: static, 2) ! { dg-error "NONMONOTONIC modifier specified for STATIC schedule kind" } + !$omp do schedule (nonmonotonic: static, 2) do i = 0, 64 end do - !$omp do schedule (nonmonotonic : static) ! { dg-error "NONMONOTONIC modifier specified for STATIC schedule kind" } + !$omp do schedule (nonmonotonic : static) do i = 0, 64 end do - !$omp do schedule (nonmonotonic : runtime) ! { dg-error "NONMONOTONIC modifier specified for RUNTIME schedule kind" } + !$omp do schedule (nonmonotonic : runtime) do i = 0, 64 end do - !$omp do schedule (nonmonotonic : auto) ! { dg-error "NONMONOTONIC modifier specified for AUTO schedule kind" } + !$omp do schedule (nonmonotonic : auto) do i = 0, 64 end do !$omp do schedule (nonmonotonic : dynamic) ordered ! { dg-error "NONMONOTONIC schedule modifier specified with ORDERED clause" } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90 new file mode 100644 index 0000000..3e639d2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 0, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_maybe_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (runtime) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90 new file mode 100644 index 0000000..e71ac3f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: static, 2) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90 new file mode 100644 index 0000000..9420220 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (dynamic) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90 new file mode 100644 index 0000000..66c6eb1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: dynamic) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90 new file mode 100644 index 0000000..89782d2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90 new file mode 100644 index 0000000..16b3e01 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (dynamic, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90 new file mode 100644 index 0000000..8bf126c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: dynamic, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90 new file mode 100644 index 0000000..fe8d1ae --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90 new file mode 100644 index 0000000..1f2823d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (guided) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90 new file mode 100644 index 0000000..ad0856a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: guided) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90 new file mode 100644 index 0000000..e884dbf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: guided) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90 new file mode 100644 index 0000000..2f78c0b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: runtime) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90 new file mode 100644 index 0000000..8a4d6df --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (guided, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90 new file mode 100644 index 0000000..2d9362b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: guided, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90 new file mode 100644 index 0000000..485171f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: guided, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90 new file mode 100644 index 0000000..45dc000 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (auto) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90 new file mode 100644 index 0000000..e7fbe92 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: auto) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90 new file mode 100644 index 0000000..d5554c4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: auto) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 new file mode 100644 index 0000000..2826790 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 0, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_maybe_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (runtime) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 new file mode 100644 index 0000000..2ee047d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: runtime) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 new file mode 100644 index 0000000..6c9d49b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 4, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: runtime) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90 new file mode 100644 index 0000000..316b72e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 new file mode 100644 index 0000000..6c9d49b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 4, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: runtime) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90 new file mode 100644 index 0000000..b9406d6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (static) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90 new file mode 100644 index 0000000..4a24604 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: static) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90 new file mode 100644 index 0000000..a7062d9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: static) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90 new file mode 100644 index 0000000..67c25c8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (static, 2) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90 new file mode 100644 index 0000000..f1e4d89 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: static, 2) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90 new file mode 100644 index 0000000..7d7c271 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: static, 2) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 new file mode 100644 index 0000000..b190e9e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (dynamic) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 new file mode 100644 index 0000000..c541d22 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: dynamic) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 new file mode 100644 index 0000000..46a27a0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 new file mode 100644 index 0000000..6cdd9a8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (dynamic, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90 new file mode 100644 index 0000000..c774427 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 new file mode 100644 index 0000000..29da27a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: dynamic, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 new file mode 100644 index 0000000..4ed879c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 new file mode 100644 index 0000000..78d02ef --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (guided) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 new file mode 100644 index 0000000..16885c8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: guided) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 new file mode 100644 index 0000000..0db9be6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: guided) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 new file mode 100644 index 0000000..40b1275 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (guided, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 new file mode 100644 index 0000000..57c7402 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: guided, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 new file mode 100644 index 0000000..b456430 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: guided, 3) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90 new file mode 100644 index 0000000..1370010 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (auto) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90 new file mode 100644 index 0000000..ab2591f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: auto) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90 new file mode 100644 index 0000000..ce3db0f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (static) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90 new file mode 100644 index 0000000..8b89427 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: auto) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90 new file mode 100644 index 0000000..13bde3a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do ordered reduction (task, *: j) schedule (runtime) + do i = a, b, c + call bar (j) + !$omp ordered + j = j + 1 + !$omp end ordered + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90 new file mode 100644 index 0000000..50dce3d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_static_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do ordered reduction (task, *: j) + do i = a, b, c + call bar (j) + !$omp ordered + j = j + 1 + !$omp end ordered + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90 new file mode 100644 index 0000000..0184209 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483650|-2147483646), 4, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do ordered reduction (task, *: j) schedule (dynamic, 4) + do i = a, b, c + call bar (j) + !$omp ordered + j = j + 1 + !$omp end ordered + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90 new file mode 100644 index 0000000..0681e43 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483651|-2147483645), 6, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do ordered reduction (task, *: j) schedule (guided, 6) + do i = a, b, c + call bar (j) + !$omp ordered + j = j + 1 + !$omp end ordered + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90 new file mode 100644 index 0000000..4d2e1e5 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do ordered(1) reduction (task, *: j) schedule (runtime) + do i = a, b, c + call bar (j) + !$omp ordered depend(sink: i - 1) + j = j + 1 + !$omp ordered depend(source) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 new file mode 100644 index 0000000..dc5ddaf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_static_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do ordered(1) reduction (task, *: j) + do i = a, b, c + call bar (j) + !$omp ordered depend(sink: i - 1) + j = j + 1 + !$omp ordered depend(source) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 new file mode 100644 index 0000000..8042488 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer(8) :: j + interface + subroutine bar(i) + integer(8) :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer(8) :: a, b ,c + integer(8) :: i + !$omp parallel + !$omp do ordered(1) reduction (task, *: j) schedule (dynamic) + do i = a, b, c + call bar (j) + !$omp ordered depend(sink: i - 1) + j = j + 1 + !$omp ordered depend(source) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90 new file mode 100644 index 0000000..ae4f8bc --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do ordered(1) reduction (task, *: j) schedule (guided) + do i = a, b, c + call bar (j) + !$omp ordered depend(sink: i - 1) + j = j + 1 + !$omp ordered depend(source) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90 new file mode 100644 index 0000000..147f14a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: static) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90 new file mode 100644 index 0000000..dc99a75 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (nonmonotonic: static) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90 new file mode 100644 index 0000000..9d0a1ce --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (static, 2) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90 new file mode 100644 index 0000000..c613746 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90 @@ -0,0 +1,31 @@ +! { dg-do compile } +! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } +! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } + +module m + implicit none (type, external) + integer :: j + interface + subroutine bar(i) + integer :: i + end subroutine + end interface +end module m + +subroutine foo(a, b, c) + use m + implicit none (type, external) + integer :: a, b ,c + integer :: i + !$omp parallel + !$omp do reduction (task, *: j) schedule (monotonic: static, 2) + do i = a, b, c + j = j + 1 + call bar (j) + end do + !$omp end parallel +end -- cgit v1.1 From c710051affd51ac630072ac0cd2c232c0bf2c265 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 23 Oct 2020 17:21:51 +0200 Subject: analyzer: remove dead code gcc/analyzer/ChangeLog: * constraint-manager.cc (constraint_manager::merge): Remove unused code. * constraint-manager.h: Likewise. * program-state.cc (sm_state_map::sm_state_map): Likewise. (program_state::program_state): Likewise. (test_sm_state_map): Likewise. * program-state.h: Likewise. * region-model-reachability.cc (reachable_regions::reachable_regions): Likewise. * region-model-reachability.h: Likewise. * region-model.cc (region_model::handle_unrecognized_call): Likewise. (region_model::get_reachable_svalues): Likewise. (region_model::can_merge_with_p): Likewise. --- gcc/analyzer/constraint-manager.cc | 11 ++++------- gcc/analyzer/constraint-manager.h | 3 +-- gcc/analyzer/program-state.cc | 22 +++++++++++----------- gcc/analyzer/program-state.h | 3 +-- gcc/analyzer/region-model-reachability.cc | 5 ++--- gcc/analyzer/region-model-reachability.h | 3 +-- gcc/analyzer/region-model.cc | 7 +++---- 7 files changed, 23 insertions(+), 31 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 2978f1b..590bf32 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -1790,9 +1790,8 @@ class merger_fact_visitor : public fact_visitor { public: merger_fact_visitor (const constraint_manager *cm_b, - constraint_manager *out, - const model_merger &merger) - : m_cm_b (cm_b), m_out (out), m_merger (merger) + constraint_manager *out) + : m_cm_b (cm_b), m_out (out) {} void on_fact (const svalue *lhs, enum tree_code code, const svalue *rhs) @@ -1826,7 +1825,6 @@ public: private: const constraint_manager *m_cm_b; constraint_manager *m_out; - const model_merger &m_merger; }; /* Use MERGER to merge CM_A and CM_B into *OUT. @@ -1838,14 +1836,13 @@ private: void constraint_manager::merge (const constraint_manager &cm_a, const constraint_manager &cm_b, - constraint_manager *out, - const model_merger &merger) + constraint_manager *out) { /* Merge the equivalence classes and constraints. The easiest way to do this seems to be to enumerate all of the facts in cm_a, see which are also true in cm_b, and add those to *OUT. */ - merger_fact_visitor v (&cm_b, out, merger); + merger_fact_visitor v (&cm_b, out); cm_a.for_each_fact (&v); } diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h index 98960ff..1142b1f 100644 --- a/gcc/analyzer/constraint-manager.h +++ b/gcc/analyzer/constraint-manager.h @@ -274,8 +274,7 @@ public: static void merge (const constraint_manager &cm_a, const constraint_manager &cm_b, - constraint_manager *out, - const model_merger &merger); + constraint_manager *out); void for_each_fact (fact_visitor *) const; diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index b39e55a..5c59c09 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -154,8 +154,8 @@ sm_state_map::entry_t::cmp (const entry_t &entry_a, const entry_t &entry_b) /* sm_state_map's ctor. */ -sm_state_map::sm_state_map (const state_machine &sm, int sm_idx) -: m_sm (sm), m_sm_idx (sm_idx), m_map (), m_global_state (sm.get_start_state ()) +sm_state_map::sm_state_map (const state_machine &sm) +: m_sm (sm), m_map (), m_global_state (sm.get_start_state ()) { } @@ -656,7 +656,7 @@ program_state::program_state (const extrinsic_state &ext_state) const int num_states = ext_state.get_num_checkers (); for (int i = 0; i < num_states; i++) { - sm_state_map *sm = new sm_state_map (ext_state.get_sm (i), i); + sm_state_map *sm = new sm_state_map (ext_state.get_sm (i)); m_checker_states.quick_push (sm); } } @@ -1251,7 +1251,7 @@ test_sm_state_map () const svalue *y_sval = model.get_rvalue (y, NULL); const svalue *z_sval = model.get_rvalue (z, NULL); - sm_state_map map (*sm, 0); + sm_state_map map (*sm); ASSERT_TRUE (map.is_empty_p ()); ASSERT_EQ (map.get_state (x_sval, ext_state), start); @@ -1280,7 +1280,7 @@ test_sm_state_map () const svalue *y_sval = model.get_rvalue (y, NULL); const svalue *z_sval = model.get_rvalue (z, NULL); - sm_state_map map (*sm, 0); + sm_state_map map (*sm); ASSERT_TRUE (map.is_empty_p ()); ASSERT_EQ (map.get_state (x_sval, ext_state), start); ASSERT_EQ (map.get_state (y_sval, ext_state), start); @@ -1303,9 +1303,9 @@ test_sm_state_map () const svalue *y_sval = model.get_rvalue (y, NULL); const svalue *z_sval = model.get_rvalue (z, NULL); - sm_state_map map0 (*sm, 0); - sm_state_map map1 (*sm, 0); - sm_state_map map2 (*sm, 0); + sm_state_map map0 (*sm); + sm_state_map map1 (*sm); + sm_state_map map2 (*sm); ASSERT_EQ (map0.hash (), map1.hash ()); ASSERT_EQ (map0, map1); @@ -1326,9 +1326,9 @@ test_sm_state_map () const state_machine::state_t TEST_STATE_2 = &test_state_2; const state_machine::state test_state_3 ("test state 3", 3); const state_machine::state_t TEST_STATE_3 = &test_state_3; - sm_state_map map0 (*sm, 0); - sm_state_map map1 (*sm, 0); - sm_state_map map2 (*sm, 0); + sm_state_map map0 (*sm); + sm_state_map map1 (*sm); + sm_state_map map2 (*sm); ASSERT_EQ (map0.hash (), map1.hash ()); ASSERT_EQ (map0, map1); diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index c44fc94..1532210 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -104,7 +104,7 @@ public: typedef hash_map map_t; typedef map_t::iterator iterator_t; - sm_state_map (const state_machine &sm, int m_sm_idx); + sm_state_map (const state_machine &sm); sm_state_map *clone () const; @@ -168,7 +168,6 @@ public: private: const state_machine &m_sm; - int m_sm_idx; map_t m_map; state_machine::state_t m_global_state; }; diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc index 7fd8905..9fc70d2 100644 --- a/gcc/analyzer/region-model-reachability.cc +++ b/gcc/analyzer/region-model-reachability.cc @@ -58,9 +58,8 @@ along with GCC; see the file COPYING3. If not see namespace ana { -reachable_regions::reachable_regions (region_model *model, - region_model_manager *mgr) -: m_model (model), m_store (model->get_store ()), m_mgr (mgr), +reachable_regions::reachable_regions (region_model *model) +: m_model (model), m_store (model->get_store ()), m_reachable_base_regs (), m_mutable_base_regs () { } diff --git a/gcc/analyzer/region-model-reachability.h b/gcc/analyzer/region-model-reachability.h index fe305b0..4d30c1f 100644 --- a/gcc/analyzer/region-model-reachability.h +++ b/gcc/analyzer/region-model-reachability.h @@ -35,7 +35,7 @@ namespace ana { class reachable_regions { public: - reachable_regions (region_model *model, region_model_manager *mgr); + reachable_regions (region_model *model); /* Callback called for each cluster when initializing this object. */ static void init_cluster_cb (const region *base_reg, @@ -97,7 +97,6 @@ public: private: region_model *m_model; store *m_store; - region_model_manager *m_mgr; /* The base regions already seen. */ hash_set m_reachable_base_regs; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index e5f027b..d30047b 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -836,7 +836,7 @@ region_model::handle_unrecognized_call (const gcall *call, { tree fndecl = get_fndecl_for_call (call, ctxt); - reachable_regions reachable_regs (this, m_mgr); + reachable_regions reachable_regs (this); /* Determine the reachable regions and their mutability. */ { @@ -904,7 +904,7 @@ void region_model::get_reachable_svalues (svalue_set *out, const svalue *extra_sval) { - reachable_regions reachable_regs (this, m_mgr); + reachable_regions reachable_regs (this); /* Add globals and regions that already escaped in previous unknown calls. */ @@ -2857,8 +2857,7 @@ region_model::can_merge_with_p (const region_model &other_model, /* Merge constraints. */ constraint_manager::merge (*m_constraints, *other_model.m_constraints, - out_model->m_constraints, - m); + out_model->m_constraints); return true; } -- cgit v1.1 From 5e41e7f0928de55d189475fc14f7e6c9737cd507 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 10 Nov 2020 14:17:52 +0100 Subject: Early exit from irange::set for poly ints. My previous cleanups to irange::set moved the early exit when VARYING. This caused poly int varyings to be created with incorrect min/max. We can just set varying and exit for all poly ints. gcc/ChangeLog: * value-range.cc (irange::set): Early exit for poly ints. --- gcc/value-range.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index f83a824..b7ccba0 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -249,9 +249,11 @@ irange::set (tree min, tree max, value_range_kind kind) return; } - if (kind != VR_VARYING - && (POLY_INT_CST_P (min) || POLY_INT_CST_P (max))) - kind = VR_VARYING; + if (POLY_INT_CST_P (min) || POLY_INT_CST_P (max)) + { + set_varying (TREE_TYPE (min)); + return; + } // Nothing to canonicalize for symbolic ranges. if (TREE_CODE (min) != INTEGER_CST -- cgit v1.1 From 8b9a92f794b8ad8011e6beb11a609efa635c4600 Mon Sep 17 00:00:00 2001 From: Strager Neds Date: Tue, 10 Nov 2020 11:42:01 -0700 Subject: Refactor copying decl section names gcc/ * cgraph.h (symtab_node::get_section): Constify. (symtab_node::set_section): Declare new overload. * symtab.c (symtab_node::set_section): Define new overload. (symtab_node::copy_visibility_from): Use new overload of symtab_node::set_section. (symtab_node::resolve_alias): Same. * tree.h (set_decl_section_name): Declare new overload. * tree.c (set_decl_section_name): Define new overload. * tree-emutls.c (get_emutls_init_templ_addr): Same. * cgraphclones.c (cgraph_node::create_virtual_clone): Use new overload of symtab_node::set_section. (cgraph_node::create_version_clone_with_body): Same. * trans-mem.c (ipa_tm_create_version): Same. gcc/c * c-decl.c (merge_decls): Use new overload of set_decl_section_name. gcc/cp * decl.c (duplicate_decls): Use new overload of set_decl_section_name. * method.c (use_thunk): Same. * optimize.c (maybe_clone_body): Same. * coroutines.cc (act_des_fn): Same. gcc/d * decl.cc (finish_thunk): Use new overload of set_decl_section_name --- gcc/c/c-decl.c | 2 +- gcc/cgraph.h | 5 ++++- gcc/cgraphclones.c | 4 ++-- gcc/cp/coroutines.cc | 2 +- gcc/cp/decl.c | 2 +- gcc/cp/method.c | 2 +- gcc/cp/optimize.c | 2 +- gcc/d/decl.cc | 2 +- gcc/symtab.c | 14 ++++++++++---- gcc/trans-mem.c | 2 +- gcc/tree-emutls.c | 2 +- gcc/tree.c | 27 +++++++++++++++++++++++++++ gcc/tree.h | 1 + 13 files changed, 52 insertions(+), 15 deletions(-) (limited to 'gcc') diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index f19c82c..d348e39 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2884,7 +2884,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) || TREE_PUBLIC (olddecl) || TREE_STATIC (olddecl)) && DECL_SECTION_NAME (newdecl) != NULL) - set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl)); + set_decl_section_name (olddecl, newdecl); /* This isn't quite correct for something like int __thread x attribute ((tls_model ("local-exec"))); diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 73c37d8..2e62db2 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -263,7 +263,7 @@ public: } /* Return section as string. */ - const char * get_section () + const char * get_section () const { if (!x_section) return NULL; @@ -322,6 +322,9 @@ public: /* Set section for symbol and its aliases. */ void set_section (const char *section); + /* Like set_section, but copying the section name from another node. */ + void set_section (const symtab_node &other); + /* Set section, do not recurse into aliases. When one wants to change section of symbol and its aliases, use set_section. */ diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index bc59081..2e69689 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -626,7 +626,7 @@ cgraph_node::create_virtual_clone (vec redirect_callers, if (tree_map) clone_info::get_create (new_node)->tree_map = tree_map; if (!implicit_section) - new_node->set_section (get_section ()); + new_node->set_section (*this); /* Clones of global symbols or symbols with unique names are unique. */ if ((TREE_PUBLIC (old_decl) @@ -1060,7 +1060,7 @@ cgraph_node::create_version_clone_with_body new_version_node->local = 1; new_version_node->lowered = true; if (!implicit_section) - new_version_node->set_section (get_section ()); + new_version_node->set_section (*this); /* Clones of global symbols or symbols with unique names are unique. */ if ((TREE_PUBLIC (old_decl) && !DECL_EXTERNAL (old_decl) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 9b9141e..fd6cda4 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3756,7 +3756,7 @@ act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) /* Copy selected attributes from the original function. */ TREE_USED (fn) = TREE_USED (orig); if (DECL_SECTION_NAME (orig)) - set_decl_section_name (fn, DECL_SECTION_NAME (orig)); + set_decl_section_name (fn, orig); /* Copy any alignment that the FE added. */ if (DECL_ALIGN (orig)) SET_DECL_ALIGN (fn, DECL_ALIGN (orig)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6264884..42e704e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2866,7 +2866,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) done later in decl_attributes since we are called before attributes are assigned. */ if (DECL_SECTION_NAME (newdecl) != NULL) - set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl)); + set_decl_section_name (olddecl, newdecl); if (DECL_ONE_ONLY (newdecl)) { diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 16e7635..4de192f 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -351,7 +351,7 @@ use_thunk (tree thunk_fndecl, bool emit_p) resolve_unique_section (thunk_fndecl, 0, flag_function_sections); /* Output the thunk into the same section as function. */ - set_decl_section_name (thunk_fndecl, DECL_SECTION_NAME (fn)); + set_decl_section_name (thunk_fndecl, fn); symtab_node::get (thunk_fndecl)->implicit_section = symtab_node::get (fn)->implicit_section; } diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 00621d6..127d7fa 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -512,7 +512,7 @@ maybe_clone_body (tree fn) DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn); DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn); - set_decl_section_name (clone, DECL_SECTION_NAME (fn)); + set_decl_section_name (clone, fn); /* Adjust the parameter names and locations. */ parm = DECL_ARGUMENTS (fn); diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 457894f..d668715 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1663,7 +1663,7 @@ finish_thunk (tree thunk, tree function) resolve_unique_section (thunk, 0, flag_function_sections); /* Output the thunk into the same section as function. */ - set_decl_section_name (thunk, DECL_SECTION_NAME (fn)); + set_decl_section_name (thunk, fn); symtab_node::get (thunk)->implicit_section = symtab_node::get (fn)->implicit_section; } diff --git a/gcc/symtab.c b/gcc/symtab.c index 58b14f3..883cc3e 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1484,8 +1484,7 @@ symtab_node::copy_visibility_from (symtab_node *n) DECL_DLLIMPORT_P (decl) = DECL_DLLIMPORT_P (n->decl); resolution = n->resolution; set_comdat_group (n->get_comdat_group ()); - call_for_symbol_and_aliases (symtab_node::set_section, - const_cast(n->get_section ()), true); + set_section (*n); externally_visible = n->externally_visible; if (!DECL_RTL_SET_P (decl)) return; @@ -1671,6 +1670,14 @@ symtab_node::set_section (const char *section) (symtab_node::set_section, const_cast(section), true); } +void +symtab_node::set_section (const symtab_node &other) +{ + const char *section = other.get_section (); + call_for_symbol_and_aliases + (symtab_node::set_section, const_cast(section), true); +} + /* Return the initialization priority. */ priority_type @@ -1814,8 +1821,7 @@ symtab_node::resolve_alias (symtab_node *target, bool transparent) { error ("section of alias %q+D must match section of its target", decl); } - call_for_symbol_and_aliases (symtab_node::set_section, - const_cast(target->get_section ()), true); + set_section (*target); if (target->implicit_section) call_for_symbol_and_aliases (set_implicit_section, NULL, true); diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c index e4f264d..c078a12 100644 --- a/gcc/trans-mem.c +++ b/gcc/trans-mem.c @@ -4998,7 +4998,7 @@ ipa_tm_create_version (struct cgraph_node *old_node) new_node->lowered = true; new_node->tm_clone = 1; if (!old_node->implicit_section) - new_node->set_section (old_node->get_section ()); + new_node->set_section (*old_node); get_cg_data (&old_node, true)->clone = new_node; if (old_node->get_availability () >= AVAIL_INTERPOSABLE) diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c index 44755dd..5b55832 100644 --- a/gcc/tree-emutls.c +++ b/gcc/tree-emutls.c @@ -259,7 +259,7 @@ get_emutls_init_templ_addr (tree decl) if (targetm.emutls.tmpl_section) set_decl_section_name (to, targetm.emutls.tmpl_section); else - set_decl_section_name (to, DECL_SECTION_NAME (decl)); + set_decl_section_name (to, decl); /* Create varpool node for the new variable and finalize it if it is not external one. */ diff --git a/gcc/tree.c b/gcc/tree.c index 9260772..663f3ec 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -773,6 +773,33 @@ set_decl_section_name (tree node, const char *value) snode->set_section (value); } +/* Set section name of NODE to match the section name of OTHER. + + set_decl_section_name (decl, other) is equivalent to + set_decl_section_name (decl, DECL_SECTION_NAME (other)), but possibly more + efficient. */ +void +set_decl_section_name (tree decl, const_tree other) +{ + struct symtab_node *other_node = symtab_node::get (other); + if (other_node) + { + struct symtab_node *decl_node; + if (VAR_P (decl)) + decl_node = varpool_node::get_create (decl); + else + decl_node = cgraph_node::get_create (decl); + decl_node->set_section (*other_node); + } + else + { + struct symtab_node *decl_node = symtab_node::get (decl); + if (!decl_node) + return; + decl_node->set_section (NULL); + } +} + /* Return TLS model of a variable NODE. */ enum tls_model decl_tls_model (const_tree node) diff --git a/gcc/tree.h b/gcc/tree.h index f8f0a60..684be10 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4281,6 +4281,7 @@ extern tree decl_comdat_group (const_tree); extern tree decl_comdat_group_id (const_tree); extern const char *decl_section_name (const_tree); extern void set_decl_section_name (tree, const char *); +extern void set_decl_section_name (tree, const_tree); extern enum tls_model decl_tls_model (const_tree); extern void set_decl_tls_model (tree, enum tls_model); -- cgit v1.1 From a210d404d08e363af4b2e2a60986c3cb08f8ebc5 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 10 Nov 2020 14:57:19 -0500 Subject: c++: Add 5 unfixed tests. A couple of dg-ice tests. gcc/testsuite/ChangeLog: PR c++/52830 PR c++/88982 PR c++/90799 PR c++/87765 PR c++/89565 * g++.dg/cpp0x/constexpr-52830.C: New test. * g++.dg/cpp0x/vt-88982.C: New test. * g++.dg/cpp1z/class-deduction76.C: New test. * g++.dg/cpp1z/constexpr-lambda26.C: New test. * g++.dg/cpp2a/nontype-class39.C: New test. --- gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C | 37 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/vt-88982.C | 14 ++++++++++ gcc/testsuite/g++.dg/cpp1z/class-deduction76.C | 25 +++++++++++++++++ gcc/testsuite/g++.dg/cpp1z/constexpr-lambda26.C | 13 +++++++++ gcc/testsuite/g++.dg/cpp2a/nontype-class39.C | 12 ++++++++ 5 files changed, 101 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/vt-88982.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction76.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-lambda26.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class39.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C new file mode 100644 index 0000000..2c9d2f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C @@ -0,0 +1,37 @@ +// PR c++/52830 +// { dg-do compile { target c++11 } } +// { dg-ice "comptypes" } + +template struct eif { typedef void type; }; +template<> struct eif {}; + +template struct same +{ + static constexpr bool value = false; +}; +template +struct same +{ + static constexpr bool value = true; +}; + + +struct foo { + template + void func(T && a, + typename eif::value>::type * = 0); +}; + +template +void +foo:: +func(T && a, + typename eif::value>::type * ) +{ +} + +void do_stuff() +{ + foo f; + f.func(12); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-88982.C b/gcc/testsuite/g++.dg/cpp0x/vt-88982.C new file mode 100644 index 0000000..cb9530d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/vt-88982.C @@ -0,0 +1,14 @@ +// PR c++/88982 +// { dg-do compile { target c++11 } } +// { dg-ice "tsubst_pack_expansion" } + +template struct A { + template class ...Cs, Cs ...Vs> struct B { + B() { + } + }; +}; + +template using Int = int; +template using Char = char; +A::B b; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction76.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction76.C new file mode 100644 index 0000000..23bb6e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction76.C @@ -0,0 +1,25 @@ +// PR c++/90799 +// { dg-do compile { target c++17 } } +// { dg-ice "unify" } + +template +void foo() noexcept(T::value); + +struct S { + static constexpr const bool value = true; + + template + void bar() noexcept(T::value); +}; + +template +constexpr bool is_noexcept_function(void(Args...) noexcept(is_noexcept)) noexcept { + return is_noexcept; +} + +template +constexpr bool is_noexcept_member_function(void(S::*)(Args...) noexcept(is_noexcept)) noexcept { + return is_noexcept; +} + +static_assert(is_noexcept_function(foo)); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda26.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda26.C new file mode 100644 index 0000000..d6c8bae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda26.C @@ -0,0 +1,13 @@ +// PR c++/87765 +// { dg-do compile { target c++17 } } +// { dg-ice "cxx_eval_constant_expression" } + +template +using foo = int; + +struct A { + constexpr int bar() const { return 42; } +}; + +void baz(A a) { + [=](auto c) { return foo { }; }; } diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C new file mode 100644 index 0000000..f5f79a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class39.C @@ -0,0 +1,12 @@ +// PR c++/89565 +// { dg-do compile { target c++20 } } +// { dg-ice "resolve_args" } + +template +struct N{}; + +template +struct S {}; + +template +using NS = S; -- cgit v1.1 From 8c0c83feb04d7486ccf9cbe86dcd5668f0a21ef9 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 6 Nov 2020 15:21:13 -0500 Subject: c++: Improve static_assert diagnostic [PR97518] Currently, when a static_assert fails, we only say "static assertion failed". It would be more useful if we could also print the expression that evaluated to false; this is especially useful when the condition uses template parameters. Consider the motivating example, in which we have this line: static_assert(is_same::value); if this fails, the user has to play dirty games to get the compiler to print the template arguments. With this patch, we say: error: static assertion failed note: 'is_same::value' evaluates to false which I think is much better. However, always printing the condition that evaluated to 'false' wouldn't be very useful: e.g. noexcept(fn) is always parsed to true/false, so we would say "'false' evaluates to false" which doesn't help. So I wound up only printing the condition when it was instantiation-dependent, that is, we called finish_static_assert from tsubst_expr. Moreover, this patch also improves the diagnostic when the condition consists of a logical AND. Say you have something like this: static_assert(fn1() && fn2() && fn3() && fn4() && fn5()); where fn4() evaluates to false and the other ones to true. Highlighting the whole thing is not that helpful because it won't say which clause evaluated to false. With the find_failing_clause tweak in this patch we emit: error: static assertion failed 6 | static_assert(fn1() && fn2() && fn3() && fn4() && fn5()); | ~~~^~ so you know right away what's going on. Unfortunately, when you combine both things, that is, have an instantiation-dependent expr and && in a static_assert, we can't yet quite point to the clause that failed. It is because when we tsubstitute something like is_same::value, we generate a VAR_DECL that doesn't have any location. It would be awesome if we could wrap it with a location wrapper, but I didn't see anything obvious. In passing, I've cleaned up some things: * use iloc_sentinel when appropriate, * it's nicer to call contextual_conv_bool instead of the rather verbose perform_implicit_conversion_flags, * no need to check for INTEGER_CST before calling integer_zerop. gcc/cp/ChangeLog: PR c++/97518 * cp-tree.h (finish_static_assert): Adjust declaration. * parser.c (cp_parser_static_assert): Pass false to finish_static_assert. * pt.c (tsubst_expr): Pass true to finish_static_assert. * semantics.c (find_failing_clause_r): New function. (find_failing_clause): New function. (finish_static_assert): Add a bool parameter. Use iloc_sentinel. Call contextual_conv_bool instead of perform_implicit_conversion_flags. Don't check for INTEGER_CST before calling integer_zerop. Call find_failing_clause and maybe use its location. Print the original condition or the failing clause if SHOW_EXPR_P. gcc/testsuite/ChangeLog: PR c++/97518 * g++.dg/diagnostic/pr87386.C: Adjust expected output. * g++.dg/diagnostic/static_assert1.C: New test. * g++.dg/diagnostic/static_assert2.C: New test. libcc1/ChangeLog: PR c++/97518 * libcp1plugin.cc (plugin_add_static_assert): Pass false to finish_static_assert. --- gcc/cp/cp-tree.h | 2 +- gcc/cp/parser.c | 3 +- gcc/cp/pt.c | 6 +- gcc/cp/semantics.c | 73 ++++++++++++++++++++---- gcc/testsuite/g++.dg/diagnostic/pr87386.C | 2 +- gcc/testsuite/g++.dg/diagnostic/static_assert1.C | 30 ++++++++++ gcc/testsuite/g++.dg/diagnostic/static_assert2.C | 68 ++++++++++++++++++++++ 7 files changed, 166 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/static_assert1.C create mode 100644 gcc/testsuite/g++.dg/diagnostic/static_assert2.C (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b98d47a..230a1525 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7234,7 +7234,7 @@ extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, - bool); + bool, bool); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9c08c0e..3632281 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -14886,7 +14886,8 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) /* Complete the static assertion, which may mean either processing the static assert now or saving it for template instantiation. */ - finish_static_assert (condition, message, assert_loc, member_p); + finish_static_assert (condition, message, assert_loc, member_p, + /*show_expr_p=*/false); } /* Parse the expression in decltype ( expression ). */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a2655a0..6ba114c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18492,8 +18492,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, tree condition; ++c_inhibit_evaluation_warnings; - condition = - tsubst_expr (STATIC_ASSERT_CONDITION (t), + condition = + tsubst_expr (STATIC_ASSERT_CONDITION (t), args, complain, in_decl, /*integral_constant_expression_p=*/true); @@ -18502,7 +18502,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, finish_static_assert (condition, STATIC_ASSERT_MESSAGE (t), STATIC_ASSERT_SOURCE_LOCATION (t), - /*member_p=*/false); + /*member_p=*/false, /*show_expr_p=*/true); } break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 33d715e..df698d5 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9827,13 +9827,53 @@ init_cp_semantics (void) { } + +/* If we have a condition in conjunctive normal form (CNF), find the first + failing clause. In other words, given an expression like + + true && true && false && true && false + + return the first 'false'. EXPR is the expression. */ + +static tree +find_failing_clause_r (tree expr) +{ + if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR) + { + /* First check the left side... */ + tree e = find_failing_clause_r (TREE_OPERAND (expr, 0)); + if (e == NULL_TREE) + /* ...if we didn't find a false clause, check the right side. */ + e = find_failing_clause_r (TREE_OPERAND (expr, 1)); + return e; + } + tree e = contextual_conv_bool (expr, tf_none); + e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true); + if (integer_zerop (e)) + /* This is the failing clause. */ + return expr; + return NULL_TREE; +} + +/* Wrapper for find_failing_clause_r. */ + +static tree +find_failing_clause (tree expr) +{ + if (TREE_CODE (expr) != TRUTH_ANDIF_EXPR) + return NULL_TREE; + return find_failing_clause_r (expr); +} + /* Build a STATIC_ASSERT for a static assertion with the condition CONDITION and the message text MESSAGE. LOCATION is the location of the static assertion in the source code. When MEMBER_P, this - static assertion is a member of a class. */ + static assertion is a member of a class. If SHOW_EXPR_P is true, + print the condition (because it was instantiation-dependent). */ + void finish_static_assert (tree condition, tree message, location_t location, - bool member_p) + bool member_p, bool show_expr_p) { tsubst_flags_t complain = tf_warning_or_error; @@ -9871,8 +9911,7 @@ finish_static_assert (tree condition, tree message, location_t location, tree orig_condition = condition; /* Fold the expression and convert it to a boolean value. */ - condition = perform_implicit_conversion_flags (boolean_type_node, condition, - complain, LOOKUP_NORMAL); + condition = contextual_conv_bool (condition, complain); condition = fold_non_dependent_expr (condition, complain, /*manifestly_const_eval=*/true); @@ -9881,21 +9920,32 @@ finish_static_assert (tree condition, tree message, location_t location, ; else { - location_t saved_loc = input_location; + iloc_sentinel ils (location); - input_location = location; - if (TREE_CODE (condition) == INTEGER_CST - && integer_zerop (condition)) + if (integer_zerop (condition)) { int sz = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (message)))); int len = TREE_STRING_LENGTH (message) / sz - 1; + + /* See if we can find which clause was failing (for logical AND). */ + tree bad = find_failing_clause (orig_condition); + /* If not, or its location is unusable, fall back to the previous + location. */ + location_t cloc = location; + if (cp_expr_location (bad) != UNKNOWN_LOCATION) + cloc = cp_expr_location (bad); + /* Report the error. */ if (len == 0) - error ("static assertion failed"); + error_at (cloc, "static assertion failed"); else - error ("static assertion failed: %s", - TREE_STRING_POINTER (message)); + error_at (cloc, "static assertion failed: %s", + TREE_STRING_POINTER (message)); + if (show_expr_p) + inform (cloc, "%qE evaluates to false", + /* Nobody wants to see the artificial (bool) cast. */ + (bad ? tree_strip_nop_conversions (bad) : orig_condition)); /* Actually explain the failure if this is a concept check or a requires-expression. */ @@ -9909,7 +9959,6 @@ finish_static_assert (tree condition, tree message, location_t location, if (require_rvalue_constant_expression (condition)) cxx_constant_value (condition); } - input_location = saved_loc; } } diff --git a/gcc/testsuite/g++.dg/diagnostic/pr87386.C b/gcc/testsuite/g++.dg/diagnostic/pr87386.C index 85726af..679a517 100644 --- a/gcc/testsuite/g++.dg/diagnostic/pr87386.C +++ b/gcc/testsuite/g++.dg/diagnostic/pr87386.C @@ -14,5 +14,5 @@ static_assert (foo::test::value, "foo"); // { dg-error "static assertion f static_assert (foo::test::value && true, "bar"); // { dg-error "static assertion failed: bar" } /* { dg-begin-multiline-output "" } static_assert (foo::test::value && true, "bar"); - ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ + ~~~~~~~~~~~~~~~~^~~~~ { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/g++.dg/diagnostic/static_assert1.C b/gcc/testsuite/g++.dg/diagnostic/static_assert1.C new file mode 100644 index 0000000..fecf3cc --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/static_assert1.C @@ -0,0 +1,30 @@ +// PR c++/97518 +// { dg-do compile { target c++17 } } + +template struct is_same { static constexpr bool value = false; }; +template struct is_same { static constexpr bool value = true; }; + +template using some_metafunction_t = T; + +template +void foo(T ) { + using X = T*; + using Y = some_metafunction_t; + + static_assert(is_same::value); // { dg-error "static assertion failed" } + // { dg-message {.is_same::value. evaluates to false} "" { target *-*-* } .-1 } + static_assert(is_same::value, "foo"); // { dg-error "static assertion failed: foo" } + // { dg-message {.is_same::value. evaluates to false} "" { target *-*-* } .-1 } + static_assert(is_same::value && is_same::value); // { dg-error "static assertion failed" } + // { dg-message {.is_same::value. evaluates to false} "" { target *-*-* } .-1 } + static_assert(is_same::value && is_same::value); // { dg-error "static assertion failed" } + // { dg-message {.is_same::value. evaluates to false} "" { target *-*-* } .-1 } + static_assert(is_same::value + && is_same::value + && is_same::value); // { dg-error "static assertion failed" } + // { dg-message {.is_same::value. evaluates to false} "" { target *-*-* } .-1 } +} + +void bar() { + foo(0); +} diff --git a/gcc/testsuite/g++.dg/diagnostic/static_assert2.C b/gcc/testsuite/g++.dg/diagnostic/static_assert2.C new file mode 100644 index 0000000..542697f --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/static_assert2.C @@ -0,0 +1,68 @@ +// PR c++/97518 +// { dg-do compile { target c++11 } } +// { dg-options "-fdiagnostics-show-caret" } + +constexpr bool yes () { return true; } +constexpr bool no () { return false; } +constexpr bool yay = true; +constexpr bool nay = false; + +void +bar () +{ + static_assert (true && true && no(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (true && true && no(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert (yay && nay, ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (yay && nay, ""); + ^~~ + { dg-end-multiline-output "" } */ + static_assert (yes() && no(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (yes() && no(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert (no() && yes(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (no() && yes(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert (no() && no() && yes(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (no() && no() && yes(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert (yes() && yes() && yes () && no() && yes(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (yes() && yes() && yes () && no() && yes(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert (yes() && yes() && yes () && (no() && yes()), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert (yes() && yes() && yes () && (no() && yes()), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert ((yes() && no()) && no(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert ((yes() && no()) && no(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert ((yes() && no()) && no(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert ((yes() && no()) && no(), ""); + ~~^~ + { dg-end-multiline-output "" } */ + static_assert ((no() || no()) && yes(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert ((no() || no()) && yes(), ""); + ~~~~~~^~~~~~~~ + { dg-end-multiline-output "" } */ + static_assert ((yes() || no()) && no(), ""); // { dg-error "static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert ((yes() || no()) && no(), ""); + ~~^~ + { dg-end-multiline-output "" } */ +} -- cgit v1.1 From 778087e0f54285de1eec5c3bf3657392779b52bf Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 10 Nov 2020 18:26:04 +0100 Subject: IBM Z: Fix bootstrap breakage due to HAVE_TF macro Commit e627cda56865 ("IBM Z: Store long doubles in vector registers when possible") introduced HAVE_TF macro which expands to a logical "or" of HAVE_ constants. Not all of these constants are available in GENERATOR_FILE context, so a hack was used: simply expand to true in this case, because the actual value matters only during compiler runtime and not during generation. However, one aspect of this value matters during generation after all: whether or not it's a constant, which in this case it appears to be. This results in incorrect values in insn-flags.h and broken bootstrap for some configurations. Fix by using a dummy value that is not a constant. gcc/ChangeLog: 2020-11-10 Ilya Leoshkevich * config/s390/s390.h (HAVE_TF): Use opaque value when GENERATOR_FILE is defined. --- gcc/config/s390/s390.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 8c02831..bc579a3 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -1187,8 +1187,9 @@ struct GTY(()) machine_function #define TARGET_INDIRECT_BRANCH_TABLE s390_indirect_branch_table #ifdef GENERATOR_FILE -/* gencondmd.c is built before insn-flags.h. */ -#define HAVE_TF(icode) true +/* gencondmd.c is built before insn-flags.h. Use an arbitrary opaque value + that cannot be optimized away by gen_insn. */ +#define HAVE_TF(icode) TARGET_HARD_FLOAT #else #define HAVE_TF(icode) (HAVE_##icode##_fpr || HAVE_##icode##_vr) #endif -- cgit v1.1 From bb6226419f566bb9f68d9f2dc7d3aca501efaa98 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 11 Nov 2020 00:16:36 +0000 Subject: Daily bump. --- gcc/ChangeLog | 314 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 15 +++ gcc/c-family/ChangeLog | 15 +++ gcc/c/ChangeLog | 18 +++ gcc/cp/ChangeLog | 45 +++++++ gcc/d/ChangeLog | 5 + gcc/fortran/ChangeLog | 28 +++++ gcc/testsuite/ChangeLog | 210 ++++++++++++++++++++++++++++++++ 9 files changed, 651 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7509245..766ce5f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,317 @@ +2020-11-11 Ilya Leoshkevich + + * config/s390/s390.h (HAVE_TF): Use opaque value when + GENERATOR_FILE is defined. + +2020-11-10 Strager Neds + + * cgraph.h (symtab_node::get_section): Constify. + (symtab_node::set_section): Declare new overload. + * symtab.c (symtab_node::set_section): Define new overload. + (symtab_node::copy_visibility_from): Use new overload of + symtab_node::set_section. + (symtab_node::resolve_alias): Same. + * tree.h (set_decl_section_name): Declare new overload. + * tree.c (set_decl_section_name): Define new overload. + * tree-emutls.c (get_emutls_init_templ_addr): Same. + * cgraphclones.c (cgraph_node::create_virtual_clone): Use new + overload of symtab_node::set_section. + (cgraph_node::create_version_clone_with_body): Same. + * trans-mem.c (ipa_tm_create_version): Same. + +2020-11-10 Aldy Hernandez + + * value-range.cc (irange::set): Early exit for poly ints. + +2020-11-10 Tobias Burnus + + * gimplify.c (gimplify_scan_omp_clauses, gimplify_omp_loop): Use 'do' + instead of 'for' in error messages for Fortran. + * omp-low.c (check_omp_nesting_restrictions): Likewise + +2020-11-10 Matthew Malcomson + + * opts.c (control_options_for_live_patching): Reform 'is incompatible + with' error messages to use a standard message with differing format + arguments. + (finish_options): Likewise. + +2020-11-10 Richard Biener + + PR tree-optimization/97769 + * tree-vect-data-refs.c (vect_update_misalignment_for_peel): + Remove assert. + +2020-11-10 Richard Biener + + PR tree-optimization/97780 + * tree-ssa-pre.c (fini_pre): Deal with added basic blocks + when freeing PHI_TRANS_TABLE. + +2020-11-10 Zhiheng Xie + Nannan Zheng + + * config/aarch64/aarch64-simd-builtins.def: Add proper FLAG + for tbl/tbx intrinsics. + +2020-11-10 Chung-Lin Tang + + * gimplify.c (is_or_contains_p): New static helper function. + (omp_target_reorder_clauses): New function. + (gimplify_scan_omp_clauses): Add use of omp_target_reorder_clauses to + reorder clause list according to OpenMP 5.0 rules. Add handling of + GOMP_MAP_ATTACH_DETACH for OpenMP cases. + * omp-low.c (is_omp_target): New static helper function. + (scan_sharing_clauses): Add scan phase handling of GOMP_MAP_ATTACH/DETACH + for OpenMP cases. + (lower_omp_target): Add lowering handling of GOMP_MAP_ATTACH/DETACH for + OpenMP cases. + +2020-11-10 Ilya Leoshkevich + + * config/s390/s390-modes.def (FPRX2): New mode. + * config/s390/s390-protos.h (s390_fma_allowed_p): New function. + * config/s390/s390.c (s390_fma_allowed_p): Likewise. + (s390_build_signbit_mask): Support 128-bit masks. + (print_operand): Support printing the second word of a TFmode + operand as vector register. + (constant_modes): Add FPRX2mode. + (s390_class_max_nregs): Return 1 for TFmode on z14+. + (s390_is_fpr128): New function. + (s390_is_vr128): Likewise. + (s390_can_change_mode_class): Use s390_is_fpr128 and + s390_is_vr128 in order to determine whether mode refers to a FPR + pair or to a VR. + (s390_emit_compare): Force TFmode operands into registers on + z14+. + * config/s390/s390.h (HAVE_TF): New macro. + (EXPAND_MOVTF): New macro. + (EXPAND_TF): Likewise. + * config/s390/s390.md (PFPO_OP_TYPE_FPRX2): PFPO_OP_TYPE_TF + alias. + (ALL): Add FPRX2. + (FP_ALL): Add FPRX2 for z14+, restrict TFmode to z13-. + (FP): Likewise. + (FP_ANYTF): New mode iterator. + (BFP): Add FPRX2 for z14+, restrict TFmode to z13-. + (TD_TF): Likewise. + (xde): Add FPRX2. + (nBFP): Likewise. + (nDFP): Likewise. + (DSF): Likewise. + (DFDI): Likewise. + (SFSI): Likewise. + (DF): Likewise. + (SF): Likewise. + (fT0): Likewise. + (bt): Likewise. + (_d): Likewise. + (HALF_TMODE): Likewise. + (tf_fpr): New mode_attr. + (type): New mode_attr. + (*cmp_ccz_0): Use type instead of mode with fsimp. + (*cmp_ccs_0_fastmath): Likewise. + (*cmptf_ccs): New pattern for wfcxb. + (*cmptf_ccsfps): New pattern for wfkxb. + (mov): Rename to mov. + (signbit2): Rename to signbit2. + (isinf2): Renamed to isinf2. + (*TDC_insn_): Use type instead of mode with fsimp. + (fixuns_trunc2): Rename to + fixuns_trunc2. + (fix_trunctf2): Rename to fix_trunctf2_fpr. + (floatdi2): Rename to floatdi2, use type + instead of mode with itof. + (floatsi2): Rename to floatsi2, use type + instead of mode with itof. + (*floatuns2): Use type instead of mode for + itof. + (floatuns2): Rename to + floatuns2. + (trunctf2): Rename to trunctf2_fpr, use type instead + of mode with fsimp. + (extend2): Rename to + extend2. + (2): Rename to + 2, use type instead of + mode with fsimp. + (rint2): Rename to rint2, use + type instead of mode with fsimp. + (2): Use type instead of mode for + fsimp. + (rint2): Likewise. + (trunc2): Rename to + trunc2. + (trunc2): Rename to + trunc2. + (extend2): Rename to + extend2. + (extend2): Rename to + extend2. + (add3): Rename to add3, use type instead of + mode with fsimp. + (*add3_cc): Use type instead of mode with fsimp. + (*add3_cconly): Likewise. + (sub3): Rename to sub3, use type instead of + mode with fsimp. + (*sub3_cc): Use type instead of mode with fsimp. + (*sub3_cconly): Likewise. + (mul3): Rename to mul3, use type instead of + mode with fsimp. + (fma4): Restrict using s390_fma_allowed_p. + (fms4): Restrict using s390_fma_allowed_p. + (div3): Rename to div3, use type instead of + mode with fdiv. + (neg2): Rename to neg2. + (*neg2_cc): Use type instead of mode with fsimp. + (*neg2_cconly): Likewise. + (*neg2_nocc): Likewise. + (*neg2): Likeiwse. + (abs2): Rename to abs2, use type instead of + mode with fdiv. + (*abs2_cc): Use type instead of mode with fsimp. + (*abs2_cconly): Likewise. + (*abs2_nocc): Likewise. + (*abs2): Likewise. + (*negabs2_cc): Likewise. + (*negabs2_cconly): Likewise. + (*negabs2_nocc): Likewise. + (*negabs2): Likewise. + (sqrt2): Rename to sqrt2, use type instead + of mode with fsqrt. + (cbranch4): Use FP_ANYTF instead of FP. + (copysign3): Rename to copysign3, use type + instead of mode with fsimp. + * config/s390/s390.opt (flag_vx_long_double_fma): New + undocumented option. + * config/s390/vector.md (V_HW): Add TF for z14+. + (V_HW2): Likewise. + (VFT): Likewise. + (VF_HW): Likewise. + (V_128): Likewise. + (tf_vr): New mode_attr. + (tointvec): Add TF. + (mov): Rename to mov. + (movetf): New dispatcher. + (*vec_tf_to_v1tf): Rename to *vec_tf_to_v1tf_fpr, restrict to + z13-. + (*vec_tf_to_v1tf_vr): New pattern for z14+. + (*fprx2_to_tf): Likewise. + (*mov_tf_to_fprx2_0): Likewise. + (*mov_tf_to_fprx2_1): Likewise. + (add3): Rename to add3. + (addtf3): New dispatcher. + (sub3): Rename to sub3. + (subtf3): New dispatcher. + (mul3): Rename to mul3. + (multf3): New dispatcher. + (div3): Rename to div3. + (divtf3): New dispatcher. + (sqrt2): Rename to sqrt2. + (sqrttf2): New dispatcher. + (fma4): Restrict using s390_fma_allowed_p. + (fms4): Likewise. + (neg_fma4): Likewise. + (neg_fms4): Likewise. + (neg2): Rename to neg2. + (negtf2): New dispatcher. + (abs2): Rename to abs2. + (abstf2): New dispatcher. + (floattf2_vr): New forwarder. + (floattf2): New dispatcher. + (floatunstf2_vr): New forwarder. + (floatunstf2): New dispatcher. + (fix_trunctf2_vr): New forwarder. + (fix_trunctf2): New dispatcher. + (fixuns_trunctf2_vr): New forwarder. + (fixuns_trunctf2): New dispatcher. + (2): New pattern. + (tf2): New forwarder. + (rint2): New pattern. + (rinttf2): New forwarder. + (*trunctfdf2_vr): New pattern. + (trunctfdf2_vr): New forwarder. + (trunctfdf2): New dispatcher. + (trunctfsf2_vr): New forwarder. + (trunctfsf2): New dispatcher. + (extenddftf2_vr): New pattern. + (extenddftf2): New dispatcher. + (extendsftf2_vr): New forwarder. + (extendsftf2): New dispatcher. + (signbittf2_vr): New forwarder. + (signbittf2): New dispatchers. + (isinftf2_vr): New forwarder. + (isinftf2): New dispatcher. + * config/s390/vx-builtins.md (*vftci_cconly): Use VF_HW + instead of VECF_HW, add missing constraint, add vw support. + (vftci_intcconly): Use VF_HW instead of VECF_HW. + (*vftci): Rename to vftci, use VF_HW instead of + VECF_HW, and vw support. + (vftci_intcc): Use VF_HW instead of VECF_HW. + +2020-11-10 Eric Botcazou + + * range-op.cc (operator_logical_not::fold_range): Tidy up. + (operator_logical_not::op1_range): Call above method. + (operator_bitwise_not::fold_range): If the type is compatible + with boolean, call op_logical_not.fold_range. + (operator_bitwise_not::op1_range): If the type is compatible + with boolean, call op_logical_not.op1_range. + +2020-11-10 Richard Biener + + * tree-ssa-pre.c (pre_expr_d::value_id): Add. + (constant_value_expressions): Turn into an array of pre_expr. + (get_or_alloc_expr_for_nary): New function. + (get_or_alloc_expr_for_reference): Likewise. + (add_to_value): For constant values only ever add a single + CONSTANT. + (get_expr_value_id): Return the new value_id member. + (vn_valnum_from_value_id): Split out and simplify constant + value id handling. + (get_or_alloc_expr_for_constant): Set the value_id member. + (phi_translate_1): Use get_or_alloc_expr_for_*. + (compute_avail): Likewise. + (bitmap_find_leader): Simplify constant value id handling. + +2020-11-10 Alex Coplan + + * doc/md.texi (Modifiers): Fix grammar in description of + earlyclobber constraint modifier. + +2020-11-10 Jakub Jelinek + + PR tree-optimization/97764 + * tree-ssa-sccvn.c (vn_walk_cb_data::push_partial_def): For + little-endian stores with negative pd.offset, subtract + BITS_PER_UNIT - amnt from size if amnt is non-zero. + +2020-11-10 Richard Biener + + PR tree-optimization/97760 + * tree-vect-loop.c (check_reduction_path): Reject + reduction paths we do not handle in epilogue generation. + +2020-11-10 Aldy Hernandez + + PR tree-optimization/97767 + * value-range.cc (dump_bound_with_infinite_markers): Use + wi::min_value and wi::max_value. + (range_tests_strict_enum): New. + (range_tests): Call range_tests_strict_enum. + * value-range.h (irange::varying_p): Use wi::min_value + and wi::max_value. + (irange::set_varying): Same. + (irange::normalize_min_max): Remove comment. + +2020-11-10 Andrew MacLeod + + PR tree-optimization/97567 + * gimple-range-gori.cc: (gori_compute::logical_combine): False + OR operations should intersect the 2 results. + (gori_compute::compute_logical_operands_in_chain): If def chains + are outside the current basic block, don't follow them. + 2020-11-09 Claudiu Zissulescu * config/arc/arc.c (arc_split_move): Recognize vadd2 instructions. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 2cca29c..bb826fc 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20201110 +20201111 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 44847ed..143f2f8 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,18 @@ +2020-11-10 Martin Liska + + * constraint-manager.cc (constraint_manager::merge): Remove + unused code. + * constraint-manager.h: Likewise. + * program-state.cc (sm_state_map::sm_state_map): Likewise. + (program_state::program_state): Likewise. + (test_sm_state_map): Likewise. + * program-state.h: Likewise. + * region-model-reachability.cc (reachable_regions::reachable_regions): Likewise. + * region-model-reachability.h: Likewise. + * region-model.cc (region_model::handle_unrecognized_call): Likewise. + (region_model::get_reachable_svalues): Likewise. + (region_model::can_merge_with_p): Likewise. + 2020-11-05 David Malcolm PR analyzer/97668 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d2ad058..bef7df3 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,18 @@ +2020-11-10 Jakub Jelinek + + PR c/97748 + * c-common.h (warn_if_unused_value): Add quiet argument defaulted + to false. + * c-warn.c (warn_if_unused_value): Likewise. Pass it down + recursively and just return true instead of warning if it is true. + Handle COMPLEX_EXPR. + +2020-11-10 Chung-Lin Tang + + * c-common.h (c_omp_adjust_map_clauses): New declaration. + * c-omp.c (struct map_clause): Helper type for c_omp_adjust_map_clauses. + (c_omp_adjust_map_clauses): New function. + 2020-11-09 Marek Polacek DR 1914 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 5b0d42c..a16dba4 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,21 @@ +2020-11-10 Strager Neds + + * c-decl.c (merge_decls): Use new overload of + set_decl_section_name. + +2020-11-10 Chung-Lin Tang + + * c-parser.c (c_parser_omp_target_data): Add use of + new c_omp_adjust_map_clauses function. Add GOMP_MAP_ATTACH_DETACH as + handled map clause kind. + (c_parser_omp_target_enter_data): Likewise. + (c_parser_omp_target_exit_data): Likewise. + (c_parser_omp_target): Likewise. + * c-typeck.c (handle_omp_array_sections): Adjust COMPONENT_REF case to + use GOMP_MAP_ATTACH_DETACH map kind for C_ORT_OMP region type. + (c_finish_omp_clauses): Adjust bitmap checks to allow struct decl and + same struct field access to co-exist on OpenMP construct. + 2020-11-07 Martin Uecker * c-parser.c (c_parser_label): Implement mixing of labels and code. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9c36b80..dd0e82e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,48 @@ +2020-11-10 Marek Polacek + + PR c++/97518 + * cp-tree.h (finish_static_assert): Adjust declaration. + * parser.c (cp_parser_static_assert): Pass false to + finish_static_assert. + * pt.c (tsubst_expr): Pass true to finish_static_assert. + * semantics.c (find_failing_clause_r): New function. + (find_failing_clause): New function. + (finish_static_assert): Add a bool parameter. Use + iloc_sentinel. Call contextual_conv_bool instead of + perform_implicit_conversion_flags. Don't check for INTEGER_CST before + calling integer_zerop. Call find_failing_clause and maybe use its + location. Print the original condition or the failing clause if + SHOW_EXPR_P. + +2020-11-10 Strager Neds + + * decl.c (duplicate_decls): Use new overload of + set_decl_section_name. + * method.c (use_thunk): Same. + * optimize.c (maybe_clone_body): Same. + * coroutines.cc (act_des_fn): Same. + +2020-11-10 Jakub Jelinek + + PR c/97748 + * cvt.c (convert_to_void): Check (complain & tf_warning) in the outer + if rather than twice times in the inner one. Use warn_if_unused_value. + Formatting fix. + +2020-11-10 Chung-Lin Tang + + * parser.c (cp_parser_omp_target_data): Add use of + new c_omp_adjust_map_clauses function. Add GOMP_MAP_ATTACH_DETACH as + handled map clause kind. + (cp_parser_omp_target_enter_data): Likewise. + (cp_parser_omp_target_exit_data): Likewise. + (cp_parser_omp_target): Likewise. + * semantics.c (handle_omp_array_sections): Adjust COMPONENT_REF case to + use GOMP_MAP_ATTACH_DETACH map kind for C_ORT_OMP region type. Fix + interaction between reference case and attach/detach. + (finish_omp_clauses): Adjust bitmap checks to allow struct decl and + same struct field access to co-exist on OpenMP construct. + 2020-11-09 Marek Polacek DR 1914 diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index adab9a9..e604f5a 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,8 @@ +2020-11-10 Strager Neds + + * decl.cc (finish_thunk): Use new overload of + set_decl_section_name + 2020-10-27 Iain Buclaw * dmd/MERGE: Merge upstream dmd bec5973b0. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f5c6066..6a023af 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,31 @@ +2020-11-10 Tobias Burnus + + * dump-parse-tree.c (show_omp_clauses): Handle new reduction enums. + * gfortran.h (OMP_LIST_REDUCTION_INSCAN, OMP_LIST_REDUCTION_TASK, + OMP_LIST_IN_REDUCTION, OMP_LIST_TASK_REDUCTION): Add enums. + * openmp.c (enum omp_mask1): Add OMP_CLAUSE_IN_REDUCTION + and OMP_CLAUSE_TASK_REDUCTION. + (gfc_match_omp_clause_reduction): Extend reduction handling; + moved from ... + (gfc_match_omp_clauses): ... here. Add calls to it. + (OMP_TASK_CLAUSES, OMP_TARGET_CLAUSES, OMP_TASKLOOP_CLAUSES): + Add OMP_CLAUSE_IN_REDUCTION. + (gfc_match_omp_taskgroup): Add task_reduction matching. + (resolve_omp_clauses): Update for new reduction clause changes; + remove removed nonmonotonic-schedule restrictions. + (gfc_resolve_omp_parallel_blocks): Add new enums to switch. + * trans-openmp.c (gfc_omp_clause_default_ctor, + gfc_trans_omp_reduction_list, gfc_trans_omp_clauses, + gfc_split_omp_clauses): Handle updated reduction clause. + +2020-11-10 Tobias Burnus + + PR fortran/95847 + * trans-decl.c (gfc_get_symbol_decl): Do not (re)set the location + of an external procedure. + (build_entry_thunks, generate_coarray_init, create_main_function, + gfc_generate_function_code): Use fndecl's location in BIND_EXPR. + 2020-11-09 Tobias Burnus PR fortran/90111 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7f89efa..58726a8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,213 @@ +2020-11-10 Marek Polacek + + PR c++/97518 + * g++.dg/diagnostic/pr87386.C: Adjust expected output. + * g++.dg/diagnostic/static_assert1.C: New test. + * g++.dg/diagnostic/static_assert2.C: New test. + +2020-11-10 Marek Polacek + + PR c++/52830 + PR c++/88982 + PR c++/90799 + PR c++/87765 + PR c++/89565 + * g++.dg/cpp0x/constexpr-52830.C: New test. + * g++.dg/cpp0x/vt-88982.C: New test. + * g++.dg/cpp1z/class-deduction76.C: New test. + * g++.dg/cpp1z/constexpr-lambda26.C: New test. + * g++.dg/cpp2a/nontype-class39.C: New test. + +2020-11-10 Tobias Burnus + + * gfortran.dg/gomp/schedule-modifiers-2.f90: Remove some dg-error. + * gfortran.dg/gomp/reduction4.f90: New test. + * gfortran.dg/gomp/reduction5.f90: New test. + * gfortran.dg/gomp/workshare-reduction-1.f90: New test. + * gfortran.dg/gomp/workshare-reduction-2.f90: New test. + * gfortran.dg/gomp/workshare-reduction-3.f90: New test. + * gfortran.dg/gomp/workshare-reduction-4.f90: New test. + * gfortran.dg/gomp/workshare-reduction-5.f90: New test. + * gfortran.dg/gomp/workshare-reduction-6.f90: New test. + * gfortran.dg/gomp/workshare-reduction-7.f90: New test. + * gfortran.dg/gomp/workshare-reduction-8.f90: New test. + * gfortran.dg/gomp/workshare-reduction-9.f90: New test. + * gfortran.dg/gomp/workshare-reduction-10.f90: New test. + * gfortran.dg/gomp/workshare-reduction-11.f90: New test. + * gfortran.dg/gomp/workshare-reduction-12.f90: New test. + * gfortran.dg/gomp/workshare-reduction-13.f90: New test. + * gfortran.dg/gomp/workshare-reduction-14.f90: New test. + * gfortran.dg/gomp/workshare-reduction-15.f90: New test. + * gfortran.dg/gomp/workshare-reduction-16.f90: New test. + * gfortran.dg/gomp/workshare-reduction-17.f90: New test. + * gfortran.dg/gomp/workshare-reduction-18.f90: New test. + * gfortran.dg/gomp/workshare-reduction-19.f90: New test. + * gfortran.dg/gomp/workshare-reduction-20.f90: New test. + * gfortran.dg/gomp/workshare-reduction-21.f90: New test. + * gfortran.dg/gomp/workshare-reduction-22.f90: New test. + * gfortran.dg/gomp/workshare-reduction-23.f90: New test. + * gfortran.dg/gomp/workshare-reduction-24.f90: New test. + * gfortran.dg/gomp/workshare-reduction-25.f90: New test. + * gfortran.dg/gomp/workshare-reduction-26.f90: New test. + * gfortran.dg/gomp/workshare-reduction-27.f90: New test. + * gfortran.dg/gomp/workshare-reduction-28.f90: New test. + * gfortran.dg/gomp/workshare-reduction-29.f90: New test. + * gfortran.dg/gomp/workshare-reduction-30.f90: New test. + * gfortran.dg/gomp/workshare-reduction-31.f90: New test. + * gfortran.dg/gomp/workshare-reduction-32.f90: New test. + * gfortran.dg/gomp/workshare-reduction-33.f90: New test. + * gfortran.dg/gomp/workshare-reduction-34.f90: New test. + * gfortran.dg/gomp/workshare-reduction-35.f90: New test. + * gfortran.dg/gomp/workshare-reduction-36.f90: New test. + * gfortran.dg/gomp/workshare-reduction-37.f90: New test. + * gfortran.dg/gomp/workshare-reduction-38.f90: New test. + * gfortran.dg/gomp/workshare-reduction-39.f90: New test. + * gfortran.dg/gomp/workshare-reduction-40.f90: New test. + * gfortran.dg/gomp/workshare-reduction-41.f90: New test. + * gfortran.dg/gomp/workshare-reduction-42.f90: New test. + * gfortran.dg/gomp/workshare-reduction-43.f90: New test. + * gfortran.dg/gomp/workshare-reduction-44.f90: New test. + * gfortran.dg/gomp/workshare-reduction-45.f90: New test. + * gfortran.dg/gomp/workshare-reduction-46.f90: New test. + * gfortran.dg/gomp/workshare-reduction-47.f90: New test. + * gfortran.dg/gomp/workshare-reduction-48.f90: New test. + * gfortran.dg/gomp/workshare-reduction-49.f90: New test. + * gfortran.dg/gomp/workshare-reduction-50.f90: New test. + * gfortran.dg/gomp/workshare-reduction-51.f90: New test. + * gfortran.dg/gomp/workshare-reduction-52.f90: New test. + * gfortran.dg/gomp/workshare-reduction-53.f90: New test. + * gfortran.dg/gomp/workshare-reduction-54.f90: New test. + * gfortran.dg/gomp/workshare-reduction-55.f90: New test. + * gfortran.dg/gomp/workshare-reduction-56.f90: New test. + * gfortran.dg/gomp/workshare-reduction-57.f90: New test. + * gfortran.dg/gomp/workshare-reduction-58.f90: New test. + +2020-11-10 Matthew Malcomson + + * c-c++-common/ubsan/sanitize-recover-7.c: Update testcase. + +2020-11-10 Jakub Jelinek + + PR c/97748 + * c-c++-common/Wunused-value-1.c: New test. + +2020-11-10 Richard Biener + + PR tree-optimization/97769 + * gcc.dg/vect/pr97769.c: New testcase. + +2020-11-10 Chung-Lin Tang + + * c-c++-common/gomp/clauses-2.c: Remove dg-error cases now valid. + * gfortran.dg/gomp/map-2.f90: Likewise. + * c-c++-common/gomp/map-5.c: New testcase. + +2020-11-10 Ilya Leoshkevich + + * gcc.target/s390/vector/long-double-callee-abi-scan.c: New test. + * gcc.target/s390/vector/long-double-caller-abi-run.c: New test. + * gcc.target/s390/vector/long-double-caller-abi-scan.c: New test. + * gcc.target/s390/vector/long-double-copysign.c: New test. + * gcc.target/s390/vector/long-double-fprx2-constant.c: New test. + * gcc.target/s390/vector/long-double-from-double.c: New test. + * gcc.target/s390/vector/long-double-from-float.c: New test. + * gcc.target/s390/vector/long-double-from-i16.c: New test. + * gcc.target/s390/vector/long-double-from-i32.c: New test. + * gcc.target/s390/vector/long-double-from-i64.c: New test. + * gcc.target/s390/vector/long-double-from-i8.c: New test. + * gcc.target/s390/vector/long-double-from-u16.c: New test. + * gcc.target/s390/vector/long-double-from-u32.c: New test. + * gcc.target/s390/vector/long-double-from-u64.c: New test. + * gcc.target/s390/vector/long-double-from-u8.c: New test. + * gcc.target/s390/vector/long-double-to-double.c: New test. + * gcc.target/s390/vector/long-double-to-float.c: New test. + * gcc.target/s390/vector/long-double-to-i16.c: New test. + * gcc.target/s390/vector/long-double-to-i32.c: New test. + * gcc.target/s390/vector/long-double-to-i64.c: New test. + * gcc.target/s390/vector/long-double-to-i8.c: New test. + * gcc.target/s390/vector/long-double-to-u16.c: New test. + * gcc.target/s390/vector/long-double-to-u32.c: New test. + * gcc.target/s390/vector/long-double-to-u64.c: New test. + * gcc.target/s390/vector/long-double-to-u8.c: New test. + * gcc.target/s390/vector/long-double-vec-duplicate.c: New test. + * gcc.target/s390/vector/long-double-wf.h: New test. + * gcc.target/s390/vector/long-double-wfaxb.c: New test. + * gcc.target/s390/vector/long-double-wfcxb-0001.c: New test. + * gcc.target/s390/vector/long-double-wfcxb-0111.c: New test. + * gcc.target/s390/vector/long-double-wfcxb-1011.c: New test. + * gcc.target/s390/vector/long-double-wfcxb-1101.c: New test. + * gcc.target/s390/vector/long-double-wfdxb.c: New test. + * gcc.target/s390/vector/long-double-wfixb.c: New test. + * gcc.target/s390/vector/long-double-wfkxb-0111.c: New test. + * gcc.target/s390/vector/long-double-wfkxb-1011.c: New test. + * gcc.target/s390/vector/long-double-wfkxb-1101.c: New test. + * gcc.target/s390/vector/long-double-wflcxb.c: New test. + * gcc.target/s390/vector/long-double-wflpxb.c: New test. + * gcc.target/s390/vector/long-double-wfmaxb-2.c: New test. + * gcc.target/s390/vector/long-double-wfmaxb-3.c: New test. + * gcc.target/s390/vector/long-double-wfmaxb-disabled.c: New test. + * gcc.target/s390/vector/long-double-wfmaxb.c: New test. + * gcc.target/s390/vector/long-double-wfmsxb-disabled.c: New test. + * gcc.target/s390/vector/long-double-wfmsxb.c: New test. + * gcc.target/s390/vector/long-double-wfmxb.c: New test. + * gcc.target/s390/vector/long-double-wfnmaxb-disabled.c: New test. + * gcc.target/s390/vector/long-double-wfnmaxb.c: New test. + * gcc.target/s390/vector/long-double-wfnmsxb-disabled.c: New test. + * gcc.target/s390/vector/long-double-wfnmsxb.c: New test. + * gcc.target/s390/vector/long-double-wfsqxb.c: New test. + * gcc.target/s390/vector/long-double-wfsxb-1.c: New test. + * gcc.target/s390/vector/long-double-wfsxb.c: New test. + * gcc.target/s390/vector/long-double-wftcixb-1.c: New test. + * gcc.target/s390/vector/long-double-wftcixb.c: New test. + +2020-11-10 Eric Botcazou + + * gnat.dg/opt88.adb: New test. + +2020-11-10 David Candler + + * gcc.target/aarch64/advsimd-intrinsics/vqrshrn_high_n.c: Added skip + directive. + * gcc.target/aarch64/advsimd-intrinsics/vqrshrun_high_n.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vqshrn_high_n.c: Likewise. + * gcc.target/aarch64/advsimd-intrinsics/vqshrun_high_n.c: Likewise. + +2020-11-10 Jakub Jelinek + + PR tree-optimization/97764 + * gcc.c-torture/execute/pr97764.c: New test. + +2020-11-10 Tobias Burnus + + PR fortran/95847 + * gfortran.dg/coverage.f90: New test. + +2020-11-10 Richard Biener + + PR tree-optimization/97760 + * gcc.dg/vect/pr97760.c: New testcase. + +2020-11-10 Aldy Hernandez + + * g++.dg/opt/pr97767.C: New test. + +2020-11-10 hongyuw1 + + * gcc.target/i386/keylocker-aesdec128kl.c: Adjust regex patterns. + * gcc.target/i386/keylocker-aesdec256kl.c: Likewise. + * gcc.target/i386/keylocker-aesdecwide128kl.c: Likewise. + * gcc.target/i386/keylocker-aesdecwide256kl.c: Likewise. + * gcc.target/i386/keylocker-aesenc128kl.c: Likewise. + * gcc.target/i386/keylocker-aesencwide128kl.c: Likewise. + * gcc.target/i386/keylocker-aesencwide256kl.c: Likewise. + * gcc.target/i386/keylocker-encodekey128.c: Likewise. + * gcc.target/i386/keylocker-encodekey256.c: Likewise. + * gcc.target/i386/keylocker-aesenc256kl.c: New test. + +2020-11-10 Andrew MacLeod + + * gcc.dg/pr97567-2.c: New. + 2020-11-09 Marek Polacek DR 1914 -- cgit v1.1 From 96fc91785ef1e4d52487e6b29787954d1df042a8 Mon Sep 17 00:00:00 2001 From: David Edelsohn Date: Tue, 10 Nov 2020 19:07:05 -0500 Subject: testsuite: skip zero-scratch-regs on powerpc. These tests are unsupported on PowerPC. gcc/testsuite/ChangeLog: * c-c++-common/zero-scratch-regs-10.c: Skip on powerpc*-*-*. * c-c++-common/zero-scratch-regs-11.c: Skip on powerpc*-*-*. * c-c++-common/zero-scratch-regs-5.c: Skip on powerpc*-*-aix*. * c-c++-common/zero-scratch-regs-8.c: Skip on powerpc*-*-*. * c-c++-common/zero-scratch-regs-9.c: Skip on powerpc*-*-*. --- gcc/testsuite/c-c++-common/zero-scratch-regs-10.c | 2 +- gcc/testsuite/c-c++-common/zero-scratch-regs-11.c | 2 +- gcc/testsuite/c-c++-common/zero-scratch-regs-5.c | 1 + gcc/testsuite/c-c++-common/zero-scratch-regs-8.c | 2 +- gcc/testsuite/c-c++-common/zero-scratch-regs-9.c | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-10.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-10.c index d63a57d..193db8c 100644 --- a/gcc/testsuite/c-c++-common/zero-scratch-regs-10.c +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-10.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-skip-if "not implemented" { powerpc*-*-darwin* } } */ +/* { dg-skip-if "not implemented" { powerpc*-*-* } } */ /* { dg-options "-O2" } */ #include diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-11.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-11.c index 1d8cabb..b04b6a2 100644 --- a/gcc/testsuite/c-c++-common/zero-scratch-regs-11.c +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-11.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-skip-if "not implemented" { powerpc*-*-darwin* } } */ +/* { dg-skip-if "not implemented" { powerpc*-*-* } } */ /* { dg-options "-O2 -fzero-call-used-regs=all" } */ #include "zero-scratch-regs-10.c" diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-5.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-5.c index 26679a4..fde74d8 100644 --- a/gcc/testsuite/c-c++-common/zero-scratch-regs-5.c +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-5.c @@ -1,4 +1,5 @@ /* { dg-do run } */ +/* { dg-skip-if "not implemented" { powerpc*-*-aix* } } */ /* { dg-options "-O2 -fzero-call-used-regs=used" } */ #include "zero-scratch-regs-1.c" diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-8.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-8.c index 7fef0d2..f612a04 100644 --- a/gcc/testsuite/c-c++-common/zero-scratch-regs-8.c +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-8.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-skip-if "not implemented" { powerpc*-*-darwin* } } */ +/* { dg-skip-if "not implemented" { powerpc*-*-* } } */ /* { dg-options "-O2 -fzero-call-used-regs=all-arg" } */ #include "zero-scratch-regs-1.c" diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-9.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-9.c index 1561656..2c63a69 100644 --- a/gcc/testsuite/c-c++-common/zero-scratch-regs-9.c +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-9.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-skip-if "not implemented" { powerpc*-*-darwin* } } */ +/* { dg-skip-if "not implemented" { powerpc*-*-* } } */ /* { dg-options "-O2 -fzero-call-used-regs=all" } */ #include "zero-scratch-regs-1.c" -- cgit v1.1 From 9179d9da39cf6e72ab870647db893ef69316b103 Mon Sep 17 00:00:00 2001 From: Nagaraju Mekala Date: Tue, 10 Nov 2020 17:23:18 -0700 Subject: Update MicroBlaze strings test gcc/testsuite * gcc.target/microblaze/others/strings1.c: Update to include $LC label. --- gcc/testsuite/gcc.target/microblaze/others/strings1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/microblaze/others/strings1.c b/gcc/testsuite/gcc.target/microblaze/others/strings1.c index 7a63faf..efaf3c6 100644 --- a/gcc/testsuite/gcc.target/microblaze/others/strings1.c +++ b/gcc/testsuite/gcc.target/microblaze/others/strings1.c @@ -1,13 +1,14 @@ /* { dg-options "-O3" } */ +/* { dg-final { scan-assembler "\.rodata*" } } */ +/* { dg-final { scan-assembler "addik\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),\\\$LC.*" } } */ +/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),*" } } */ #include -/* { dg-final { scan-assembler "\.rodata*" } } */ extern void somefunc (char *); int testfunc () { char string2[80]; -/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r0,.LC*" } } */ strcpy (string2, "hello"); somefunc (string2); } -- cgit v1.1 From 6b797b651f5e3a8a2867053dbaf4f2a70ed27da0 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Wed, 11 Nov 2020 10:35:04 +0800 Subject: Formatting, there should be a space between PTA_* and (. gcc/ChangeLog * config/i386/i386.h (PTA_MOVDIRI, PTA_MOVDIR64B, PTA_AMX_TILE, PTA_AMX_INT8, PTA_AMX_BF16, PTA_HRESET): Formatting. --- gcc/config/i386/i386.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 5e01fe6..e882977 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2480,17 +2480,17 @@ const wide_int_bitmask PTA_AVX512VP2INTERSECT (0, HOST_WIDE_INT_1U << 9); const wide_int_bitmask PTA_PTWRITE (0, HOST_WIDE_INT_1U << 10); const wide_int_bitmask PTA_AVX512BF16 (0, HOST_WIDE_INT_1U << 11); const wide_int_bitmask PTA_WAITPKG (0, HOST_WIDE_INT_1U << 12); -const wide_int_bitmask PTA_MOVDIRI(0, HOST_WIDE_INT_1U << 13); -const wide_int_bitmask PTA_MOVDIR64B(0, HOST_WIDE_INT_1U << 14); +const wide_int_bitmask PTA_MOVDIRI (0, HOST_WIDE_INT_1U << 13); +const wide_int_bitmask PTA_MOVDIR64B (0, HOST_WIDE_INT_1U << 14); const wide_int_bitmask PTA_ENQCMD (0, HOST_WIDE_INT_1U << 15); const wide_int_bitmask PTA_CLDEMOTE (0, HOST_WIDE_INT_1U << 16); const wide_int_bitmask PTA_SERIALIZE (0, HOST_WIDE_INT_1U << 17); const wide_int_bitmask PTA_TSXLDTRK (0, HOST_WIDE_INT_1U << 18); -const wide_int_bitmask PTA_AMX_TILE(0, HOST_WIDE_INT_1U << 19); -const wide_int_bitmask PTA_AMX_INT8(0, HOST_WIDE_INT_1U << 20); -const wide_int_bitmask PTA_AMX_BF16(0, HOST_WIDE_INT_1U << 21); +const wide_int_bitmask PTA_AMX_TILE (0, HOST_WIDE_INT_1U << 19); +const wide_int_bitmask PTA_AMX_INT8 (0, HOST_WIDE_INT_1U << 20); +const wide_int_bitmask PTA_AMX_BF16 (0, HOST_WIDE_INT_1U << 21); const wide_int_bitmask PTA_UINTR (0, HOST_WIDE_INT_1U << 22); -const wide_int_bitmask PTA_HRESET(0, HOST_WIDE_INT_1U << 23); +const wide_int_bitmask PTA_HRESET (0, HOST_WIDE_INT_1U << 23); const wide_int_bitmask PTA_KL (0, HOST_WIDE_INT_1U << 24); const wide_int_bitmask PTA_WIDEKL (0, HOST_WIDE_INT_1U << 25); -- cgit v1.1 From e79de0682e6cb6fe041a22f81cc65375c8c15bff Mon Sep 17 00:00:00 2001 From: Strager Neds Date: Tue, 10 Nov 2020 20:53:14 -0700 Subject: Refactor section name ref counting gcc/ * symtab.c (symtab_node::set_section_for_node): Extract reference counting logic into ... (retain_section_hash_entry): ... here (new function) and ... (release_section_hash_entry): ... here (new function). --- gcc/symtab.c | 55 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'gcc') diff --git a/gcc/symtab.c b/gcc/symtab.c index 883cc3e..c84259f 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -368,6 +368,36 @@ section_name_hasher::equal (section_hash_entry *n1, const char *name) return n1->name == name || !strcmp (n1->name, name); } +/* Bump the reference count on ENTRY so that it is retained. */ + +static section_hash_entry * +retain_section_hash_entry (section_hash_entry *entry) +{ + entry->ref_count++; + return entry; +} + +/* Drop the reference count on ENTRY and remove it if the reference + count drops to zero. */ + +static void +release_section_hash_entry (section_hash_entry *entry) +{ + if (entry) + { + entry->ref_count--; + if (!entry->ref_count) + { + hashval_t hash = htab_hash_string (entry->name); + section_hash_entry **slot + = symtab->section_hash->find_slot_with_hash (entry->name, + hash, INSERT); + ggc_free (entry); + symtab->section_hash->clear_slot (slot); + } + } +} + /* Add node into symbol table. This function is not used directly, but via cgraph/varpool node creation routines. */ @@ -1609,46 +1639,33 @@ void symtab_node::set_section_for_node (const char *section) { const char *current = get_section (); - section_hash_entry **slot; if (current == section || (current && section && !strcmp (current, section))) return; - if (current) - { - x_section->ref_count--; - if (!x_section->ref_count) - { - hashval_t hash = htab_hash_string (x_section->name); - slot = symtab->section_hash->find_slot_with_hash (x_section->name, - hash, INSERT); - ggc_free (x_section); - symtab->section_hash->clear_slot (slot); - } - x_section = NULL; - } + release_section_hash_entry (x_section); if (!section) { + x_section = NULL; implicit_section = false; return; } if (!symtab->section_hash) symtab->section_hash = hash_table::create_ggc (10); - slot = symtab->section_hash->find_slot_with_hash (section, - htab_hash_string (section), - INSERT); + section_hash_entry **slot = symtab->section_hash->find_slot_with_hash + (section, htab_hash_string (section), INSERT); if (*slot) - x_section = (section_hash_entry *)*slot; + x_section = retain_section_hash_entry (*slot); else { int len = strlen (section); *slot = x_section = ggc_cleared_alloc (); + x_section->ref_count = 1; x_section->name = ggc_vec_alloc (len + 1); memcpy (x_section->name, section, len + 1); } - x_section->ref_count++; } /* Worker for set_section. */ -- cgit v1.1 From 4656461585bfd0b925553995a9d114645f1287d0 Mon Sep 17 00:00:00 2001 From: Strager Neds Date: Tue, 10 Nov 2020 20:57:04 -0700 Subject: Improve efficiency of copying section from another tree gcc/ * cgraph.h (symtab_node::set_section_for_node): Declare new overload. (symtab_node::set_section_from_string): Rename from set_section. (symtab_node::set_section_from_node): Declare. * symtab.c (symtab_node::set_section_for_node): Define new overload. (symtab_node::set_section_from_string): Rename from set_section. (symtab_node::set_section_from_node): Define. (symtab_node::set_section): Call renamed set_section_from_string. (symtab_node::set_section): Call new set_section_from_node. --- gcc/cgraph.h | 9 +++++++-- gcc/symtab.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 2e62db2..97287bd 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -330,6 +330,10 @@ public: use set_section. */ void set_section_for_node (const char *section); + /* Like set_section_for_node, but copying the section name from another + node. */ + void set_section_for_node (const symtab_node &other); + /* Set initialization priority to PRIORITY. */ void set_init_priority (priority_type priority); @@ -646,8 +650,9 @@ protected: void *data, bool include_overwrite); private: - /* Worker for set_section. */ - static bool set_section (symtab_node *n, void *s); + /* Workers for set_section. */ + static bool set_section_from_string (symtab_node *n, void *s); + static bool set_section_from_node (symtab_node *n, void *o); /* Worker for symtab_resolve_alias. */ static bool set_implicit_section (symtab_node *n, void *); diff --git a/gcc/symtab.c b/gcc/symtab.c index c84259f..393d6b0 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1668,15 +1668,37 @@ symtab_node::set_section_for_node (const char *section) } } -/* Worker for set_section. */ +void +symtab_node::set_section_for_node (const symtab_node &other) +{ + if (x_section == other.x_section) + return; + if (get_section () && other.get_section ()) + gcc_checking_assert (strcmp (get_section (), other.get_section ()) != 0); + release_section_hash_entry (x_section); + if (other.x_section) + x_section = retain_section_hash_entry (other.x_section); + else + x_section = NULL; +} + +/* Workers for set_section. */ bool -symtab_node::set_section (symtab_node *n, void *s) +symtab_node::set_section_from_string (symtab_node *n, void *s) { n->set_section_for_node ((char *)s); return false; } +bool +symtab_node::set_section_from_node (symtab_node *n, void *o) +{ + const symtab_node &other = *static_cast (o); + n->set_section_for_node (other); + return false; +} + /* Set section of symbol and its aliases. */ void @@ -1684,15 +1706,14 @@ symtab_node::set_section (const char *section) { gcc_assert (!this->alias || !this->analyzed); call_for_symbol_and_aliases - (symtab_node::set_section, const_cast(section), true); + (symtab_node::set_section_from_string, const_cast(section), true); } void symtab_node::set_section (const symtab_node &other) { - const char *section = other.get_section (); call_for_symbol_and_aliases - (symtab_node::set_section, const_cast(section), true); + (symtab_node::set_section_from_node, const_cast(&other), true); } /* Return the initialization priority. */ -- cgit v1.1 From 693a79a355e13b3cf381d4adebe3fcea2736c8f0 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 11 Nov 2020 15:37:25 +1030 Subject: Re: Refactor copying decl section names * go-gcc.cc (Gcc_backend::global_variable_set_init): Cast NULL to avoid ambiguous overloaded call. --- gcc/go/go-gcc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index ba286fa..d8d9c3f 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -2756,7 +2756,7 @@ Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr) if (symtab_node::get(var_decl) && symtab_node::get(var_decl)->implicit_section) { - set_decl_section_name (var_decl, NULL); + set_decl_section_name (var_decl, (const char *) NULL); resolve_unique_section (var_decl, compute_reloc_for_constant (expr_tree), 1); -- cgit v1.1 From 81372618277bfae682434fcdc80b311ee6007476 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 11 Nov 2020 08:27:38 +0100 Subject: fortran: Fix up gfc_typename CHARACTER length handling [PR97768] The first testcase below ICEs when f951 is 32-bit (or 64-bit big-endian). The problem is that ex->ts.u.cl && ex->ts.u.cl->length are both non-NULL, but ex->ts.u.cl->length->expr_type is not EXPR_CONSTANT, but EXPR_FUNCTION. value.function.actual and value.function.name are in that case pointers, but value._mp_alloc and value._mp_size are 4 byte integers no matter what. So, in 64-bit little-endian the function returns most of the time incorrect CHARACTER(0) because the most significant 32 bits of the value.function.actual pointer are likely 0. Anyway, the following patch is an attempt to get all the cases right. Uses ex->value.character.length only for ex->expr_type == EXPR_CONSTANT (i.e. CHARACTER literals), handles the deferred lengths, assumed lengths, known constant lengths and finally if the length is something other, just doesn't print it, i.e. prints just CHARACTER (for default kind) or CHARACTER(KIND=4) (for e.g. kind 4). 2020-11-11 Jakub Jelinek PR fortran/97768 gcc/fortran/ * misc.c (gfc_typename): Use ex->value.character.length only if ex->expr_type == EXPR_CONSTANT. If ex->ts.deferred, print : instead of length. If ex->ts.u.cl && ex->ts.u.cl->length == NULL, print * instead of length. Otherwise if character length is non-constant, print just CHARACTER or CHARACTER(KIND=N). gcc/testsuite/ * gfortran.dg/pr97768_1.f90: New test. * gfortran.dg/pr97768_2.f90: New test. --- gcc/fortran/misc.c | 28 +++++++++++++++-- gcc/testsuite/gfortran.dg/pr97768_1.f90 | 25 ++++++++++++++++ gcc/testsuite/gfortran.dg/pr97768_2.f90 | 53 +++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr97768_1.f90 create mode 100644 gcc/testsuite/gfortran.dg/pr97768_2.f90 (limited to 'gcc') diff --git a/gcc/fortran/misc.c b/gcc/fortran/misc.c index 65bcfa6..e9b87aa 100644 --- a/gcc/fortran/misc.c +++ b/gcc/fortran/misc.c @@ -224,10 +224,32 @@ gfc_typename (gfc_expr *ex) if (ex->ts.type == BT_CHARACTER) { - if (ex->ts.u.cl && ex->ts.u.cl->length) - length = gfc_mpz_get_hwi (ex->ts.u.cl->length->value.integer); - else + if (ex->expr_type == EXPR_CONSTANT) length = ex->value.character.length; + else if (ex->ts.deferred) + { + if (ex->ts.kind == gfc_default_character_kind) + return "CHARACTER(:)"; + sprintf (buffer, "CHARACTER(:,%d)", ex->ts.kind); + return buffer; + } + else if (ex->ts.u.cl && ex->ts.u.cl->length == NULL) + { + if (ex->ts.kind == gfc_default_character_kind) + return "CHARACTER(*)"; + sprintf (buffer, "CHARACTER(*,%d)", ex->ts.kind); + return buffer; + } + else if (ex->ts.u.cl == NULL + || ex->ts.u.cl->length->expr_type != EXPR_CONSTANT) + { + if (ex->ts.kind == gfc_default_character_kind) + return "CHARACTER"; + sprintf (buffer, "CHARACTER(KIND=%d)", ex->ts.kind); + return buffer; + } + else + length = gfc_mpz_get_hwi (ex->ts.u.cl->length->value.integer); if (ex->ts.kind == gfc_default_character_kind) sprintf (buffer, "CHARACTER(" HOST_WIDE_INT_PRINT_DEC ")", length); else diff --git a/gcc/testsuite/gfortran.dg/pr97768_1.f90 b/gcc/testsuite/gfortran.dg/pr97768_1.f90 new file mode 100644 index 0000000..fce01e3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr97768_1.f90 @@ -0,0 +1,25 @@ +! PR fortran/97768 +! { dg-do compile } + +module pr97768_1 + interface operator(.in.) + module procedure substr_in_str + end interface +contains + pure function to_upper (in_str) result (string) + character(len=*), intent(in) :: in_str + character(len=len(in_str)) :: string + string = in_str + end function to_upper + logical pure function substr_in_str (substring, string) + character(len=*), intent(in) :: string, substring + substr_in_str=.false. + end function +end module +function foo () + use pr97768_1, only : to_upper, operator(.in.) + logical :: foo + character(len=8) :: str + str = 'abcde' + foo = 'b' .in. to_upper (str) +end function foo diff --git a/gcc/testsuite/gfortran.dg/pr97768_2.f90 b/gcc/testsuite/gfortran.dg/pr97768_2.f90 new file mode 100644 index 0000000..5dc1987 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr97768_2.f90 @@ -0,0 +1,53 @@ +! PR fortran/97768 +! { dg-do compile } + +module pr97768_2 + interface operator(.in.) + module procedure substr_in_str + end interface +contains + pure function to_upper (in_str) result (string) + character(len=*), intent(in) :: in_str + character(len=len(in_str)) :: string + string = in_str + end function to_upper + logical pure function substr_in_str (substring, string) + character(len=*), intent(in) :: string, substring + substr_in_str=.false. + end function +end module +function foo () + use pr97768_2, only : to_upper, operator(.in.) + logical :: foo + character(len=8) :: str + str = 'abcde' + foo = to_upper (str) .in. 32 ! { dg-error "are CHARACTER/INTEGER" } +end function foo +function bar (str) + use pr97768_2, only : operator(.in.) + logical :: bar + character(len=*) :: str + foo = str .in. 32 ! { dg-error "are CHARACTER\\(\\*\\)/INTEGER" } +end function bar +function baz (lenstr) + use pr97768_2, only : operator(.in.) + logical :: baz + integer :: lenstr + character(len=lenstr) :: str + str = 'abc' + foo = str .in. 32 ! { dg-error "are CHARACTER/INTEGER" } +end function baz +function qux () + use pr97768_2, only : operator(.in.) + logical :: qux + character(len=8) :: str + str = 'def' + foo = str .in. 32 ! { dg-error "are CHARACTER\\(8\\)/INTEGER" } +end function qux +function corge () + use pr97768_2, only : operator(.in.) + logical :: corge + character(len=:), allocatable :: str + str = 'ghijk' + foo = str .in. 32 ! { dg-error "are CHARACTER\\(:\\)/INTEGER" } +end function corge -- cgit v1.1 From 1644ab9917ca6b96e9e683c422f1793258b9a3db Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 11 Nov 2020 09:23:07 +0100 Subject: gfortran.dg/gomp/workshare-reduction-*.f90: Fix dumps for -m32 gcc/testsuite/ChangeLog: * gfortran.dg/gomp/workshare-reduction-26.f90: Add (?:_ull) to scan-tree-dump-times regex for -m32. * gfortran.dg/gomp/workshare-reduction-27.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-28.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-3.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-36.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-37.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-38.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-39.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-40.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-41.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-42.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-43.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-44.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-45.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-46.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-47.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-56.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-57.f90: Likewise. --- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 | 8 ++++---- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 | 8 ++++---- 18 files changed, 40 insertions(+), 40 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 index 2826790..d8633b6 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 0, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 0, 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_maybe_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_maybe_nonmonotonic_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 index 2ee047d..aada4d7 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 index 6c9d49b..e67e24b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 4, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 4, 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 index 6c9d49b..e67e24b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 4, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 4, 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 index b190e9e..82dc063 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 index c541d22..4fb64cf 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 index 46a27a0..08eaef0 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 index 6cdd9a8..732753c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 index 29da27a..44ecfa8 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 index 4ed879c..a8b9912 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 index 78d02ef..c6709e3 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 index 16885c8..3cb0a66 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 index 0db9be6..3a4867f 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 index 40b1275..1252ffc 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 index 57c7402..bf19198 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 index b456430..d2b03f6 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 index dc5ddaf..fb6175c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 @@ -1,10 +1,10 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_doacross_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_static_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_static_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 index 8042488..41b55ea 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 @@ -1,10 +1,10 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_doacross_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } -- cgit v1.1 From 7a9a5d1a61c7b8111557261a8d275a531812b50e Mon Sep 17 00:00:00 2001 From: zhengnannan Date: Wed, 11 Nov 2020 10:37:20 +0000 Subject: AArch64: Add FLAG for arithmetic operation intrinsics [PR94442] 2020-11-11 Zhiheng Xie Nannan Zheng gcc/ChangeLog: * config/aarch64/aarch64-simd-builtins.def: Add proper FLAG for arithmetic operation intrinsics. --- gcc/config/aarch64/aarch64-simd-builtins.def | 44 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-simd-builtins.def b/gcc/config/aarch64/aarch64-simd-builtins.def index cb05aad..b70056a 100644 --- a/gcc/config/aarch64/aarch64-simd-builtins.def +++ b/gcc/config/aarch64/aarch64-simd-builtins.def @@ -47,7 +47,7 @@ VAR1 (COMBINEP, combine, 0, ALL, di) BUILTIN_VB (BINOP, pmul, 0, NONE) BUILTIN_VHSDF_HSDF (BINOP, fmulx, 0, FP) - BUILTIN_VHSDF_DF (UNOP, sqrt, 2, ALL) + BUILTIN_VHSDF_DF (UNOP, sqrt, 2, FP) BUILTIN_VD_BHSI (BINOP, addp, 0, NONE) VAR1 (UNOP, addp, 0, NONE, di) BUILTIN_VDQ_BHSI (UNOP, clrsb, 2, ALL) @@ -229,9 +229,9 @@ BUILTIN_VSDQ_I_DI (BINOP_UUS, urshl, 0, ALL) /* Implemented by aarch64_{_lane}{q}. */ - BUILTIN_VB (TERNOP, sdot, 0, ALL) - BUILTIN_VB (TERNOPU, udot, 0, ALL) - BUILTIN_VB (TERNOP_SSUS, usdot, 0, ALL) + BUILTIN_VB (TERNOP, sdot, 0, NONE) + BUILTIN_VB (TERNOPU, udot, 0, NONE) + BUILTIN_VB (TERNOP_SSUS, usdot, 0, NONE) BUILTIN_VB (QUADOP_LANE, sdot_lane, 0, ALL) BUILTIN_VB (QUADOPU_LANE, udot_lane, 0, ALL) BUILTIN_VB (QUADOP_LANE, sdot_laneq, 0, ALL) @@ -304,7 +304,7 @@ BUILTIN_VSDQ_I (USHIFTIMM, uqshl_n, 0, ALL) /* Implemented by aarch64_reduc_plus_. */ - BUILTIN_VALL (UNOP, reduc_plus_scal_, 10, ALL) + BUILTIN_VALL (UNOP, reduc_plus_scal_, 10, NONE) /* Implemented by reduc__scal_ (producing scalar). */ BUILTIN_VDQIF_F16 (UNOP, reduc_smax_scal_, 10, NONE) @@ -462,19 +462,19 @@ BUILTIN_VALL (BINOP, trn1, 0, ALL) BUILTIN_VALL (BINOP, trn2, 0, ALL) - BUILTIN_GPF_F16 (UNOP, frecpe, 0, ALL) - BUILTIN_GPF_F16 (UNOP, frecpx, 0, ALL) + BUILTIN_GPF_F16 (UNOP, frecpe, 0, FP) + BUILTIN_GPF_F16 (UNOP, frecpx, 0, FP) - BUILTIN_VDQ_SI (UNOP, urecpe, 0, ALL) + BUILTIN_VDQ_SI (UNOP, urecpe, 0, NONE) - BUILTIN_VHSDF (UNOP, frecpe, 0, ALL) - BUILTIN_VHSDF_HSDF (BINOP, frecps, 0, ALL) + BUILTIN_VHSDF (UNOP, frecpe, 0, FP) + BUILTIN_VHSDF_HSDF (BINOP, frecps, 0, FP) /* Implemented by a mixture of abs2 patterns. Note the DImode builtin is only ever used for the int64x1_t intrinsic, there is no scalar version. */ - BUILTIN_VSDQ_I_DI (UNOP, abs, 0, ALL) - BUILTIN_VHSDF (UNOP, abs, 2, ALL) - VAR1 (UNOP, abs, 2, ALL, hf) + BUILTIN_VSDQ_I_DI (UNOP, abs, 0, AUTO_FP) + BUILTIN_VHSDF (UNOP, abs, 2, AUTO_FP) + VAR1 (UNOP, abs, 2, AUTO_FP, hf) BUILTIN_VQ_HSF (UNOP, vec_unpacks_hi_, 10, FP) VAR1 (BINOP, float_truncate_hi_, 0, FP, v4sf) @@ -508,11 +508,11 @@ BUILTIN_VALLDIF (STORESTRUCT, st1x4, 0, STORE) /* Implemented by fma4. */ - BUILTIN_VHSDF (TERNOP, fma, 4, ALL) - VAR1 (TERNOP, fma, 4, ALL, hf) + BUILTIN_VHSDF (TERNOP, fma, 4, FP) + VAR1 (TERNOP, fma, 4, FP, hf) /* Implemented by fnma4. */ - BUILTIN_VHSDF (TERNOP, fnma, 4, ALL) - VAR1 (TERNOP, fnma, 4, ALL, hf) + BUILTIN_VHSDF (TERNOP, fnma, 4, FP) + VAR1 (TERNOP, fnma, 4, FP, hf) /* Implemented by aarch64_simd_bsl. */ BUILTIN_VDQQH (BSL_P, simd_bsl, 0, ALL) @@ -595,13 +595,13 @@ BUILTIN_GPI (SHIFTIMM_USS, fcvtzuhf, 3, ALL) /* Implemented by aarch64_rsqrte. */ - BUILTIN_VHSDF_HSDF (UNOP, rsqrte, 0, ALL) + BUILTIN_VHSDF_HSDF (UNOP, rsqrte, 0, FP) /* Implemented by aarch64_rsqrts. */ - BUILTIN_VHSDF_HSDF (BINOP, rsqrts, 0, ALL) + BUILTIN_VHSDF_HSDF (BINOP, rsqrts, 0, FP) /* Implemented by fabd3. */ - BUILTIN_VHSDF_HSDF (BINOP, fabd, 3, ALL) + BUILTIN_VHSDF_HSDF (BINOP, fabd, 3, FP) /* Implemented by aarch64_faddp. */ BUILTIN_VHSDF (BINOP, faddp, 0, FP) @@ -623,7 +623,7 @@ BUILTIN_VHSDF_HSDF (BINOP_USS, facge, 0, FP) /* Implemented by sqrt2. */ - VAR1 (UNOP, sqrt, 2, ALL, hf) + VAR1 (UNOP, sqrt, 2, FP, hf) /* Implemented by hf2. */ VAR1 (UNOP, floatdi, 2, FP, hf) @@ -714,7 +714,7 @@ BUILTIN_VSFDF (UNOP, frint64x, 0, FP) /* Implemented by aarch64_bfdot{_lane}{q}. */ - VAR2 (TERNOP, bfdot, 0, ALL, v2sf, v4sf) + VAR2 (TERNOP, bfdot, 0, AUTO_FP, v2sf, v4sf) VAR2 (QUADOP_LANE_PAIR, bfdot_lane, 0, ALL, v2sf, v4sf) VAR2 (QUADOP_LANE_PAIR, bfdot_laneq, 0, ALL, v2sf, v4sf) -- cgit v1.1 From c76c23a0da27f6a5583490893b82a82002691a90 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 11 Nov 2020 09:05:32 +0100 Subject: Early exit on VR_VARYING from irange::set. gcc/ChangeLog: * value-range.cc (irange::set): Early exit on VR_VARYING. --- gcc/value-range.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index b7ccba0..2b82dfe 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -249,7 +249,9 @@ irange::set (tree min, tree max, value_range_kind kind) return; } - if (POLY_INT_CST_P (min) || POLY_INT_CST_P (max)) + if (kind == VR_VARYING + || POLY_INT_CST_P (min) + || POLY_INT_CST_P (max)) { set_varying (TREE_TYPE (min)); return; -- cgit v1.1 From 57f076655eaaa03ae4b63408e25438d3caa20b4d Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Nov 2020 10:18:47 +0100 Subject: Drop topological sort for PRE phi-translation The topological sort sorted_array_from_bitmap_set is supposed to provide isn't one since quite some time since value_ids are assigned first to SSA names in the order of SSA_NAME_VERSION and then to hashtable entries in the order they appear in the table. One can even argue that expression-ids provide a closer approximation of a topological sort since those are assigned during AVAIL_OUT computation which is done in a dominator walk. Now - phi-translation is not even depending on topological sorting but it essentially does a DFS walk, phi-translating expressions it depends on and relying on phi-translation caching to avoid doing redundant work. So this patch drops the use of sorted_array_from_bitmap_set from phi_translate_set because this function is quite expensive. 2020-11-11 Richard Biener * tree-ssa-pre.c (phi_translate_set): Do not sort the expression set topologically. --- gcc/tree-ssa-pre.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 90877e3..da2b689 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -1762,9 +1762,8 @@ phi_translate (bitmap_set_t dest, pre_expr expr, static void phi_translate_set (bitmap_set_t dest, bitmap_set_t set, edge e) { - vec exprs; - pre_expr expr; - int i; + bitmap_iterator bi; + unsigned int i; if (gimple_seq_empty_p (phi_nodes (e->dest))) { @@ -1772,24 +1771,22 @@ phi_translate_set (bitmap_set_t dest, bitmap_set_t set, edge e) return; } - exprs = sorted_array_from_bitmap_set (set); /* Allocate the phi-translation cache where we have an idea about its size. hash-table implementation internals tell us that allocating the table to fit twice the number of elements will make sure we do not usually re-allocate. */ if (!PHI_TRANS_TABLE (e->src)) - PHI_TRANS_TABLE (e->src) - = new hash_table (2 * exprs.length ()); - FOR_EACH_VEC_ELT (exprs, i, expr) + PHI_TRANS_TABLE (e->src) = new hash_table + (2 * bitmap_count_bits (&set->expressions)); + FOR_EACH_EXPR_ID_IN_SET (set, i, bi) { - pre_expr translated; - translated = phi_translate (dest, expr, set, NULL, e); + pre_expr expr = expression_for_id (i); + pre_expr translated = phi_translate (dest, expr, set, NULL, e); if (!translated) continue; bitmap_insert_into_set (dest, translated); } - exprs.release (); } /* Find the leader for a value (i.e., the name representing that -- cgit v1.1 From fbb3e275ab0ddbe1413b7f18fc25249fdb46a275 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 11 Nov 2020 11:59:02 +0100 Subject: Fix spelling. gcc/ChangeLog: * tree.c (copy_node): Fix spelling. --- gcc/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree.c b/gcc/tree.c index 663f3ec..1d4a1da 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1241,7 +1241,7 @@ copy_node (tree node MEM_STAT_DECL) SET_DECL_VALUE_EXPR (t, DECL_VALUE_EXPR (node)); DECL_HAS_VALUE_EXPR_P (t) = 1; } - /* DECL_DEBUG_EXPR is copied explicitely by callers. */ + /* DECL_DEBUG_EXPR is copied explicitly by callers. */ if (VAR_P (node)) { DECL_HAS_DEBUG_EXPR_P (t) = 0; -- cgit v1.1 From ca813880dcaae71f664d8f386b1a584cfefbbd4b Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 10 Nov 2020 13:01:32 +0800 Subject: Support Intel AVX VNNI 2020-10-13 Hongtao Liu Hongyu Wang gcc/ * common/config/i386/cpuinfo.h (get_available_features): Detect AVXVNNI. * common/config/i386/i386-common.c (OPTION_MASK_ISA2_AVXVNNI_SET, OPTION_MASK_ISA2_AVXVNNI_UNSET): New. (OPTION_MASK_ISA2_AVX2_UNSET): Add AVXVNNI. (ix86_hanlde_option): Handle -mavxvnni, unset avxvnni when avx2 is disabled. * common/config/i386/i386-cpuinfo.h (enum processor_features): Add FEATURE_AVXVNNI. * common/config/i386/i386-isas.h: Add ISA_NAMES_TABLE_ENTRY for avxvnni. * config.gcc: Add avxvnniintrin.h. * config/i386/avx512vnnivlintrin.h: Reimplement 128/256 bit non-mask intrinsics with macros to support unified interface. * config/i386/avxvnniintrin.h: New header file. * config/i386/cpuid.h (bit_AVXVNNI): New. * config/i386/i386-builtins.c (def_builtin): Handle AVXVNNI mask for unified builtin. * config/i386/i386-builtin.def (BDESC): Adjust AVX512VNNI builtins for AVXVNNI. * config/i386/i386-c.c (ix86_target_macros_internal): Define __AVXVNNI__. * config/i386/i386-expand.c (ix86_expand_builtin): Handle bisa for AVXVNNI to support unified intrinsic name, since there is no dependency between AVX512VNNI and AVXVNNI. * config/i386/i386-options.c (isa2_opts): Add -mavxvnni. (ix86_valid_target_attribute_inner_p): Handle avxnnni. (ix86_option_override_internal): Ditto. * config/i386/i386.h (TARGET_AVXVNNI, TARGET_AVXVNNI_P, TARGET_AVXVNNI_P, PTA_AVXVNNI): New. (PTA_SAPPHIRERAPIDS): Add AVX_VNNI. (PTA_ALDERLAKE): Likewise. * config/i386/i386.md ("isa"): Add avxvnni, avx512vnnivl. ("enabled"): Adjust for avxvnni and avx512vnnivl. * config/i386/i386.opt: Add option -mavxvnni. * config/i386/immintrin.h: Include avxvnniintrin.h. * config/i386/sse.md (vpdpbusd_): Adjust for AVXVNNI. (vpdpbusds_): Likewise. (vpdpwssd_): Likewise. (vpdpwssds_): Likewise. (vpdpbusd_v16si): New. (vpdpbusds_v16si): Likewise. (vpdpwssd_v16si): Likewise. (vpdpwssds_v16si): Likewise. * doc/invoke.texi: Document -mavxvnni. * doc/extend.texi: Document avxvnni. * doc/sourcebuild.texi: Document target avxvnni. gcc/testsuite/ * gcc.target/i386/avx512vl-vnni-1.c: Rename.. * gcc.target/i386/avx512vl-vnni-1a.c: To This. * gcc.target/i386/avx512vl-vnni-1b.c: New test. * gcc.target/i386/avx512vl-vnni-2.c: Ditto. * gcc.target/i386/avx512vl-vnni-3.c: Ditto. * gcc.target/i386/avx-vnni-1.c: Ditto. * gcc.target/i386/avx-vnni-2.c: Ditto. * gcc.target/i386/avx-vnni-3.c: Ditto. * gcc.target/i386/avx-vnni-4.c: Ditto. * gcc.target/i386/avx-vnni-5.c: Ditto. * gcc.target/i386/avx-vnni-6.c: Ditto. * gcc.target/i386/avx-vpdpbusd-2.c: Ditto. * gcc.target/i386/avx-vpdpbusds-2.c: Ditto. * gcc.target/i386/avx-vpdpwssd-2.c: Ditto. * gcc.target/i386/avx-vpdpwssds-2.c: Ditto. * gcc.target/i386/vnni_inline_error.c: Ditto. * gcc.target/i386/avx512vnnivl-builtin.c: Ditto. * gcc.target/i386/avxvnni-builtin.c: Ditto. * gcc.target/i386/funcspec-56.inc: Add new target attribute. * gcc.target/i386/sse-12.c: Add -mavxvnni. * gcc.target/i386/sse-13.c: Ditto. * gcc.target/i386/sse-14.c: Ditto. * gcc.target/i386/sse-22.c: Ditto. * gcc.target/i386/sse-23.c: Ditto. * g++.dg/other/i386-2.C: Ditto. * g++.dg/other/i386-3.C: Ditto. * lib/target-supports.exp (check_effective_target_avxvnni): New proc. --- gcc/common/config/i386/cpuinfo.h | 2 + gcc/common/config/i386/i386-common.c | 20 +++- gcc/common/config/i386/i386-cpuinfo.h | 1 + gcc/common/config/i386/i386-isas.h | 1 + gcc/config.gcc | 4 +- gcc/config/i386/avx512vnnivlintrin.h | 88 ++++++---------- gcc/config/i386/avxvnniintrin.h | 113 ++++++++++++++++++++ gcc/config/i386/cpuid.h | 1 + gcc/config/i386/i386-builtin.def | 18 ++-- gcc/config/i386/i386-builtins.c | 4 + gcc/config/i386/i386-c.c | 2 + gcc/config/i386/i386-expand.c | 13 +++ gcc/config/i386/i386-options.c | 8 +- gcc/config/i386/i386.h | 7 +- gcc/config/i386/i386.md | 5 +- gcc/config/i386/i386.opt | 5 + gcc/config/i386/immintrin.h | 2 + gcc/config/i386/sse.md | 117 +++++++++++++++------ gcc/doc/extend.texi | 5 + gcc/doc/invoke.texi | 11 +- gcc/doc/sourcebuild.texi | 3 + gcc/testsuite/g++.dg/other/i386-2.C | 2 +- gcc/testsuite/g++.dg/other/i386-3.C | 2 +- gcc/testsuite/gcc.target/i386/avx-vnni-1.c | 29 +++++ gcc/testsuite/gcc.target/i386/avx-vnni-2.c | 30 ++++++ gcc/testsuite/gcc.target/i386/avx-vnni-3.c | 16 +++ gcc/testsuite/gcc.target/i386/avx-vnni-4.c | 16 +++ gcc/testsuite/gcc.target/i386/avx-vnni-5.c | 29 +++++ gcc/testsuite/gcc.target/i386/avx-vnni-6.c | 29 +++++ gcc/testsuite/gcc.target/i386/avx-vpdpbusd-2.c | 74 +++++++++++++ gcc/testsuite/gcc.target/i386/avx-vpdpbusds-2.c | 74 +++++++++++++ gcc/testsuite/gcc.target/i386/avx-vpdpwssd-2.c | 70 ++++++++++++ gcc/testsuite/gcc.target/i386/avx-vpdpwssds-2.c | 70 ++++++++++++ gcc/testsuite/gcc.target/i386/avx512vl-vnni-1.c | 69 ------------ gcc/testsuite/gcc.target/i386/avx512vl-vnni-1a.c | 69 ++++++++++++ gcc/testsuite/gcc.target/i386/avx512vl-vnni-1b.c | 69 ++++++++++++ gcc/testsuite/gcc.target/i386/avx512vl-vnni-2.c | 30 ++++++ gcc/testsuite/gcc.target/i386/avx512vl-vnni-3.c | 47 +++++++++ .../gcc.target/i386/avx512vnnivl-builtin.c | 8 ++ gcc/testsuite/gcc.target/i386/avxvnni-builtin.c | 8 ++ gcc/testsuite/gcc.target/i386/funcspec-56.inc | 2 + gcc/testsuite/gcc.target/i386/sse-12.c | 2 +- gcc/testsuite/gcc.target/i386/sse-13.c | 2 +- gcc/testsuite/gcc.target/i386/sse-14.c | 2 +- gcc/testsuite/gcc.target/i386/sse-22.c | 4 +- gcc/testsuite/gcc.target/i386/sse-23.c | 2 +- gcc/testsuite/gcc.target/i386/vnni_inline_error.c | 13 +++ gcc/testsuite/lib/target-supports.exp | 12 +++ 48 files changed, 1025 insertions(+), 185 deletions(-) create mode 100644 gcc/config/i386/avxvnniintrin.h create mode 100644 gcc/testsuite/gcc.target/i386/avx-vnni-1.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vnni-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vnni-3.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vnni-4.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vnni-5.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vnni-6.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vpdpbusd-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vpdpbusds-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vpdpwssd-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx-vpdpwssds-2.c delete mode 100644 gcc/testsuite/gcc.target/i386/avx512vl-vnni-1.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512vl-vnni-1a.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512vl-vnni-1b.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512vl-vnni-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512vl-vnni-3.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512vnnivl-builtin.c create mode 100644 gcc/testsuite/gcc.target/i386/avxvnni-builtin.c create mode 100644 gcc/testsuite/gcc.target/i386/vnni_inline_error.c (limited to 'gcc') diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h index 7a93e17..41728a2 100644 --- a/gcc/common/config/i386/cpuinfo.h +++ b/gcc/common/config/i386/cpuinfo.h @@ -713,6 +713,8 @@ get_available_features (struct __processor_model *cpu_model, set_feature (FEATURE_AVX512BF16); if (eax & bit_HRESET) set_feature (FEATURE_HRESET); + if (eax & bit_AVXVNNI) + set_feature (FEATURE_AVXVNNI); } } diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c index e29320d..8f809c1 100644 --- a/gcc/common/config/i386/i386-common.c +++ b/gcc/common/config/i386/i386-common.c @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see (OPTION_MASK_ISA_AVX512VBMI2 | OPTION_MASK_ISA_AVX512F_SET) #define OPTION_MASK_ISA_AVX512VNNI_SET \ (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512F_SET) +#define OPTION_MASK_ISA2_AVXVNNI_SET OPTION_MASK_ISA2_AVXVNNI #define OPTION_MASK_ISA_AVX512VPOPCNTDQ_SET \ (OPTION_MASK_ISA_AVX512VPOPCNTDQ | OPTION_MASK_ISA_AVX512F_SET) #define OPTION_MASK_ISA_AVX512BITALG_SET \ @@ -206,6 +207,8 @@ along with GCC; see the file COPYING3. If not see #define OPTION_MASK_ISA_XSAVEOPT_UNSET OPTION_MASK_ISA_XSAVEOPT #define OPTION_MASK_ISA_AVX2_UNSET \ (OPTION_MASK_ISA_AVX2 | OPTION_MASK_ISA_AVX512F_UNSET) +#define OPTION_MASK_ISA2_AVX2_UNSET \ + (OPTION_MASK_ISA2_AVXVNNI_UNSET | OPTION_MASK_ISA2_AVX512F_UNSET) #define OPTION_MASK_ISA_AVX512F_UNSET \ (OPTION_MASK_ISA_AVX512F | OPTION_MASK_ISA_AVX512CD_UNSET \ | OPTION_MASK_ISA_AVX512PF_UNSET | OPTION_MASK_ISA_AVX512ER_UNSET \ @@ -228,6 +231,7 @@ along with GCC; see the file COPYING3. If not see #define OPTION_MASK_ISA2_AVX5124VNNIW_UNSET OPTION_MASK_ISA2_AVX5124VNNIW #define OPTION_MASK_ISA_AVX512VBMI2_UNSET OPTION_MASK_ISA_AVX512VBMI2 #define OPTION_MASK_ISA_AVX512VNNI_UNSET OPTION_MASK_ISA_AVX512VNNI +#define OPTION_MASK_ISA2_AVXVNNI_UNSET OPTION_MASK_ISA2_AVXVNNI #define OPTION_MASK_ISA_AVX512VPOPCNTDQ_UNSET OPTION_MASK_ISA_AVX512VPOPCNTDQ #define OPTION_MASK_ISA_AVX512BITALG_UNSET OPTION_MASK_ISA_AVX512BITALG #define OPTION_MASK_ISA2_AVX512BF16_UNSET OPTION_MASK_ISA2_AVX512BF16 @@ -310,7 +314,6 @@ along with GCC; see the file COPYING3. If not see | OPTION_MASK_ISA2_AVX512VP2INTERSECT_UNSET) #define OPTION_MASK_ISA2_GENERAL_REGS_ONLY_UNSET \ (OPTION_MASK_ISA2_AVX512F_UNSET) -#define OPTION_MASK_ISA2_AVX2_UNSET OPTION_MASK_ISA2_AVX512F_UNSET #define OPTION_MASK_ISA2_AVX_UNSET OPTION_MASK_ISA2_AVX2_UNSET #define OPTION_MASK_ISA2_SSE4_2_UNSET OPTION_MASK_ISA2_AVX_UNSET #define OPTION_MASK_ISA2_SSE4_1_UNSET OPTION_MASK_ISA2_SSE4_2_UNSET @@ -882,6 +885,21 @@ ix86_handle_option (struct gcc_options *opts, } return true; + case OPT_mavxvnni: + if (value) + { + opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA2_AVXVNNI_SET; + opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVXVNNI_SET; + opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX2_SET; + opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX2_SET; + } + else + { + opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVXVNNI_UNSET; + opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVXVNNI_UNSET; + } + return true; + case OPT_msgx: if (value) { diff --git a/gcc/common/config/i386/i386-cpuinfo.h b/gcc/common/config/i386/i386-cpuinfo.h index 2138220..af02be5 100644 --- a/gcc/common/config/i386/i386-cpuinfo.h +++ b/gcc/common/config/i386/i386-cpuinfo.h @@ -224,6 +224,7 @@ enum processor_features FEATURE_KL, FEATURE_AESKLE, FEATURE_WIDEKL, + FEATURE_AVXVNNI, CPU_FEATURE_MAX }; diff --git a/gcc/common/config/i386/i386-isas.h b/gcc/common/config/i386/i386-isas.h index 921db06..c4fd036 100644 --- a/gcc/common/config/i386/i386-isas.h +++ b/gcc/common/config/i386/i386-isas.h @@ -168,4 +168,5 @@ ISA_NAMES_TABLE_START ISA_NAMES_TABLE_ENTRY("kl", FEATURE_KL, P_NONE, "-mkl") ISA_NAMES_TABLE_ENTRY("aeskle", FEATURE_AESKLE, P_NONE, NULL) ISA_NAMES_TABLE_ENTRY("widekl", FEATURE_WIDEKL, P_NONE, "-mwidekl") + ISA_NAMES_TABLE_ENTRY("avxvnni", FEATURE_AVXVNNI, P_NONE, "-mavxvnni") ISA_NAMES_TABLE_END diff --git a/gcc/config.gcc b/gcc/config.gcc index dc6d68b..15318b2 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -414,7 +414,7 @@ i[34567]86-*-*) avx512vp2intersectintrin.h avx512vp2intersectvlintrin.h tsxldtrkintrin.h amxtileintrin.h amxint8intrin.h amxbf16intrin.h x86gprintrin.h uintrintrin.h - hresetintrin.h keylockerintrin.h" + hresetintrin.h keylockerintrin.h avxvnniintrin.h" ;; x86_64-*-*) cpu_type=i386 @@ -451,7 +451,7 @@ x86_64-*-*) avx512vp2intersectintrin.h avx512vp2intersectvlintrin.h tsxldtrkintrin.h amxtileintrin.h amxint8intrin.h amxbf16intrin.h x86gprintrin.h uintrintrin.h - hresetintrin.h keylockerintrin.h" + hresetintrin.h keylockerintrin.h avxvnniintrin.h" ;; ia64-*-*) extra_headers=ia64intrin.h diff --git a/gcc/config/i386/avx512vnnivlintrin.h b/gcc/config/i386/avx512vnnivlintrin.h index b4a6db3..3845b03 100644 --- a/gcc/config/i386/avx512vnnivlintrin.h +++ b/gcc/config/i386/avx512vnnivlintrin.h @@ -34,13 +34,10 @@ #define __DISABLE_AVX512VNNIVL__ #endif /* __AVX512VNNIVL__ */ -extern __inline __m256i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm256_dpbusd_epi32 (__m256i __A, __m256i __B, __m256i __C) -{ - return (__m256i) __builtin_ia32_vpdpbusd_v8si ((__v8si)__A, (__v8si) __B, - (__v8si) __C); -} +#define _mm256_dpbusd_epi32(A, B, C) \ + ((__m256i) __builtin_ia32_vpdpbusd_v8si ((__v8si) (A), \ + (__v8si) (B), \ + (__v8si) (C))) extern __inline __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -58,13 +55,10 @@ _mm256_maskz_dpbusd_epi32 (__mmask8 __A, __m256i __B, __m256i __C, __m256i __D) (__v8si) __C, (__v8si) __D, (__mmask8)__A); } -extern __inline __m128i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm_dpbusd_epi32 (__m128i __A, __m128i __B, __m128i __C) -{ - return (__m128i) __builtin_ia32_vpdpbusd_v4si ((__v4si)__A, (__v4si) __B, - (__v4si) __C); -} +#define _mm_dpbusd_epi32(A, B, C) \ + ((__m128i) __builtin_ia32_vpdpbusd_v4si ((__v4si) (A), \ + (__v4si) (B), \ + (__v4si) (C))) extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -82,13 +76,10 @@ _mm_maskz_dpbusd_epi32 (__mmask8 __A, __m128i __B, __m128i __C, __m128i __D) (__v4si) __C, (__v4si) __D, (__mmask8)__A); } -extern __inline __m256i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm256_dpbusds_epi32 (__m256i __A, __m256i __B, __m256i __C) -{ - return (__m256i) __builtin_ia32_vpdpbusds_v8si ((__v8si)__A, (__v8si) __B, - (__v8si) __C); -} +#define _mm256_dpbusds_epi32(A, B, C) \ + ((__m256i) __builtin_ia32_vpdpbusds_v8si ((__v8si) (A), \ + (__v8si) (B), \ + (__v8si) (C))) extern __inline __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -107,13 +98,10 @@ _mm256_maskz_dpbusds_epi32 (__mmask8 __A, __m256i __B, __m256i __C, (__v8si) __C, (__v8si) __D, (__mmask8)__A); } -extern __inline __m128i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm_dpbusds_epi32 (__m128i __A, __m128i __B, __m128i __C) -{ - return (__m128i) __builtin_ia32_vpdpbusds_v4si ((__v4si)__A, (__v4si) __B, - (__v4si) __C); -} +#define _mm_dpbusds_epi32(A, B, C) \ + ((__m128i) __builtin_ia32_vpdpbusds_v4si ((__v4si) (A), \ + (__v4si) (B), \ + (__v4si) (C))) extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -131,13 +119,10 @@ _mm_maskz_dpbusds_epi32 (__mmask8 __A, __m128i __B, __m128i __C, __m128i __D) (__v4si) __C, (__v4si) __D, (__mmask8)__A); } -extern __inline __m256i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm256_dpwssd_epi32 (__m256i __A, __m256i __B, __m256i __C) -{ - return (__m256i) __builtin_ia32_vpdpwssd_v8si ((__v8si)__A, (__v8si) __B, - (__v8si) __C); -} +#define _mm256_dpwssd_epi32(A, B, C) \ + ((__m256i) __builtin_ia32_vpdpwssd_v8si ((__v8si) (A), \ + (__v8si) (B), \ + (__v8si) (C))) extern __inline __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -155,13 +140,10 @@ _mm256_maskz_dpwssd_epi32 (__mmask8 __A, __m256i __B, __m256i __C, __m256i __D) (__v8si) __C, (__v8si) __D, (__mmask8)__A); } -extern __inline __m128i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm_dpwssd_epi32 (__m128i __A, __m128i __B, __m128i __C) -{ - return (__m128i) __builtin_ia32_vpdpwssd_v4si ((__v4si)__A, (__v4si) __B, - (__v4si) __C); -} +#define _mm_dpwssd_epi32(A, B, C) \ + ((__m128i) __builtin_ia32_vpdpwssd_v4si ((__v4si) (A), \ + (__v4si) (B), \ + (__v4si) (C))) extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -179,13 +161,10 @@ _mm_maskz_dpwssd_epi32 (__mmask8 __A, __m128i __B, __m128i __C, __m128i __D) (__v4si) __C, (__v4si) __D, (__mmask8)__A); } -extern __inline __m256i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm256_dpwssds_epi32 (__m256i __A, __m256i __B, __m256i __C) -{ - return (__m256i) __builtin_ia32_vpdpwssds_v8si ((__v8si)__A, (__v8si) __B, - (__v8si) __C); -} +#define _mm256_dpwssds_epi32(A, B, C) \ + ((__m256i) __builtin_ia32_vpdpwssds_v8si ((__v8si) (A), \ + (__v8si) (B), \ + (__v8si) (C))) extern __inline __m256i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -204,13 +183,10 @@ _mm256_maskz_dpwssds_epi32 (__mmask8 __A, __m256i __B, __m256i __C, (__v8si) __C, (__v8si) __D, (__mmask8)__A); } -extern __inline __m128i -__attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm_dpwssds_epi32 (__m128i __A, __m128i __B, __m128i __C) -{ - return (__m128i) __builtin_ia32_vpdpwssds_v4si ((__v4si)__A, (__v4si) __B, - (__v4si) __C); -} +#define _mm_dpwssds_epi32(A, B, C) \ + ((__m128i) __builtin_ia32_vpdpwssds_v4si ((__v4si) (A), \ + (__v4si) (B), \ + (__v4si) (C))) extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) diff --git a/gcc/config/i386/avxvnniintrin.h b/gcc/config/i386/avxvnniintrin.h new file mode 100644 index 0000000..de7e6a9 --- /dev/null +++ b/gcc/config/i386/avxvnniintrin.h @@ -0,0 +1,113 @@ +/* Copyright (C) 2020 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _IMMINTRIN_H_INCLUDED +#error "Never use directly; include instead." +#endif + +#ifndef _AVXVNNIINTRIN_H_INCLUDED +#define _AVXVNNIINTRIN_H_INCLUDED + +#if !defined(__AVXVNNI__) +#pragma GCC push_options +#pragma GCC target("avxvnni") +#define __DISABLE_AVXVNNIVL__ +#endif /* __AVXVNNIVL__ */ + +extern __inline __m256i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_dpbusd_avx_epi32(__m256i __A, __m256i __B, __m256i __C) +{ + return (__m256i) __builtin_ia32_vpdpbusd_v8si ((__v8si) __A, + (__v8si) __B, + (__v8si) __C); +} + +extern __inline __m128i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_dpbusd_avx_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpdpbusd_v4si ((__v4si) __A, + (__v4si) __B, + (__v4si) __C); +} + +extern __inline __m256i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_dpbusds_avx_epi32(__m256i __A, __m256i __B, __m256i __C) +{ + return (__m256i) __builtin_ia32_vpdpbusds_v8si ((__v8si) __A, + (__v8si) __B, + (__v8si) __C); +} + +extern __inline __m128i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_dpbusds_avx_epi32(__m128i __A,__m128i __B,__m128i __C) +{ + return (__m128i) __builtin_ia32_vpdpbusds_v4si ((__v4si) __A, + (__v4si) __B, + (__v4si) __C); +} + +extern __inline __m256i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_dpwssd_avx_epi32(__m256i __A,__m256i __B,__m256i __C) +{ + return (__m256i) __builtin_ia32_vpdpwssd_v8si ((__v8si) __A, + (__v8si) __B, + (__v8si) __C); +} + +extern __inline __m128i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_dpwssd_avx_epi32(__m128i __A,__m128i __B,__m128i __C) +{ + return (__m128i) __builtin_ia32_vpdpwssd_v4si ((__v4si) __A, + (__v4si) __B, + (__v4si) __C); +} + +extern __inline __m256i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_dpwssds_avx_epi32(__m256i __A,__m256i __B,__m256i __C) +{ + return (__m256i) __builtin_ia32_vpdpwssds_v8si ((__v8si) __A, + (__v8si) __B, + (__v8si) __C); +} + +extern __inline __m128i +__attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_dpwssds_avx_epi32(__m128i __A,__m128i __B,__m128i __C) +{ + return (__m128i) __builtin_ia32_vpdpwssds_v4si ((__v4si) __A, + (__v4si) __B, + (__v4si) __C); +} + +#ifdef __DISABLE_AVXVNNIVL__ +#undef __DISABLE_AVXVNNIVL__ +#pragma GCC pop_options +#endif /* __DISABLE_AVXVNNIVL__ */ +#endif /* _AVXVNNIINTRIN_H_INCLUDED */ diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h index 595b423..d2d42f7 100644 --- a/gcc/config/i386/cpuid.h +++ b/gcc/config/i386/cpuid.h @@ -25,6 +25,7 @@ #define _CPUID_H_INCLUDED /* %eax */ +#define bit_AVXVNNI (1 << 4) #define bit_AVX512BF16 (1 << 5) #define bit_HRESET (1 << 22) diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def index 4d38cea..67d5f2ef 100644 --- a/gcc/config/i386/i386-builtin.def +++ b/gcc/config/i386/i386-builtin.def @@ -2626,45 +2626,45 @@ BDESC (OPTION_MASK_ISA_GFNI | OPTION_MASK_ISA_AVX512VL | OPTION_MASK_ISA_AVX512B BDESC (OPTION_MASK_ISA_GFNI | OPTION_MASK_ISA_SSE2, 0, CODE_FOR_vgf2p8mulb_v16qi, "__builtin_ia32_vgf2p8mulb_v16qi", IX86_BUILTIN_VGF2P8MULB128, UNKNOWN, (int) V16QI_FTYPE_V16QI_V16QI) BDESC (OPTION_MASK_ISA_GFNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vgf2p8mulb_v16qi_mask, "__builtin_ia32_vgf2p8mulb_v16qi_mask", IX86_BUILTIN_VGF2P8MULB128MASK, UNKNOWN, (int) V16QI_FTYPE_V16QI_V16QI_V16QI_UHI) -/* VNNI */ +/* AVX512_VNNI */ BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpbusd_v16si, "__builtin_ia32_vpdpbusd_v16si", IX86_BUILTIN_VPDPBUSDV16SI, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpbusd_v16si_mask, "__builtin_ia32_vpdpbusd_v16si_mask", IX86_BUILTIN_VPDPBUSDV16SI_MASK, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpbusd_v16si_maskz, "__builtin_ia32_vpdpbusd_v16si_maskz", IX86_BUILTIN_VPDPBUSDV16SI_MASKZ, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusd_v8si, "__builtin_ia32_vpdpbusd_v8si", IX86_BUILTIN_VPDPBUSDV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpbusd_v8si, "__builtin_ia32_vpdpbusd_v8si", IX86_BUILTIN_VPDPBUSDV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusd_v8si_mask, "__builtin_ia32_vpdpbusd_v8si_mask", IX86_BUILTIN_VPDPBUSDV8SI_MASK, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusd_v8si_maskz, "__builtin_ia32_vpdpbusd_v8si_maskz", IX86_BUILTIN_VPDPBUSDV8SI_MASKZ, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusd_v4si, "__builtin_ia32_vpdpbusd_v4si", IX86_BUILTIN_VPDPBUSDV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpbusd_v4si, "__builtin_ia32_vpdpbusd_v4si", IX86_BUILTIN_VPDPBUSDV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusd_v4si_mask, "__builtin_ia32_vpdpbusd_v4si_mask", IX86_BUILTIN_VPDPBUSDV4SI_MASK, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusd_v4si_maskz, "__builtin_ia32_vpdpbusd_v4si_maskz", IX86_BUILTIN_VPDPBUSDV4SI_MASKZ, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpbusds_v16si, "__builtin_ia32_vpdpbusds_v16si", IX86_BUILTIN_VPDPBUSDSV16SI, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpbusds_v16si_mask, "__builtin_ia32_vpdpbusds_v16si_mask", IX86_BUILTIN_VPDPBUSDSV16SI_MASK, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpbusds_v16si_maskz, "__builtin_ia32_vpdpbusds_v16si_maskz", IX86_BUILTIN_VPDPBUSDSV16SI_MASKZ, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusds_v8si, "__builtin_ia32_vpdpbusds_v8si", IX86_BUILTIN_VPDPBUSDSV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpbusds_v8si, "__builtin_ia32_vpdpbusds_v8si", IX86_BUILTIN_VPDPBUSDSV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusds_v8si_mask, "__builtin_ia32_vpdpbusds_v8si_mask", IX86_BUILTIN_VPDPBUSDSV8SI_MASK, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusds_v8si_maskz, "__builtin_ia32_vpdpbusds_v8si_maskz", IX86_BUILTIN_VPDPBUSDSV8SI_MASKZ, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusds_v4si, "__builtin_ia32_vpdpbusds_v4si", IX86_BUILTIN_VPDPBUSDSV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpbusds_v4si, "__builtin_ia32_vpdpbusds_v4si", IX86_BUILTIN_VPDPBUSDSV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusds_v4si_mask, "__builtin_ia32_vpdpbusds_v4si_mask", IX86_BUILTIN_VPDPBUSDSV4SI_MASK, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpbusds_v4si_maskz, "__builtin_ia32_vpdpbusds_v4si_maskz", IX86_BUILTIN_VPDPBUSDSV4SI_MASKZ, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpwssd_v16si, "__builtin_ia32_vpdpwssd_v16si", IX86_BUILTIN_VPDPWSSDV16SI, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpwssd_v16si_mask, "__builtin_ia32_vpdpwssd_v16si_mask", IX86_BUILTIN_VPDPWSSDV16SI_MASK, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpwssd_v16si_maskz, "__builtin_ia32_vpdpwssd_v16si_maskz", IX86_BUILTIN_VPDPWSSDV16SI_MASKZ, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssd_v8si, "__builtin_ia32_vpdpwssd_v8si", IX86_BUILTIN_VPDPWSSDV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpwssd_v8si, "__builtin_ia32_vpdpwssd_v8si", IX86_BUILTIN_VPDPWSSDV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssd_v8si_mask, "__builtin_ia32_vpdpwssd_v8si_mask", IX86_BUILTIN_VPDPWSSDV8SI_MASK, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssd_v8si_maskz, "__builtin_ia32_vpdpwssd_v8si_maskz", IX86_BUILTIN_VPDPWSSDV8SI_MASKZ, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssd_v4si, "__builtin_ia32_vpdpwssd_v4si", IX86_BUILTIN_VPDPWSSDV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpwssd_v4si, "__builtin_ia32_vpdpwssd_v4si", IX86_BUILTIN_VPDPWSSDV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssd_v4si_mask, "__builtin_ia32_vpdpwssd_v4si_mask", IX86_BUILTIN_VPDPWSSDV4SI_MASK, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssd_v4si_maskz, "__builtin_ia32_vpdpwssd_v4si_maskz", IX86_BUILTIN_VPDPWSSDV4SI_MASKZ, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpwssds_v16si, "__builtin_ia32_vpdpwssds_v16si", IX86_BUILTIN_VPDPWSSDSV16SI, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpwssds_v16si_mask, "__builtin_ia32_vpdpwssds_v16si_mask", IX86_BUILTIN_VPDPWSSDSV16SI_MASK, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) BDESC (OPTION_MASK_ISA_AVX512VNNI, 0, CODE_FOR_vpdpwssds_v16si_maskz, "__builtin_ia32_vpdpwssds_v16si_maskz", IX86_BUILTIN_VPDPWSSDSV16SI_MASKZ, UNKNOWN, (int) V16SI_FTYPE_V16SI_V16SI_V16SI_UHI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssds_v8si, "__builtin_ia32_vpdpwssds_v8si", IX86_BUILTIN_VPDPWSSDSV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpwssds_v8si, "__builtin_ia32_vpdpwssds_v8si", IX86_BUILTIN_VPDPWSSDSV8SI, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssds_v8si_mask, "__builtin_ia32_vpdpwssds_v8si_mask", IX86_BUILTIN_VPDPWSSDSV8SI_MASK, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssds_v8si_maskz, "__builtin_ia32_vpdpwssds_v8si_maskz", IX86_BUILTIN_VPDPWSSDSV8SI_MASKZ, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_V8SI_UQI) -BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssds_v4si, "__builtin_ia32_vpdpwssds_v4si", IX86_BUILTIN_VPDPWSSDSV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) +BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVXVNNI, CODE_FOR_vpdpwssds_v4si, "__builtin_ia32_vpdpwssds_v4si", IX86_BUILTIN_VPDPWSSDSV4SI, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssds_v4si_mask, "__builtin_ia32_vpdpwssds_v4si_mask", IX86_BUILTIN_VPDPWSSDSV4SI_MASK, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) BDESC (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL, 0, CODE_FOR_vpdpwssds_v4si_maskz, "__builtin_ia32_vpdpwssds_v4si_maskz", IX86_BUILTIN_VPDPWSSDSV4SI_MASKZ, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI_V4SI_UQI) diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c index 504987a..d8ec1e5 100644 --- a/gcc/config/i386/i386-builtins.c +++ b/gcc/config/i386/i386-builtins.c @@ -274,6 +274,10 @@ def_builtin (HOST_WIDE_INT mask, HOST_WIDE_INT mask2, if (((mask2 == 0 || (mask2 & ix86_isa_flags2) != 0) && (mask == 0 || (mask & ix86_isa_flags) != 0)) || ((mask & OPTION_MASK_ISA_MMX) != 0 && TARGET_MMX_WITH_SSE) + /* "Unified" builtin used by either AVXVNNI intrinsics or AVX512VNNIVL + non-mask intrinsics should be defined whenever avxvnni + or avx512vnni && avx512vl exist. */ + || (mask2 == OPTION_MASK_ISA2_AVXVNNI) || (lang_hooks.builtin_function == lang_hooks.builtin_function_ext_scope)) { diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index 3299a56..87b3a2b 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -606,6 +606,8 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag, def_or_undef (parse_in, "__KL__"); if (isa_flag2 & OPTION_MASK_ISA2_WIDEKL) def_or_undef (parse_in, "__WIDEKL__"); + if (isa_flag2 & OPTION_MASK_ISA2_AVXVNNI) + def_or_undef (parse_in, "__AVXVNNI__"); if (TARGET_IAMCU) { def_or_undef (parse_in, "__iamcu"); diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index 6f81b58..795320b 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -11059,6 +11059,8 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget, OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_CRC32 OPTION_MASK_ISA_FMA | OPTION_MASK_ISA_FMA4 + (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL) or + OPTION_MASK_ISA2_AVXVNNI where for each such pair it is sufficient if either of the ISAs is enabled, plus if it is ored with other options also those others. OPTION_MASK_ISA_MMX in bisa is satisfied also if TARGET_MMX_WITH_SSE. */ @@ -11077,6 +11079,17 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget, && (isa & (OPTION_MASK_ISA_FMA | OPTION_MASK_ISA_FMA4)) != 0) isa |= (OPTION_MASK_ISA_FMA | OPTION_MASK_ISA_FMA4); + if ((((bisa & (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL)) + == (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL)) + || (bisa2 & OPTION_MASK_ISA2_AVXVNNI) != 0) + && (((isa & (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL)) + == (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL)) + || (isa2 & OPTION_MASK_ISA2_AVXVNNI) != 0)) + { + isa |= OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512VL; + isa2 |= OPTION_MASK_ISA2_AVXVNNI; + } + if ((bisa & OPTION_MASK_ISA_MMX) && !TARGET_MMX && TARGET_MMX_WITH_SSE /* __builtin_ia32_maskmovq requires MMX registers. */ && fcode != IX86_BUILTIN_MASKMOVQ) diff --git a/gcc/config/i386/i386-options.c b/gcc/config/i386/i386-options.c index 4128e93..467bed8 100644 --- a/gcc/config/i386/i386-options.c +++ b/gcc/config/i386/i386-options.c @@ -216,7 +216,8 @@ static struct ix86_target_opts isa2_opts[] = { "-muintr", OPTION_MASK_ISA2_UINTR }, { "-mhreset", OPTION_MASK_ISA2_HRESET }, { "-mkl", OPTION_MASK_ISA2_KL }, - { "-mwidekl", OPTION_MASK_ISA2_WIDEKL } + { "-mwidekl", OPTION_MASK_ISA2_WIDEKL }, + { "-mavxvnni", OPTION_MASK_ISA2_AVXVNNI } }; static struct ix86_target_opts isa_opts[] = { @@ -1047,6 +1048,7 @@ ix86_valid_target_attribute_inner_p (tree fndecl, tree args, char *p_strings[], IX86_ATTR_ISA ("amx-int8", OPT_mamx_int8), IX86_ATTR_ISA ("amx-bf16", OPT_mamx_bf16), IX86_ATTR_ISA ("hreset", OPT_mhreset), + IX86_ATTR_ISA ("avxvnni", OPT_mavxvnni), /* enum options */ IX86_ATTR_ENUM ("fpmath=", OPT_mfpmath_), @@ -2304,6 +2306,10 @@ ix86_option_override_internal (bool main_args_p, && !(opts->x_ix86_isa_flags2_explicit & OPTION_MASK_ISA2_AMX_BF16)) opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA2_AMX_BF16; + if (((processor_alias_table[i].flags & PTA_AVXVNNI) != 0) + && !(opts->x_ix86_isa_flags2_explicit + & OPTION_MASK_ISA2_AVXVNNI)) + opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA2_AVXVNNI; if (((processor_alias_table[i].flags & PTA_MOVDIRI) != 0) && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_MOVDIRI)) opts->x_ix86_isa_flags |= OPTION_MASK_ISA_MOVDIRI; diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index e882977..3be7551 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -217,6 +217,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define TARGET_KL_P(x) TARGET_ISA2_KL_P(x) #define TARGET_WIDEKL TARGET_ISA2_WIDEKL #define TARGET_WIDEKL_P(x) TARGET_ISA2_WIDEKL_P(x) +#define TARGET_AVXVNNI TARGET_ISA2_AVXVNNI +#define TARGET_AVXVNNI_P(x) TARGET_ISA2_AVXVNNI_P(x) #define TARGET_LP64 TARGET_ABI_64 #define TARGET_LP64_P(x) TARGET_ABI_64_P(x) @@ -2493,6 +2495,7 @@ const wide_int_bitmask PTA_UINTR (0, HOST_WIDE_INT_1U << 22); const wide_int_bitmask PTA_HRESET (0, HOST_WIDE_INT_1U << 23); const wide_int_bitmask PTA_KL (0, HOST_WIDE_INT_1U << 24); const wide_int_bitmask PTA_WIDEKL (0, HOST_WIDE_INT_1U << 25); +const wide_int_bitmask PTA_AVXVNNI (0, HOST_WIDE_INT_1U << 26); const wide_int_bitmask PTA_X86_64_BASELINE = PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_NO_SAHF | PTA_FXSR; @@ -2536,9 +2539,9 @@ const wide_int_bitmask PTA_TIGERLAKE = PTA_ICELAKE_CLIENT | PTA_MOVDIRI const wide_int_bitmask PTA_SAPPHIRERAPIDS = PTA_COOPERLAKE | PTA_MOVDIRI | PTA_MOVDIR64B | PTA_AVX512VP2INTERSECT | PTA_ENQCMD | PTA_CLDEMOTE | PTA_PTWRITE | PTA_WAITPKG | PTA_SERIALIZE | PTA_TSXLDTRK | PTA_AMX_TILE - | PTA_AMX_INT8 | PTA_AMX_BF16 | PTA_UINTR; + | PTA_AMX_INT8 | PTA_AMX_BF16 | PTA_UINTR | PTA_AVXVNNI; const wide_int_bitmask PTA_ALDERLAKE = PTA_SKYLAKE | PTA_CLDEMOTE | PTA_PTWRITE - | PTA_WAITPKG | PTA_SERIALIZE | PTA_HRESET | PTA_KL | PTA_WIDEKL; + | PTA_WAITPKG | PTA_SERIALIZE | PTA_HRESET | PTA_KL | PTA_WIDEKL | PTA_AVXVNNI; const wide_int_bitmask PTA_KNL = PTA_BROADWELL | PTA_AVX512PF | PTA_AVX512ER | PTA_AVX512F | PTA_AVX512CD | PTA_PREFETCHWT1; const wide_int_bitmask PTA_BONNELL = PTA_CORE2 | PTA_MOVBE; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 979e49d..80f1ccc 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -818,7 +818,8 @@ sse_noavx,sse2,sse2_noavx,sse3,sse3_noavx,sse4,sse4_noavx, avx,noavx,avx2,noavx2,bmi,bmi2,fma4,fma,avx512f,noavx512f, avx512bw,noavx512bw,avx512dq,noavx512dq, - avx512vl,noavx512vl,x64_avx512dq,x64_avx512bw" + avx512vl,noavx512vl,x64_avx512dq,x64_avx512bw, + avxvnni,avx512vnnivl" (const_string "base")) ;; Define instruction set of MMX instructions @@ -867,6 +868,8 @@ (eq_attr "isa" "noavx512dq") (symbol_ref "!TARGET_AVX512DQ") (eq_attr "isa" "avx512vl") (symbol_ref "TARGET_AVX512VL") (eq_attr "isa" "noavx512vl") (symbol_ref "!TARGET_AVX512VL") + (eq_attr "isa" "avxvnni") (symbol_ref "TARGET_AVXVNNI") + (eq_attr "isa" "avx512vnnivl") (symbol_ref "TARGET_AVX512VNNI && TARGET_AVX512VL") (eq_attr "mmx_isa" "native") (symbol_ref "!TARGET_MMX_WITH_SSE") diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index 029cacb..fac76e4 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -1143,3 +1143,8 @@ Support KL built-in functions and code generation. mwidekl Target Report Mask(ISA2_WIDEKL) Var(ix86_isa_flags2) Save Support WIDEKL built-in functions and code generation. + +mavxvnni +Target Report Mask(ISA2_AVXVNNI) Var(ix86_isa_flags2) Save +Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2, and +AVXVNNI built-in functions and code generation. diff --git a/gcc/config/i386/immintrin.h b/gcc/config/i386/immintrin.h index 0ce08e5..b787967 100644 --- a/gcc/config/i386/immintrin.h +++ b/gcc/config/i386/immintrin.h @@ -42,6 +42,8 @@ #include +#include + #include #include diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index b153a87..8437ad2 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -22915,16 +22915,30 @@ [(set_attr ("prefix") ("evex")) (set_attr "mode" "")]) -(define_insn "vpdpbusd_" - [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") - (unspec:VI4_AVX512VL - [(match_operand:VI4_AVX512VL 1 "register_operand" "0") - (match_operand:VI4_AVX512VL 2 "register_operand" "v") - (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] +(define_insn "vpdpbusd_v16si" + [(set (match_operand:V16SI 0 "register_operand" "=v") + (unspec:V16SI + [(match_operand:V16SI 1 "register_operand" "0") + (match_operand:V16SI 2 "register_operand" "v") + (match_operand:V16SI 3 "nonimmediate_operand" "vm")] UNSPEC_VPMADDUBSWACCD))] "TARGET_AVX512VNNI" - "vpdpbusd\t{%3, %2, %0|%0, %2, %3 }" - [(set_attr ("prefix") ("evex"))]) + "vpdpbusd\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("evex"))]) + +(define_insn "vpdpbusd_" + [(set (match_operand:VI4_AVX2 0 "register_operand" "=x,v") + (unspec:VI4_AVX2 + [(match_operand:VI4_AVX2 1 "register_operand" "0,0") + (match_operand:VI4_AVX2 2 "register_operand" "x,v") + (match_operand:VI4_AVX2 3 "nonimmediate_operand" "xm,vm")] + UNSPEC_VPMADDUBSWACCD))] + "TARGET_AVXVNNI || (TARGET_AVX512VNNI && TARGET_AVX512VL)" + "@ + %{vex%} vpdpbusd\t{%3, %2, %0|%0, %2, %3} + vpdpbusd\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("vex,evex")) + (set_attr ("isa") ("avxvnni,avx512vnnivl"))]) (define_insn "vpdpbusd__mask" [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") @@ -22969,17 +22983,30 @@ "vpdpbusd\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" [(set_attr ("prefix") ("evex"))]) +(define_insn "vpdpbusds_v16si" + [(set (match_operand:V16SI 0 "register_operand" "=v") + (unspec:V16SI + [(match_operand:V16SI 1 "register_operand" "0") + (match_operand:V16SI 2 "register_operand" "v") + (match_operand:V16SI 3 "nonimmediate_operand" "vm")] + UNSPEC_VPMADDUBSWACCSSD))] + "TARGET_AVX512VNNI" + "vpdpbusds\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("evex"))]) (define_insn "vpdpbusds_" - [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") - (unspec:VI4_AVX512VL - [(match_operand:VI4_AVX512VL 1 "register_operand" "0") - (match_operand:VI4_AVX512VL 2 "register_operand" "v") - (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] + [(set (match_operand:VI4_AVX2 0 "register_operand" "=x,v") + (unspec:VI4_AVX2 + [(match_operand:VI4_AVX2 1 "register_operand" "0,0") + (match_operand:VI4_AVX2 2 "register_operand" "x,v") + (match_operand:VI4_AVX2 3 "nonimmediate_operand" "xm,vm")] UNSPEC_VPMADDUBSWACCSSD))] - "TARGET_AVX512VNNI" - "vpdpbusds\t{%3, %2, %0|%0, %2, %3 }" - [(set_attr ("prefix") ("evex"))]) + "TARGET_AVXVNNI || (TARGET_AVX512VNNI && TARGET_AVX512VL)" + "@ + %{vex%} vpdpbusds\t{%3, %2, %0|%0, %2, %3} + vpdpbusds\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("vex,evex")) + (set_attr ("isa") ("avxvnni,avx512vnnivl"))]) (define_insn "vpdpbusds__mask" [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") @@ -23024,17 +23051,30 @@ "vpdpbusds\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" [(set_attr ("prefix") ("evex"))]) +(define_insn "vpdpwssd_v16si" + [(set (match_operand:V16SI 0 "register_operand" "=v") + (unspec:V16SI + [(match_operand:V16SI 1 "register_operand" "0") + (match_operand:V16SI 2 "register_operand" "v") + (match_operand:V16SI 3 "nonimmediate_operand" "vm")] + UNSPEC_VPMADDWDACCD))] + "TARGET_AVX512VNNI" + "vpdpwssd\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("evex"))]) (define_insn "vpdpwssd_" - [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") - (unspec:VI4_AVX512VL - [(match_operand:VI4_AVX512VL 1 "register_operand" "0") - (match_operand:VI4_AVX512VL 2 "register_operand" "v") - (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] + [(set (match_operand:VI4_AVX2 0 "register_operand" "=x,v") + (unspec:VI4_AVX2 + [(match_operand:VI4_AVX2 1 "register_operand" "0,0") + (match_operand:VI4_AVX2 2 "register_operand" "x,v") + (match_operand:VI4_AVX2 3 "nonimmediate_operand" "xm,vm")] UNSPEC_VPMADDWDACCD))] - "TARGET_AVX512VNNI" - "vpdpwssd\t{%3, %2, %0|%0, %2, %3 }" - [(set_attr ("prefix") ("evex"))]) + "TARGET_AVXVNNI || (TARGET_AVX512VNNI && TARGET_AVX512VL)" + "@ + %{vex%} vpdpwssd\t{%3, %2, %0|%0, %2, %3} + vpdpwssd\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("vex,evex")) + (set_attr ("isa") ("avxvnni,avx512vnnivl"))]) (define_insn "vpdpwssd__mask" [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") @@ -23079,17 +23119,30 @@ "vpdpwssd\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" [(set_attr ("prefix") ("evex"))]) +(define_insn "vpdpwssds_v16si" + [(set (match_operand:V16SI 0 "register_operand" "=v") + (unspec:V16SI + [(match_operand:V16SI 1 "register_operand" "0") + (match_operand:V16SI 2 "register_operand" "v") + (match_operand:V16SI 3 "nonimmediate_operand" "vm")] + UNSPEC_VPMADDWDACCSSD))] + "TARGET_AVX512VNNI" + "vpdpwssds\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("evex"))]) (define_insn "vpdpwssds_" - [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") - (unspec:VI4_AVX512VL - [(match_operand:VI4_AVX512VL 1 "register_operand" "0") - (match_operand:VI4_AVX512VL 2 "register_operand" "v") - (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] + [(set (match_operand:VI4_AVX2 0 "register_operand" "=x,v") + (unspec:VI4_AVX2 + [(match_operand:VI4_AVX2 1 "register_operand" "0,0") + (match_operand:VI4_AVX2 2 "register_operand" "x,v") + (match_operand:VI4_AVX2 3 "nonimmediate_operand" "xm,vm")] UNSPEC_VPMADDWDACCSSD))] - "TARGET_AVX512VNNI" - "vpdpwssds\t{%3, %2, %0|%0, %2, %3 }" - [(set_attr ("prefix") ("evex"))]) + "TARGET_AVXVNNI || (TARGET_AVX512VNNI && TARGET_AVX512VL)" + "@ + %{vex%} vpdpwssds\t{%3, %2, %0|%0, %2, %3} + vpdpwssds\t{%3, %2, %0|%0, %2, %3}" + [(set_attr ("prefix") ("vex,evex")) + (set_attr ("isa") ("avxvnni,avx512vnnivl"))]) (define_insn "vpdpwssds__mask" [(set (match_operand:VI4_AVX512VL 0 "register_operand" "=v") diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 5f1e3bf..420a14b 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -6750,6 +6750,11 @@ Enable/disable the generation of the KEYLOCKER instructions. @cindex @code{target("widekl")} function attribute, x86 Enable/disable the generation of the WIDEKL instructions. +@item avxvnni +@itemx no-avxvnni +@cindex @code{target("avxvnni")} function attribute, x86 +Enable/disable the generation of the AVXVNNI instructions. + @item cld @itemx no-cld @cindex @code{target("cld")} function attribute, x86 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d01beb2..18ca759 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1367,7 +1367,7 @@ See RS/6000 and PowerPC Options. -mvpclmulqdq -mavx512bitalg -mmovdiri -mmovdir64b -mavx512vpopcntdq @gol -mavx5124fmaps -mavx512vnni -mavx5124vnniw -mprfchw -mrdpid @gol -mrdseed -msgx -mavx512vp2intersect -mserialize -mtsxldtrk@gol --mamx-tile -mamx-int8 -mamx-bf16 -muintr -mhreset@gol +-mamx-tile -mamx-int8 -mamx-bf16 -muintr -mhreset -mavxvnni@gol -mcldemote -mms-bitfields -mno-align-stringops -minline-all-stringops @gol -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol -mkl -mwidekl @gol @@ -30409,6 +30409,9 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}. @itemx -mavx512vnni @opindex mavx512vnni @need 200 +@itemx -mavxvnni +@opindex mavxvnni +@need 200 @itemx -mavx5124vnniw @opindex mavx5124vnniw @need 200 @@ -30443,9 +30446,9 @@ WBNOINVD, FMA4, PREFETCHW, RDPID, PREFETCHWT1, RDSEED, SGX, XOP, LWP, XSAVEOPT, XSAVEC, XSAVES, RTM, HLE, TBM, MWAITX, CLZERO, PKU, AVX512VBMI2, GFNI, VAES, WAITPKG, VPCLMULQDQ, AVX512BITALG, MOVDIRI, MOVDIR64B, AVX512BF16, ENQCMD, AVX512VPOPCNTDQ, AVX5124FMAPS, AVX512VNNI, AVX5124VNNIW, SERIALIZE, -UINTR, HRESET, AMXTILE, AMXINT8, AMXBF16, KL, WIDEKL or CLDEMOTE extended -instruction sets. Each has a corresponding @option{-mno-} option to disable -use of these instructions. +UINTR, HRESET, AMXTILE, AMXINT8, AMXBF16, KL, WIDEKL, AVXVNNI or CLDEMOTE +extended instruction sets. Each has a corresponding @option{-mno-} option to +disable use of these instructions. These extensions are also available as built-in functions: see @ref{x86 Built-in Functions}, for details of the functions enabled and diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index b3c5e53..4822efe 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -2243,6 +2243,9 @@ Target supports compiling @code{avx2} instructions. @item avx2_runtime Target supports the execution of @code{avx2} instructions. +@item avxvnni +Target supports the execution of @code{avxvnni} instructions. + @item avx512f Target supports compiling @code{avx512f} instructions. diff --git a/gcc/testsuite/g++.dg/other/i386-2.C b/gcc/testsuite/g++.dg/other/i386-2.C index b964248..62b2132 100644 --- a/gcc/testsuite/g++.dg/other/i386-2.C +++ b/gcc/testsuite/g++.dg/other/i386-2.C @@ -1,5 +1,5 @@ /* { dg-do compile { target i?86-*-* x86_64-*-* } } */ -/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512dq -mavx512bw -mavx512vl -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl" } */ +/* { dg-options "-O -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512dq -mavx512bw -mavx512vl -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl -mavxvnni" } */ /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h, xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h, diff --git a/gcc/testsuite/g++.dg/other/i386-3.C b/gcc/testsuite/g++.dg/other/i386-3.C index 2f73de2..843aa2b 100644 --- a/gcc/testsuite/g++.dg/other/i386-3.C +++ b/gcc/testsuite/g++.dg/other/i386-3.C @@ -1,5 +1,5 @@ /* { dg-do compile { target i?86-*-* x86_64-*-* } } */ -/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512dq -mavx512bw -mavx512vl -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl" } */ +/* { dg-options "-O -fkeep-inline-functions -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512dq -mavx512bw -mavx512vl -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl -mavxvnni" } */ /* Test that {,x,e,p,t,s,w,a,b,i}mmintrin.h, mm3dnow.h, fma4intrin.h, xopintrin.h, abmintrin.h, bmiintrin.h, tbmintrin.h, lwpintrin.h, diff --git a/gcc/testsuite/gcc.target/i386/avx-vnni-1.c b/gcc/testsuite/gcc.target/i386/avx-vnni-1.c new file mode 100644 index 0000000..a22d12a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vnni-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-mavxvnni -O2" } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; + +void extern +avxvnni_test (void) +{ + x = _mm256_dpbusd_epi32 (x, y, z); + x_ = _mm_dpbusd_epi32 (x_, y_, z_); + x = _mm256_dpbusds_epi32 (x, y, z); + x_ = _mm_dpbusds_epi32 (x_, y_, z_); + x = _mm256_dpwssd_epi32 (x, y, z); + x_ = _mm_dpwssd_epi32 (x_, y_, z_); + x = _mm256_dpwssds_epi32 (x, y, z); + x_ = _mm_dpwssds_epi32 (x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vnni-2.c b/gcc/testsuite/gcc.target/i386/avx-vnni-2.c new file mode 100644 index 0000000..4ab6f0c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vnni-2.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; + +__attribute__((target("avxvnni"))) +void +avxvnni_test (void) +{ + x = _mm256_dpbusd_epi32 (x, y, z); + x_ = _mm_dpbusd_epi32 (x_, y_, z_); + x = _mm256_dpbusds_epi32 (x, y, z); + x_ = _mm_dpbusds_epi32 (x_, y_, z_); + x = _mm256_dpwssd_epi32 (x, y, z); + x_ = _mm_dpwssd_epi32 (x_, y_, z_); + x = _mm256_dpwssds_epi32 (x, y, z); + x_ = _mm_dpwssds_epi32 (x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vnni-3.c b/gcc/testsuite/gcc.target/i386/avx-vnni-3.c new file mode 100644 index 0000000..fdea7f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vnni-3.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=x86-64" } */ + +__attribute__ ((__gnu_inline__, __always_inline__, target("avxvnni"))) +inline int +foo (void) /* { dg-error "inlining failed in call to 'always_inline' .* target specific option mismatch" } */ +{ + return 0; +} + +__attribute__ ((target("avx512vnni,avx512vl"))) +int +bar (void) +{ + return foo (); /* { dg-message "called from here" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vnni-4.c b/gcc/testsuite/gcc.target/i386/avx-vnni-4.c new file mode 100644 index 0000000..1ef3edc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vnni-4.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=x86-64" } */ + +__attribute__ ((__gnu_inline__, __always_inline__, target("avx512vnni,avx512vl"))) +inline int +foo (void) /* { dg-error "inlining failed in call to 'always_inline' .* target specific option mismatch" } */ +{ + return 0; +} + +__attribute__ ((target("avxvnni"))) +int +bar (void) +{ + return foo (); /* { dg-message "called from here" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vnni-5.c b/gcc/testsuite/gcc.target/i386/avx-vnni-5.c new file mode 100644 index 0000000..6556a32 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vnni-5.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavxvnni -mavx512vnni -mavx512vl" } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; + +void +avxvnni_test (void) +{ + x = _mm256_dpbusd_epi32 (x, y, z); + x_ = _mm_dpbusd_epi32 (x_, y_, z_); + x = _mm256_dpbusds_epi32 (x, y, z); + x_ = _mm_dpbusds_epi32 (x_, y_, z_); + x = _mm256_dpwssd_epi32 (x, y, z); + x_ = _mm_dpwssd_epi32 (x_, y_, z_); + x = _mm256_dpwssds_epi32 (x, y, z); + x_ = _mm_dpwssds_epi32 (x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vnni-6.c b/gcc/testsuite/gcc.target/i386/avx-vnni-6.c new file mode 100644 index 0000000..2c42627 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vnni-6.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-mavxvnni -O2" } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; + +void extern +avxvnni_test (void) +{ + x = _mm256_dpbusd_avx_epi32 (x, y, z); + x_ = _mm_dpbusd_avx_epi32 (x_, y_, z_); + x = _mm256_dpbusds_avx_epi32 (x, y, z); + x_ = _mm_dpbusds_avx_epi32 (x_, y_, z_); + x = _mm256_dpwssd_avx_epi32 (x, y, z); + x_ = _mm_dpwssd_avx_epi32 (x_, y_, z_); + x = _mm256_dpwssds_avx_epi32 (x, y, z); + x_ = _mm_dpwssds_avx_epi32 (x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vpdpbusd-2.c b/gcc/testsuite/gcc.target/i386/avx-vpdpbusd-2.c new file mode 100644 index 0000000..d4b8d89 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vpdpbusd-2.c @@ -0,0 +1,74 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavxvnni" } */ +/* { dg-require-effective-target avxvnni } */ + +#ifndef CHECK +#define CHECK "avx-check.h" +#endif + +#ifndef TEST +#define TEST avx_test +#endif + +#include CHECK + +static void +CALC (int *r, int *dst, unsigned char *s1, char *s2, int size) +{ + short tempres[32]; + for (int i = 0; i < size; i++) { + tempres[i] = ((unsigned short)(s1[i]) * (short)(s2[i])); + } + for (int i = 0; i < size / 4; i++) { + long long test = (long long)dst[i] + tempres[i*4] + tempres[i*4 + 1] + tempres[i*4 + 2] + tempres[i*4 + 3]; + r[i] = test; + } +} + +void +TEST (void) +{ + int i; + union256i_d res_256; + union256i_b src2_256; + union256i_ub src1_256; + int res_ref_256[8]; + + if (!__builtin_cpu_supports ("avxvnni")) + return; + + for (i = 0; i < 32; i++) + { + int sign = i % 2 ? 1 : -1; + src1_256.a[i] = 10 + 3*i + sign; + src2_256.a[i] = sign*10*i*i; + } + + for (i = 0; i < 8; i++) + res_256.a[i] = 0x7fffffff; + + CALC (res_ref_256, res_256.a, src1_256.a, src2_256.a, 32); + res_256.x = _mm256_dpbusd_avx_epi32 (res_256.x, src1_256.x, src2_256.x); + if (check_union256i_d (res_256, res_ref_256)) + abort (); + + union128i_d res_128; + union128i_b src2_128; + union128i_ub src1_128; + int res_ref_128[4]; + + for (i = 0; i < 16; i++) + { + int sign = i % 2 ? 1 : -1; + src1_128.a[i] = 10 + 3*i*i + sign; + src2_128.a[i] = sign*10*i*i; + } + + for (i = 0; i < 4; i++) + res_128.a[i] = 0x7fffffff; + + CALC (res_ref_128, res_128.a, src1_128.a, src2_128.a, 16); + res_128.x = _mm_dpbusd_avx_epi32 (res_128.x, src1_128.x, src2_128.x); + if (check_union128i_d (res_128, res_ref_128)) + abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vpdpbusds-2.c b/gcc/testsuite/gcc.target/i386/avx-vpdpbusds-2.c new file mode 100644 index 0000000..5041ffe --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vpdpbusds-2.c @@ -0,0 +1,74 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavxvnni " } */ +/* { dg-require-effective-target avxvnni } */ + +#ifndef CHECK +#define CHECK "avx-check.h" +#endif + +#ifndef TEST +#define TEST avx_test +#endif + +#include CHECK + +static void +CALC (int *r, int *dst, unsigned char *s1, char *s2, int size) +{ + short tempres[32]; + for (int i = 0; i < size; i++) { + tempres[i] = ((unsigned short)(s1[i]) * (short)(s2[i])); + } + for (int i = 0; i < size / 4; i++) { + long long test = (long long)dst[i] + tempres[i*4] + tempres[i*4 + 1] + tempres[i*4 + 2] + tempres[i*4 + 3]; + r[i] = test > 0x7FFFFFFF ? 0x7FFFFFFF : test; + } +} + +void +TEST (void) +{ + int i; + union256i_d res_256; + union256i_b src2_256; + union256i_ub src1_256; + int res_ref_256[8]; + + if (!__builtin_cpu_supports ("avxvnni")) + return; + + for (i = 0; i < 32; i++) + { + int sign = i % 2 ? 1 : -1; + src1_256.a[i] = 10 + 3*i*i + sign; + src2_256.a[i] = sign*10*i*i; + } + + for (i = 0; i < 8; i++) + res_256.a[i] = 0x7fffffff; + + CALC (res_ref_256, res_256.a, src1_256.a, src2_256.a, 32); + res_256.x = _mm256_dpbusds_avx_epi32 (res_256.x, src1_256.x, src2_256.x); + if (check_union256i_d (res_256, res_ref_256)) + abort (); + + union128i_d res_128; + union128i_b src2_128; + union128i_ub src1_128; + int res_ref_128[4]; + + for (i = 0; i < 16; i++) + { + int sign = i % 2 ? 1 : -1; + src1_128.a[i] = 10 + 3*i*i + sign; + src2_128.a[i] = sign*10*i*i; + } + + for (i = 0; i < 4; i++) + res_128.a[i] = 0x7fffffff; + + CALC (res_ref_128, res_128.a, src1_128.a, src2_128.a, 16); + res_128.x = _mm_dpbusds_avx_epi32 (res_128.x, src1_128.x, src2_128.x); + if (check_union128i_d (res_128, res_ref_128)) + abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vpdpwssd-2.c b/gcc/testsuite/gcc.target/i386/avx-vpdpwssd-2.c new file mode 100644 index 0000000..2630c97 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vpdpwssd-2.c @@ -0,0 +1,70 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavxvnni" } */ +/* { dg-require-effective-target avxvnni } */ + +#ifndef CHECK +#define CHECK "avx-check.h" +#endif + +#ifndef TEST +#define TEST avx_test +#endif + +#include CHECK + +static void +CALC (int *r, int *dst, short *s1, short *s2, int size) +{ + short tempres[16]; + for (int i = 0; i < size; i++) { + tempres[i] = ((int)(s1[i]) * (int)(s2[i])); + } + for (int i = 0; i < size / 2; i++) { + long long test = (long long)dst[i] + tempres[i*2] + tempres[i*2 + 1]; + r[i] = test; + } +} + +void +TEST (void) +{ + int i; + union256i_d res_256; + union256i_w src1_256, src2_256; + int res_ref_256[8]; + + if (!__builtin_cpu_supports ("avxvnni")) + return; + + for (i = 0; i < 16; i++) + { + src1_256.a[i] = 1 + i; + src2_256.a[i] = 2 + 2*i + i * i; + } + + for (i = 0; i < 8; i++) + res_256.a[i] = 0x7fffffff; + + CALC (res_ref_256, res_256.a, src1_256.a, src2_256.a, 16); + res_256.x = _mm256_dpwssd_avx_epi32 (res_256.x, src1_256.x, src2_256.x); + if (check_union256i_d (res_256, res_ref_256)) + abort (); + + union128i_d res_128; + union128i_w src1_128, src2_128; + int res_ref_128[4]; + + for (i = 0; i < 8; i++) + { + src1_128.a[i] = 1 + i; + src2_128.a[i] = 2 + 2*i + i * i; + } + + for (i = 0; i < 4; i++) + res_128.a[i] = 0x7fffffff; + + CALC (res_ref_128, res_128.a, src1_128.a, src2_128.a, 8); + res_128.x = _mm_dpwssd_avx_epi32 (res_128.x, src1_128.x, src2_128.x); + if (check_union128i_d (res_128, res_ref_128)) + abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/avx-vpdpwssds-2.c b/gcc/testsuite/gcc.target/i386/avx-vpdpwssds-2.c new file mode 100644 index 0000000..bc4395a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx-vpdpwssds-2.c @@ -0,0 +1,70 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavxvnni" } */ +/* { dg-require-effective-target avxvnni } */ + +#ifndef CHECK +#define CHECK "avx-check.h" +#endif + +#ifndef TEST +#define TEST avx_test +#endif + +#include CHECK + +static void +CALC (int *r, int *dst, short *s1, short *s2, int size) +{ + short tempres[16]; + for (int i = 0; i < size; i++) { + tempres[i] = ((int)(s1[i]) * (int)(s2[i])); + } + for (int i = 0; i < size / 2; i++) { + long long test = (long long)dst[i] + tempres[i*2] + tempres[i*2 + 1]; + r[i] = test > 0x7FFFFFFF ? 0x7FFFFFFF : test; + } +} + +void +TEST (void) +{ + int i; + union256i_d res_256; + union256i_w src1_256, src2_256; + int res_ref_256[8]; + + if (!__builtin_cpu_supports ("avxvnni")) + return; + + for (i = 0; i < 16; i++) + { + src1_256.a[i] = 1 + i; + src2_256.a[i] = 2 + 2*i + i * i; + } + + for (i = 0; i < 8; i++) + res_256.a[i] = 0x7fffffff; + + CALC (res_ref_256, res_256.a, src1_256.a, src2_256.a, 16); + res_256.x = _mm256_dpwssds_avx_epi32 (res_256.x, src1_256.x, src2_256.x); + if (check_union256i_d (res_256, res_ref_256)) + abort (); + + union128i_d res_128; + union128i_w src1_128, src2_128; + int res_ref_128[4]; + + for (i = 0; i < 8; i++) + { + src1_128.a[i] = 1 + i; + src2_128.a[i] = 2 + 2*i + i * i; + } + + for (i = 0; i < 4; i++) + res_128.a[i] = 0x7fffffff; + + CALC (res_ref_128, res_128.a, src1_128.a, src2_128.a, 8); + res_128.x = _mm_dpwssds_avx_epi32 (res_128.x, src1_128.x, src2_128.x); + if (check_union128i_d (res_128, res_ref_128)) + abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1.c deleted file mode 100644 index e63bc19..0000000 --- a/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1.c +++ /dev/null @@ -1,69 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-mavx512vl -mavx512vnni -mavx512bw -O2" } */ -/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ - - -#include - -volatile __m256i x,y,z; -volatile __m128i x_,y_,z_; -volatile __mmask32 m; - -void extern -avx512f_test (void) -{ - x = _mm256_dpbusd_epi32 (x, y, z); - x = _mm256_mask_dpbusd_epi32 (x, m, y, z); - x = _mm256_maskz_dpbusd_epi32 (m, x, y, z); - - x_ = _mm_dpbusd_epi32 (x_, y_, z_); - x_ = _mm_mask_dpbusd_epi32 (x_, m, y_, z_); - x_ = _mm_maskz_dpbusd_epi32 (m, x_, y_, z_); - - x = _mm256_dpbusds_epi32 (x, y, z); - x = _mm256_mask_dpbusds_epi32 (x, m, y, z); - x = _mm256_maskz_dpbusds_epi32 (m, x, y, z); - - x_ = _mm_dpbusds_epi32 (x_, y_, z_); - x_ = _mm_mask_dpbusds_epi32 (x_, m, y_, z_); - x_ = _mm_maskz_dpbusds_epi32 (m, x_, y_, z_); - - x = _mm256_dpwssd_epi32 (x, y, z); - x = _mm256_mask_dpwssd_epi32 (x, m, y, z); - x = _mm256_maskz_dpwssd_epi32 (m, x, y, z); - - x_ = _mm_dpwssd_epi32 (x_, y_, z_); - x_ = _mm_mask_dpwssd_epi32 (x_, m, y_, z_); - x_ = _mm_maskz_dpwssd_epi32 (m, x_, y_, z_); - - x = _mm256_dpwssds_epi32 (x, y, z); - x = _mm256_mask_dpwssds_epi32 (x, m, y, z); - x = _mm256_maskz_dpwssds_epi32 (m, x, y, z); - - x_ = _mm_dpwssds_epi32 (x_, y_, z_); - x_ = _mm_mask_dpwssds_epi32 (x_, m, y_, z_); - x_ = _mm_maskz_dpwssds_epi32 (m, x_, y_, z_); -} diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1a.c b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1a.c new file mode 100644 index 0000000..e63bc19 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1a.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vnni -mavx512bw -O2" } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x = _mm256_dpbusd_epi32 (x, y, z); + x = _mm256_mask_dpbusd_epi32 (x, m, y, z); + x = _mm256_maskz_dpbusd_epi32 (m, x, y, z); + + x_ = _mm_dpbusd_epi32 (x_, y_, z_); + x_ = _mm_mask_dpbusd_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpbusd_epi32 (m, x_, y_, z_); + + x = _mm256_dpbusds_epi32 (x, y, z); + x = _mm256_mask_dpbusds_epi32 (x, m, y, z); + x = _mm256_maskz_dpbusds_epi32 (m, x, y, z); + + x_ = _mm_dpbusds_epi32 (x_, y_, z_); + x_ = _mm_mask_dpbusds_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpbusds_epi32 (m, x_, y_, z_); + + x = _mm256_dpwssd_epi32 (x, y, z); + x = _mm256_mask_dpwssd_epi32 (x, m, y, z); + x = _mm256_maskz_dpwssd_epi32 (m, x, y, z); + + x_ = _mm_dpwssd_epi32 (x_, y_, z_); + x_ = _mm_mask_dpwssd_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpwssd_epi32 (m, x_, y_, z_); + + x = _mm256_dpwssds_epi32 (x, y, z); + x = _mm256_mask_dpwssds_epi32 (x, m, y, z); + x = _mm256_maskz_dpwssds_epi32 (m, x, y, z); + + x_ = _mm_dpwssds_epi32 (x_, y_, z_); + x_ = _mm_mask_dpwssds_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpwssds_epi32 (m, x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1b.c b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1b.c new file mode 100644 index 0000000..067e631 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-1b.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vnni -mavx512bw -mavxvnni -O2" } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\\n\\r]*%ymm\[0-9\]+\[^\\n\\r\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\{vex\} vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\\n\\r]*%xmm\[0-9\]+\[^\\n\\r\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x = _mm256_dpbusd_epi32 (x, y, z); + x = _mm256_mask_dpbusd_epi32 (x, m, y, z); + x = _mm256_maskz_dpbusd_epi32 (m, x, y, z); + + x_ = _mm_dpbusd_epi32 (x_, y_, z_); + x_ = _mm_mask_dpbusd_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpbusd_epi32 (m, x_, y_, z_); + + x = _mm256_dpbusds_epi32 (x, y, z); + x = _mm256_mask_dpbusds_epi32 (x, m, y, z); + x = _mm256_maskz_dpbusds_epi32 (m, x, y, z); + + x_ = _mm_dpbusds_epi32 (x_, y_, z_); + x_ = _mm_mask_dpbusds_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpbusds_epi32 (m, x_, y_, z_); + + x = _mm256_dpwssd_epi32 (x, y, z); + x = _mm256_mask_dpwssd_epi32 (x, m, y, z); + x = _mm256_maskz_dpwssd_epi32 (m, x, y, z); + + x_ = _mm_dpwssd_epi32 (x_, y_, z_); + x_ = _mm_mask_dpwssd_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpwssd_epi32 (m, x_, y_, z_); + + x = _mm256_dpwssds_epi32 (x, y, z); + x = _mm256_mask_dpwssds_epi32 (x, m, y, z); + x = _mm256_maskz_dpwssds_epi32 (m, x, y, z); + + x_ = _mm_dpwssds_epi32 (x_, y_, z_); + x_ = _mm_mask_dpwssds_epi32 (x_, m, y_, z_); + x_ = _mm_maskz_dpwssds_epi32 (m, x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vnni-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-2.c new file mode 100644 index 0000000..d4b4635 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-2.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; + +__attribute__((target("avx512vnni,avx512vl"))) +void +avxvnni_test (void) +{ + x = _mm256_dpbusd_epi32 (x, y, z); + x_ = _mm_dpbusd_epi32 (x_, y_, z_); + x = _mm256_dpbusds_epi32 (x, y, z); + x_ = _mm_dpbusds_epi32 (x_, y_, z_); + x = _mm256_dpwssd_epi32 (x, y, z); + x_ = _mm_dpwssd_epi32 (x_, y_, z_); + x = _mm256_dpwssds_epi32 (x, y, z); + x_ = _mm_dpwssds_epi32 (x_, y_, z_); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vnni-3.c b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-3.c new file mode 100644 index 0000000..15a95ab --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512vl-vnni-3.c @@ -0,0 +1,47 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mavxvnni -mavx512vnni -mavx512vl" } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpbusds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssds\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "\\tvpdpwssds\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ + + +#include + +volatile __m256i x,y,z; +volatile __m128i x_,y_,z_; + +void +avxvnni_test (void) +{ + register __m256i a __asm ("xmm16"); + register __m128i a_ __asm ("xmm26"); + a = _mm256_dpbusd_epi32 (x, y, z); + asm volatile ("" : "+v" (a)); + x = a; + a_ = _mm_dpbusd_epi32 (x_, y_, z_); + asm volatile ("" : "+v" (a_)); + x_ = a_; + a = _mm256_dpbusds_epi32 (x, y, z); + asm volatile ("" : "+v" (a)); + x = a; + a_ = _mm_dpbusds_epi32 (x_, y_, z_); + asm volatile ("" : "+v" (a_)); + x_ = a_; + a = _mm256_dpwssd_epi32 (x, y, z); + asm volatile ("" : "+v" (a)); + x = a; + a_ = _mm_dpwssd_epi32 (x_, y_, z_); + asm volatile ("" : "+v" (a_)); + x_ = a_; + a = _mm256_dpwssds_epi32 (x, y, z); + asm volatile ("" : "+v" (a)); + x = a; + a_ = _mm_dpwssds_epi32 (x_, y_, z_); + asm volatile ("" : "+v" (a_)); + x_ = a_; +} diff --git a/gcc/testsuite/gcc.target/i386/avx512vnnivl-builtin.c b/gcc/testsuite/gcc.target/i386/avx512vnnivl-builtin.c new file mode 100644 index 0000000..97aaba0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512vnnivl-builtin.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -mno-avxvnni -mavx512vnni -mavx512vl" } */ +typedef int v8si __attribute__ ((vector_size (32))); +v8si +foo (v8si a, v8si b, v8si c) +{ + return __builtin_ia32_vpdpbusd_v8si (a, b, c); +} diff --git a/gcc/testsuite/gcc.target/i386/avxvnni-builtin.c b/gcc/testsuite/gcc.target/i386/avxvnni-builtin.c new file mode 100644 index 0000000..893a62a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avxvnni-builtin.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -mavxvnni -mno-avx512vnni" } */ +typedef int v8si __attribute__ ((vector_size (32))); +v8si +foo (v8si a, v8si b, v8si c) +{ + return __builtin_ia32_vpdpbusd_v8si (a, b, c); +} diff --git a/gcc/testsuite/gcc.target/i386/funcspec-56.inc b/gcc/testsuite/gcc.target/i386/funcspec-56.inc index b8e3b1f..395a21c 100644 --- a/gcc/testsuite/gcc.target/i386/funcspec-56.inc +++ b/gcc/testsuite/gcc.target/i386/funcspec-56.inc @@ -78,6 +78,7 @@ extern void test_uintr (void) __attribute__((__target__("uintr"))); extern void test_hreset (void) __attribute__((__target__("hreset"))); extern void test_keylocker (void) __attribute__((__target__("kl"))); extern void test_widekl (void) __attribute__((__target__("widekl"))); +extern void test_avxvnni (void) __attribute__((__target__("avxvnni"))); extern void test_no_sgx (void) __attribute__((__target__("no-sgx"))); extern void test_no_avx5124fmaps(void) __attribute__((__target__("no-avx5124fmaps"))); @@ -157,6 +158,7 @@ extern void test_no_uintr (void) __attribute__((__target__("no-uintr"))); extern void test_no_hreset (void) __attribute__((__target__("no-hreset"))); extern void test_no_keylocker (void) __attribute__((__target__("no-kl"))); extern void test_no_widekl (void) __attribute__((__target__("no-widekl"))); +extern void test_no_avxvnni (void) __attribute__((__target__("no-avxvnni"))); extern void test_arch_nocona (void) __attribute__((__target__("arch=nocona"))); extern void test_arch_core2 (void) __attribute__((__target__("arch=core2"))); diff --git a/gcc/testsuite/gcc.target/i386/sse-12.c b/gcc/testsuite/gcc.target/i386/sse-12.c index f1e05e6..375d4d1 100644 --- a/gcc/testsuite/gcc.target/i386/sse-12.c +++ b/gcc/testsuite/gcc.target/i386/sse-12.c @@ -3,7 +3,7 @@ popcntintrin.h gfniintrin.h and mm_malloc.h are usable with -O -std=c89 -pedantic-errors. */ /* { dg-do compile } */ -/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512bw -mavx512dq -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512ifma -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl" } */ +/* { dg-options "-O -std=c89 -pedantic-errors -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512bw -mavx512dq -mavx512vl -mavx512vbmi -mavx512vbmi2 -mavx512ifma -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl -mavxvnni" } */ #include diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c index 7f96331..7029771 100644 --- a/gcc/testsuite/gcc.target/i386/sse-13.c +++ b/gcc/testsuite/gcc.target/i386/sse-13.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512vl -mavx512dq -mavx512bw -mavx512vbmi -mavx512vbmi2 -mavx512ifma -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mavx512vp2intersect -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl" } */ +/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512vl -mavx512dq -mavx512bw -mavx512vbmi -mavx512vbmi2 -mavx512ifma -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mavx512vp2intersect -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mavx512bitalg -mpconfig -mwbnoinvd -mavx512bf16 -menqcmd -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl -mavxvnni" } */ /* { dg-add-options bind_pic_locally } */ #include diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c index 27704c3..4ce0fff 100644 --- a/gcc/testsuite/gcc.target/i386/sse-14.c +++ b/gcc/testsuite/gcc.target/i386/sse-14.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512dq -mavx512bw -mavx512vl -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mpconfig -mwbnoinvd -mavx512vl -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl" } */ +/* { dg-options "-O0 -Werror-implicit-function-declaration -march=k8 -msse4a -m3dnow -mavx -mavx2 -mfma4 -mxop -maes -mpclmul -mpopcnt -mabm -mlzcnt -mbmi -mbmi2 -mtbm -mlwp -mfsgsbase -mrdrnd -mf16c -mfma -mrtm -mrdseed -mprfchw -madx -mfxsr -mxsaveopt -mavx512f -mavx512er -mavx512cd -mavx512pf -msha -mprefetchwt1 -mxsavec -mxsaves -mclflushopt -mavx512dq -mavx512bw -mavx512vl -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq -mclwb -mmwaitx -mclzero -mpku -msgx -mrdpid -mgfni -mpconfig -mwbnoinvd -mavx512vl -mavx512bf16 -menqcmd -mavx512vp2intersect -mserialize -mtsxldtrk -mamx-tile -mamx-int8 -mamx-bf16 -mkl -mwidekl -mavxvnni" } */ /* { dg-add-options bind_pic_locally } */ #include diff --git a/gcc/testsuite/gcc.target/i386/sse-22.c b/gcc/testsuite/gcc.target/i386/sse-22.c index 789c8be..6e8b6f3 100644 --- a/gcc/testsuite/gcc.target/i386/sse-22.c +++ b/gcc/testsuite/gcc.target/i386/sse-22.c @@ -103,7 +103,7 @@ #ifndef DIFFERENT_PRAGMAS -#pragma GCC target ("sse4a,3dnow,avx,avx2,fma4,xop,aes,pclmul,popcnt,abm,lzcnt,bmi,bmi2,tbm,lwp,fsgsbase,rdrnd,f16c,rtm,rdseed,prfchw,adx,fxsr,xsaveopt,avx512f,avx512er,avx512cd,avx512pf,sha,prefetchwt1,avx512vl,avx512bw,avx512dq,avx512vbmi,avx512vbmi2,avx512ifma,avx5124fmaps,avx5124vnniw,avx512vpopcntdq,gfni,avx512bitalg,avx512bf16,avx512vp2intersect,serialize,tsxldtrk,amx-tile,amx-int8,amx-bf16,kl,widekl") +#pragma GCC target ("sse4a,3dnow,avx,avx2,fma4,xop,aes,pclmul,popcnt,abm,lzcnt,bmi,bmi2,tbm,lwp,fsgsbase,rdrnd,f16c,rtm,rdseed,prfchw,adx,fxsr,xsaveopt,avx512f,avx512er,avx512cd,avx512pf,sha,prefetchwt1,avx512vl,avx512bw,avx512dq,avx512vbmi,avx512vbmi2,avx512ifma,avx5124fmaps,avx5124vnniw,avx512vpopcntdq,gfni,avx512bitalg,avx512bf16,avx512vp2intersect,serialize,tsxldtrk,amx-tile,amx-int8,amx-bf16,kl,widekl,avxvnni") #endif /* Following intrinsics require immediate arguments. They @@ -220,7 +220,7 @@ test_4 (_mm_cmpestrz, int, __m128i, int, __m128i, int, 1) /* immintrin.h (AVX/AVX2/RDRND/FSGSBASE/F16C/RTM/AVX512F/SHA) */ #ifdef DIFFERENT_PRAGMAS -#pragma GCC target ("avx,avx2,rdrnd,fsgsbase,f16c,rtm,avx512f,avx512er,avx512cd,avx512pf,sha,avx512vl,avx512bw,avx512dq,avx512ifma,avx512vbmi,avx512vbmi2,avx5124fmaps,avx5124vnniw,avx512vpopcntdq,gfni,avx512bitalg,avx512bf16,avx512vp2intersect,serialize,tsxldtrk,amx-tile,amx-int8,amx-bf16,kl,widekl") +#pragma GCC target ("avx,avx2,rdrnd,fsgsbase,f16c,rtm,avx512f,avx512er,avx512cd,avx512pf,sha,avx512vl,avx512bw,avx512dq,avx512ifma,avx512vbmi,avx512vbmi2,avx5124fmaps,avx5124vnniw,avx512vpopcntdq,gfni,avx512bitalg,avx512bf16,avx512vp2intersect,serialize,tsxldtrk,amx-tile,amx-int8,amx-bf16,kl,widekl,avxvnni") #endif #include test_1 (_cvtss_sh, unsigned short, float, 1) diff --git a/gcc/testsuite/gcc.target/i386/sse-23.c b/gcc/testsuite/gcc.target/i386/sse-23.c index 3e5e3e9..7faa053 100644 --- a/gcc/testsuite/gcc.target/i386/sse-23.c +++ b/gcc/testsuite/gcc.target/i386/sse-23.c @@ -708,6 +708,6 @@ #define __builtin_ia32_vpclmulqdq_v2di(A, B, C) __builtin_ia32_vpclmulqdq_v2di(A, B, 1) #define __builtin_ia32_vpclmulqdq_v8di(A, B, C) __builtin_ia32_vpclmulqdq_v8di(A, B, 1) -#pragma GCC target ("sse4a,3dnow,avx,avx2,fma4,xop,aes,pclmul,popcnt,abm,lzcnt,bmi,bmi2,tbm,lwp,fsgsbase,rdrnd,f16c,fma,rtm,rdseed,prfchw,adx,fxsr,xsaveopt,avx512f,avx512er,avx512cd,avx512pf,sha,prefetchwt1,xsavec,xsaves,clflushopt,avx512bw,avx512dq,avx512vl,avx512vbmi,avx512ifma,avx5124fmaps,avx5124vnniw,avx512vpopcntdq,clwb,mwaitx,clzero,pku,sgx,rdpid,gfni,avx512vbmi2,vpclmulqdq,avx512bitalg,pconfig,wbnoinvd,avx512bf16,enqcmd,avx512vp2intersect,serialize,tsxldtrk,amx-tile,amx-int8,amx-bf16,kl,widekl") +#pragma GCC target ("sse4a,3dnow,avx,avx2,fma4,xop,aes,pclmul,popcnt,abm,lzcnt,bmi,bmi2,tbm,lwp,fsgsbase,rdrnd,f16c,fma,rtm,rdseed,prfchw,adx,fxsr,xsaveopt,avx512f,avx512er,avx512cd,avx512pf,sha,prefetchwt1,xsavec,xsaves,clflushopt,avx512bw,avx512dq,avx512vl,avx512vbmi,avx512ifma,avx5124fmaps,avx5124vnniw,avx512vpopcntdq,clwb,mwaitx,clzero,pku,sgx,rdpid,gfni,avx512vbmi2,vpclmulqdq,avx512bitalg,pconfig,wbnoinvd,avx512bf16,enqcmd,avx512vp2intersect,serialize,tsxldtrk,amx-tile,amx-int8,amx-bf16,kl,widekl,avxvnni") #include diff --git a/gcc/testsuite/gcc.target/i386/vnni_inline_error.c b/gcc/testsuite/gcc.target/i386/vnni_inline_error.c new file mode 100644 index 0000000..eaed984 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/vnni_inline_error.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -mavx512vnni -mavx512vl -mno-popcnt" } */ + +inline int __attribute__ ((__gnu_inline__, __always_inline__, target("popcnt"))) +foo () /* { dg-error "inlining failed in call to 'always_inline' .* target specific option mismatch" } */ +{ + return 0; +} + +int bar() +{ + return foo (); /* { dg-message "called from here" } */ +} diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 60ebbb3..ceee78c 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -8461,6 +8461,18 @@ proc check_effective_target_avx2 { } { } "-O0 -mavx2" ] } +# Return 1 if avxvnni instructions can be compiled. +proc check_effective_target_avxvnni { } { + return [check_no_compiler_messages avxvnni object { + typedef int __v8si __attribute__ ((__vector_size__ (32))); + __v8si + _mm256_dpbusd_epi32 (__v8si __A, __v8si __B, __v8si __C) + { + return __builtin_ia32_vpdpbusd_v8si (__A, __B, __C); + } + } "-mavxvnni" ] +} + # Return 1 if sse instructions can be compiled. proc check_effective_target_sse { } { return [check_no_compiler_messages sse object { -- cgit v1.1 From e29dd0eb733f4b9ae03e44322c7fbe8b51eff0a4 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 11 Nov 2020 11:42:45 +0000 Subject: vect: Allow vconds between different vector sizes The vcond code requires the compared vectors and the selected vectors to have both the same size and the same number of elements as each other. But the operation makes logical sense even for different vector sizes. E.g. you could compare two V4SIs and use the result to select between two V4DIs. The underlying optab already allows the compared mode and the selected mode to be specified separately. Since the vectoriser now also supports mixed vector sizes, I think we can simply remove the equal-size check and just keep the equal-lanes check. It's then up to the target to decide which (if any) mixtures of sizes it supports. gcc/ * optabs-tree.c (expand_vec_cond_expr_p): Allow the compared values and the selected values to have different mode sizes. * gimple-isel.cc (gimple_expand_vec_cond_expr): Likewise. --- gcc/gimple-isel.cc | 5 ++--- gcc/optabs-tree.c | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-isel.cc b/gcc/gimple-isel.cc index 9186ff5..b5362cc 100644 --- a/gcc/gimple-isel.cc +++ b/gcc/gimple-isel.cc @@ -199,9 +199,8 @@ gimple_expand_vec_cond_expr (gimple_stmt_iterator *gsi, unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a)); - gcc_assert (known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (cmp_op_mode)) - && known_eq (GET_MODE_NUNITS (mode), - GET_MODE_NUNITS (cmp_op_mode))); + gcc_assert (known_eq (GET_MODE_NUNITS (mode), + GET_MODE_NUNITS (cmp_op_mode))); icode = get_vcond_icode (mode, cmp_op_mode, unsignedp); if (icode == CODE_FOR_nothing) diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c index badd30b..4dfda75 100644 --- a/gcc/optabs-tree.c +++ b/gcc/optabs-tree.c @@ -377,8 +377,7 @@ expand_vec_cond_expr_p (tree value_type, tree cmp_op_type, enum tree_code code) TYPE_MODE (cmp_op_type)) != CODE_FOR_nothing) return true; - if (maybe_ne (GET_MODE_SIZE (value_mode), GET_MODE_SIZE (cmp_op_mode)) - || maybe_ne (GET_MODE_NUNITS (value_mode), GET_MODE_NUNITS (cmp_op_mode))) + if (maybe_ne (GET_MODE_NUNITS (value_mode), GET_MODE_NUNITS (cmp_op_mode))) return false; if (TREE_CODE_CLASS (code) != tcc_comparison) -- cgit v1.1 From 46c705e70e078f6a1920d92e49042125d5e18495 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 11 Nov 2020 11:42:46 +0000 Subject: aarch64: Support SVE comparisons for unpacked integers This patch adds support for comparing unpacked SVE integer vectors, such as byte elements stored in the bottom bytes of halfword containers. It also adds support for selects between unpacked SVE vectors (both integer and floating-point), since selects and compares are closely tied via the vcond optab interface. gcc/ * config/aarch64/aarch64-sve.md (@vcond_mask_): Extend from SVE_FULL to SVE_ALL. (*vcond_mask_): Likewise. (@aarch64_sel_dup): Likewise. (vcond): Extend to... (vcond): ...this, but requiring the sizes of the container modes to match. (vcondu): Extend to... (vcondu): ...this. (vec_cmp): Extend to... (vec_cmp): ...this. (vec_cmpu): Extend to... (vec_cmpu): ...this. (@aarch64_pred_cmp): Extend to... (@aarch64_pred_cmp): ...this. (*cmp_cc): Extend to... (*cmp_cc): ...this. (*cmp_ptest): Extend to... (*cmp_ptest): ...this. (*cmp_and): Extend to... (*cmp_and): ...this. gcc/testsuite/ * gcc.target/aarch64/sve/cmp_1.c: New test. * gcc.target/aarch64/sve/cmp_2.c: Likewise. * gcc.target/aarch64/sve/cond_arith_1.c: Add --param aarch64-sve-compare-costs=0 * gcc.target/aarch64/sve/cond_arith_1_run.c: Likewise. * gcc.target/aarch64/sve/cond_arith_3.c: Likewise. * gcc.target/aarch64/sve/cond_arith_3_run.c: Likewise. * gcc.target/aarch64/sve/mask_gather_load_7.c: Likewise. * gcc.target/aarch64/sve/mask_load_slp_1.c: Likewise. * gcc.target/aarch64/sve/vcond_11.c: Likewise. * gcc.target/aarch64/sve/vcond_11_run.c: Likewise. --- gcc/config/aarch64/aarch64-sve.md | 121 ++++++++++++++------- gcc/testsuite/gcc.target/aarch64/sve/cmp_1.c | 57 ++++++++++ gcc/testsuite/gcc.target/aarch64/sve/cmp_2.c | 72 ++++++++++++ .../gcc.target/aarch64/sve/cond_arith_1.c | 2 +- .../gcc.target/aarch64/sve/cond_arith_1_run.c | 2 +- .../gcc.target/aarch64/sve/cond_arith_3.c | 2 +- .../gcc.target/aarch64/sve/cond_arith_3_run.c | 2 +- .../gcc.target/aarch64/sve/mask_gather_load_7.c | 2 +- .../gcc.target/aarch64/sve/mask_load_slp_1.c | 2 +- gcc/testsuite/gcc.target/aarch64/sve/vcond_11.c | 2 +- .../gcc.target/aarch64/sve/vcond_11_run.c | 2 +- 11 files changed, 216 insertions(+), 50 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cmp_1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cmp_2.c (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 4b0a1eb..455b025 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -7379,11 +7379,11 @@ ;; UNSPEC_SEL operand order: mask, true, false (as for VEC_COND_EXPR) ;; SEL operand order: mask, true, false (define_expand "@vcond_mask_" - [(set (match_operand:SVE_FULL 0 "register_operand") - (unspec:SVE_FULL + [(set (match_operand:SVE_ALL 0 "register_operand") + (unspec:SVE_ALL [(match_operand: 3 "register_operand") - (match_operand:SVE_FULL 1 "aarch64_sve_reg_or_dup_imm") - (match_operand:SVE_FULL 2 "aarch64_simd_reg_or_zero")] + (match_operand:SVE_ALL 1 "aarch64_sve_reg_or_dup_imm") + (match_operand:SVE_ALL 2 "aarch64_simd_reg_or_zero")] UNSPEC_SEL))] "TARGET_SVE" { @@ -7396,12 +7396,25 @@ ;; - two registers ;; - a duplicated immediate and a register ;; - a duplicated immediate and zero +;; +;; For unpacked vectors, it doesn't really matter whether SEL uses the +;; the container size or the element size. If SEL used the container size, +;; it would ignore undefined bits of the predicate but would copy the +;; upper (undefined) bits of each container along with the defined bits. +;; If SEL used the element size, it would use undefined bits of the predicate +;; to select between undefined elements in each input vector. Thus the only +;; difference is whether the undefined bits in a container always come from +;; the same input as the defined bits, or whether the choice can vary +;; independently of the defined bits. +;; +;; For the other instructions, using the element size is more natural, +;; so we do that for SEL as well. (define_insn "*vcond_mask_" - [(set (match_operand:SVE_FULL 0 "register_operand" "=w, w, w, w, ?w, ?&w, ?&w") - (unspec:SVE_FULL + [(set (match_operand:SVE_ALL 0 "register_operand" "=w, w, w, w, ?w, ?&w, ?&w") + (unspec:SVE_ALL [(match_operand: 3 "register_operand" "Upa, Upa, Upa, Upa, Upl, Upl, Upl") - (match_operand:SVE_FULL 1 "aarch64_sve_reg_or_dup_imm" "w, vss, vss, Ufc, Ufc, vss, Ufc") - (match_operand:SVE_FULL 2 "aarch64_simd_reg_or_zero" "w, 0, Dz, 0, Dz, w, w")] + (match_operand:SVE_ALL 1 "aarch64_sve_reg_or_dup_imm" "w, vss, vss, Ufc, Ufc, vss, Ufc") + (match_operand:SVE_ALL 2 "aarch64_simd_reg_or_zero" "w, 0, Dz, 0, Dz, w, w")] UNSPEC_SEL))] "TARGET_SVE && (!register_operand (operands[1], mode) @@ -7422,12 +7435,12 @@ ;; of GPRs as being more expensive than duplicates of FPRs, since they ;; involve a cross-file move. (define_insn "@aarch64_sel_dup" - [(set (match_operand:SVE_FULL 0 "register_operand" "=?w, w, ??w, ?&w, ??&w, ?&w") - (unspec:SVE_FULL + [(set (match_operand:SVE_ALL 0 "register_operand" "=?w, w, ??w, ?&w, ??&w, ?&w") + (unspec:SVE_ALL [(match_operand: 3 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") - (vec_duplicate:SVE_FULL + (vec_duplicate:SVE_ALL (match_operand: 1 "register_operand" "r, w, r, w, r, w")) - (match_operand:SVE_FULL 2 "aarch64_simd_reg_or_zero" "0, 0, Dz, Dz, w, w")] + (match_operand:SVE_ALL 2 "aarch64_simd_reg_or_zero" "0, 0, Dz, Dz, w, w")] UNSPEC_SEL))] "TARGET_SVE" "@ @@ -7448,34 +7461,34 @@ ;; Integer (signed) vcond. Don't enforce an immediate range here, since it ;; depends on the comparison; leave it to aarch64_expand_sve_vcond instead. -(define_expand "vcond" - [(set (match_operand:SVE_FULL 0 "register_operand") - (if_then_else:SVE_FULL +(define_expand "vcond" + [(set (match_operand:SVE_ALL 0 "register_operand") + (if_then_else:SVE_ALL (match_operator 3 "comparison_operator" - [(match_operand: 4 "register_operand") - (match_operand: 5 "nonmemory_operand")]) - (match_operand:SVE_FULL 1 "nonmemory_operand") - (match_operand:SVE_FULL 2 "nonmemory_operand")))] - "TARGET_SVE" + [(match_operand:SVE_I 4 "register_operand") + (match_operand:SVE_I 5 "nonmemory_operand")]) + (match_operand:SVE_ALL 1 "nonmemory_operand") + (match_operand:SVE_ALL 2 "nonmemory_operand")))] + "TARGET_SVE && == " { - aarch64_expand_sve_vcond (mode, mode, operands); + aarch64_expand_sve_vcond (mode, mode, operands); DONE; } ) ;; Integer vcondu. Don't enforce an immediate range here, since it ;; depends on the comparison; leave it to aarch64_expand_sve_vcond instead. -(define_expand "vcondu" - [(set (match_operand:SVE_FULL 0 "register_operand") - (if_then_else:SVE_FULL +(define_expand "vcondu" + [(set (match_operand:SVE_ALL 0 "register_operand") + (if_then_else:SVE_ALL (match_operator 3 "comparison_operator" - [(match_operand: 4 "register_operand") - (match_operand: 5 "nonmemory_operand")]) - (match_operand:SVE_FULL 1 "nonmemory_operand") - (match_operand:SVE_FULL 2 "nonmemory_operand")))] - "TARGET_SVE" + [(match_operand:SVE_I 4 "register_operand") + (match_operand:SVE_I 5 "nonmemory_operand")]) + (match_operand:SVE_ALL 1 "nonmemory_operand") + (match_operand:SVE_ALL 2 "nonmemory_operand")))] + "TARGET_SVE && == " { - aarch64_expand_sve_vcond (mode, mode, operands); + aarch64_expand_sve_vcond (mode, mode, operands); DONE; } ) @@ -7520,8 +7533,8 @@ [(parallel [(set (match_operand: 0 "register_operand") (match_operator: 1 "comparison_operator" - [(match_operand:SVE_FULL_I 2 "register_operand") - (match_operand:SVE_FULL_I 3 "nonmemory_operand")])) + [(match_operand:SVE_I 2 "register_operand") + (match_operand:SVE_I 3 "nonmemory_operand")])) (clobber (reg:CC_NZC CC_REGNUM))])] "TARGET_SVE" { @@ -7538,8 +7551,8 @@ [(parallel [(set (match_operand: 0 "register_operand") (match_operator: 1 "comparison_operator" - [(match_operand:SVE_FULL_I 2 "register_operand") - (match_operand:SVE_FULL_I 3 "nonmemory_operand")])) + [(match_operand:SVE_I 2 "register_operand") + (match_operand:SVE_I 3 "nonmemory_operand")])) (clobber (reg:CC_NZC CC_REGNUM))])] "TARGET_SVE" { @@ -7550,14 +7563,38 @@ ) ;; Predicated integer comparisons. +;; +;; For unpacked vectors, only the lowpart element in each input container +;; has a defined value, and only the predicate bits associated with +;; those elements are defined. For example, when comparing two VNx2SIs: +;; +;; - The VNx2SIs can be seem as VNx2DIs in which the low halves of each +;; DI container store an SI element. The upper bits of each DI container +;; are undefined. +;; +;; - Alternatively, the VNx2SIs can be seen as VNx4SIs in which the +;; even elements are defined and the odd elements are undefined. +;; +;; - The associated predicate mode is VNx2BI. This means that only the +;; low bit in each predicate byte is defined (on input and on output). +;; +;; - We use a .s comparison to compare VNx2SIs, under the control of a +;; VNx2BI governing predicate, to produce a VNx2BI result. If we view +;; the .s operation as operating on VNx4SIs then for odd lanes: +;; +;; - the input governing predicate bit is undefined +;; - the SI elements being compared are undefined +;; - the predicate result bit is therefore undefined, but +;; - the predicate result bit is in the undefined part of a VNx2BI, +;; so its value doesn't matter anyway. (define_insn "@aarch64_pred_cmp" [(set (match_operand: 0 "register_operand" "=Upa, Upa") (unspec: [(match_operand: 1 "register_operand" "Upl, Upl") (match_operand:SI 2 "aarch64_sve_ptrue_flag") (SVE_INT_CMP: - (match_operand:SVE_FULL_I 3 "register_operand" "w, w") - (match_operand:SVE_FULL_I 4 "aarch64_sve_cmp__operand" ", w"))] + (match_operand:SVE_I 3 "register_operand" "w, w") + (match_operand:SVE_I 4 "aarch64_sve_cmp__operand" ", w"))] UNSPEC_PRED_Z)) (clobber (reg:CC_NZC CC_REGNUM))] "TARGET_SVE" @@ -7578,8 +7615,8 @@ [(match_operand 6) (match_operand:SI 7 "aarch64_sve_ptrue_flag") (SVE_INT_CMP: - (match_operand:SVE_FULL_I 2 "register_operand" "w, w") - (match_operand:SVE_FULL_I 3 "aarch64_sve_cmp__operand" ", w"))] + (match_operand:SVE_I 2 "register_operand" "w, w") + (match_operand:SVE_I 3 "aarch64_sve_cmp__operand" ", w"))] UNSPEC_PRED_Z)] UNSPEC_PTEST)) (set (match_operand: 0 "register_operand" "=Upa, Upa") @@ -7614,8 +7651,8 @@ [(match_operand 6) (match_operand:SI 7 "aarch64_sve_ptrue_flag") (SVE_INT_CMP: - (match_operand:SVE_FULL_I 2 "register_operand" "w, w") - (match_operand:SVE_FULL_I 3 "aarch64_sve_cmp__operand" ", w"))] + (match_operand:SVE_I 2 "register_operand" "w, w") + (match_operand:SVE_I 3 "aarch64_sve_cmp__operand" ", w"))] UNSPEC_PRED_Z)] UNSPEC_PTEST)) (clobber (match_scratch: 0 "=Upa, Upa"))] @@ -7642,8 +7679,8 @@ [(match_operand 4) (const_int SVE_KNOWN_PTRUE) (SVE_INT_CMP: - (match_operand:SVE_FULL_I 2 "register_operand" "w, w") - (match_operand:SVE_FULL_I 3 "aarch64_sve_cmp__operand" ", w"))] + (match_operand:SVE_I 2 "register_operand" "w, w") + (match_operand:SVE_I 3 "aarch64_sve_cmp__operand" ", w"))] UNSPEC_PRED_Z) (match_operand: 1 "register_operand" "Upl, Upl"))) (clobber (reg:CC_NZC CC_REGNUM))] diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cmp_1.c b/gcc/testsuite/gcc.target/aarch64/sve/cmp_1.c new file mode 100644 index 0000000..7cf66c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cmp_1.c @@ -0,0 +1,57 @@ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include + +#define TEST_PAIR(TYPE1, TYPE2) \ + void \ + f_##TYPE1##_##TYPE2 (TYPE1 *restrict x, \ + TYPE2 *restrict g, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + if (g[i] < 4) \ + x[i] += 1; \ + } + +#define TEST_SINGLE(TYPE) \ + TEST_PAIR (TYPE, int8_t) \ + TEST_PAIR (TYPE, uint8_t) \ + TEST_PAIR (TYPE, int16_t) \ + TEST_PAIR (TYPE, uint16_t) \ + TEST_PAIR (TYPE, int32_t) \ + TEST_PAIR (TYPE, uint32_t) \ + TEST_PAIR (TYPE, int64_t) \ + TEST_PAIR (TYPE, uint64_t) + +TEST_SINGLE (int8_t) +TEST_SINGLE (uint8_t) +TEST_SINGLE (int16_t) +TEST_SINGLE (uint16_t) +TEST_SINGLE (int32_t) +TEST_SINGLE (uint32_t) +TEST_SINGLE (int64_t) +TEST_SINGLE (uint64_t) + +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.b,} 8 } } */ +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.h,} 8 } } */ +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.s,} 8 } } */ +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.d,} 8 } } */ + +/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.h,} 16 } } */ +/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s,} 8 } } */ +/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d,} 8 } } */ + +/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.s,} 24 } } */ +/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d,} 8 } } */ + +/* { dg-final { scan-assembler-times {\tld1d\tz[0-9]+\.d,} 32 } } */ + +/* { dg-final { scan-assembler-times {\tcmpl[et]\tp[0-9]+\.b,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[so]\tp[0-9]+\.b,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[et]\tp[0-9]+\.h,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[so]\tp[0-9]+\.h,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[et]\tp[0-9]+\.s,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[so]\tp[0-9]+\.s,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[et]\tp[0-9]+\.d,} 8 } } */ +/* { dg-final { scan-assembler-times {\tcmpl[so]\tp[0-9]+\.d,} 8 } } */ + +/* { dg-final { scan-assembler-not {\tpunpk} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cmp_2.c b/gcc/testsuite/gcc.target/aarch64/sve/cmp_2.c new file mode 100644 index 0000000..b221206 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cmp_2.c @@ -0,0 +1,72 @@ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include + +#define TEST_PAIR(TYPE1, TYPE2) \ + void \ + f_##TYPE1##_##TYPE2 (TYPE1 *restrict x, TYPE1 y, TYPE1 z, \ + TYPE2 *restrict g, TYPE2 h, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = g[i] < h ? y : z; \ + } + +#define TEST_SINGLE(TYPE) \ + TEST_PAIR (TYPE, int8_t) \ + TEST_PAIR (TYPE, uint8_t) \ + TEST_PAIR (TYPE, int16_t) \ + TEST_PAIR (TYPE, uint16_t) \ + TEST_PAIR (TYPE, int32_t) \ + TEST_PAIR (TYPE, uint32_t) \ + TEST_PAIR (TYPE, int64_t) \ + TEST_PAIR (TYPE, uint64_t) + +TEST_SINGLE (int8_t) +TEST_SINGLE (uint8_t) +TEST_SINGLE (int16_t) +TEST_SINGLE (uint16_t) +TEST_SINGLE (int32_t) +TEST_SINGLE (uint32_t) +TEST_SINGLE (float) +TEST_SINGLE (int64_t) +TEST_SINGLE (uint64_t) +TEST_SINGLE (double) + +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.b,} 4 } } */ +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.h,} 4 } } */ +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.s,} 6 } } */ +/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.d,} 6 } } */ + +/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.h,} 8 } } */ +/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s,} 6 } } */ +/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d,} 6 } } */ + +/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.s,} 14 } } */ +/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d,} 6 } } */ + +/* { dg-final { scan-assembler-times {\tld1d\tz[0-9]+\.d,} 20 } } */ + +/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.b,} 4 } } */ +/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.h,} 4 } } */ +/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.s,} 4 } } */ +/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.d,} 4 } } */ + +/* { dg-final { scan-assembler-times {\tst1h\tz[0-9]+\.h,} 8 } } */ +/* { dg-final { scan-assembler-times {\tst1h\tz[0-9]+\.s,} 4 } } */ +/* { dg-final { scan-assembler-times {\tst1h\tz[0-9]+\.d,} 4 } } */ + +/* { dg-final { scan-assembler-times {\tst1w\tz[0-9]+\.s,} 18 } } */ +/* { dg-final { scan-assembler-times {\tst1w\tz[0-9]+\.d,} 6 } } */ + +/* { dg-final { scan-assembler-times {\tst1d\tz[0-9]+\.d,} 24 } } */ + +/* { dg-final { scan-assembler-times {\tcmp(?:h[is]|l[os])\tp[0-9]+\.b,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp[lg][et]\tp[0-9]+\.b,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp(?:h[is]|l[os])\tp[0-9]+\.h,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp[lg][et]\tp[0-9]+\.h,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp(?:h[is]|l[os])\tp[0-9]+\.s,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp[lg][et]\tp[0-9]+\.s,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp(?:h[is]|l[os])\tp[0-9]+\.d,} 10 } } */ +/* { dg-final { scan-assembler-times {\tcmp[lg][et]\tp[0-9]+\.d,} 10 } } */ + +/* { dg-final { scan-assembler-not {\tpunpk} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1.c index 52138d2..d831e9c 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize" } */ +/* { dg-options "-O2 -ftree-vectorize --param aarch64-sve-compare-costs=0" } */ #include diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1_run.c index 876f98f..5808e0a 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1_run.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_1_run.c @@ -1,5 +1,5 @@ /* { dg-do run { target aarch64_sve_hw } } */ -/* { dg-options "-O2 -ftree-vectorize" } */ +/* { dg-options "-O2 -ftree-vectorize --param aarch64-sve-compare-costs=0" } */ #include "cond_arith_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3.c index 94eb255..068e0b6 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize" } */ +/* { dg-options "-O2 -ftree-vectorize --param aarch64-sve-compare-costs=0" } */ #include diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3_run.c index 31457da..d258004 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3_run.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_arith_3_run.c @@ -1,5 +1,5 @@ /* { dg-do run { target aarch64_sve_hw } } */ -/* { dg-options "-O2 -ftree-vectorize" } */ +/* { dg-options "-O2 -ftree-vectorize --param aarch64-sve-compare-costs=0" } */ #include "cond_arith_3.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/mask_gather_load_7.c b/gcc/testsuite/gcc.target/aarch64/sve/mask_gather_load_7.c index cd2661e..687716e 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/mask_gather_load_7.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/mask_gather_load_7.c @@ -1,5 +1,5 @@ /* { dg-do assemble { target aarch64_asm_sve_ok } } */ -/* { dg-options "-O2 -ftree-vectorize -ffast-math --save-temps" } */ +/* { dg-options "-O2 -ftree-vectorize -ffast-math --save-temps --param aarch64-sve-compare-costs=0" } */ #include diff --git a/gcc/testsuite/gcc.target/aarch64/sve/mask_load_slp_1.c b/gcc/testsuite/gcc.target/aarch64/sve/mask_load_slp_1.c index 78c70b2..a38b92d 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/mask_load_slp_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/mask_load_slp_1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize" } */ +/* { dg-options "-O2 -ftree-vectorize --param aarch64-sve-compare-costs=0" } */ #include diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vcond_11.c b/gcc/testsuite/gcc.target/aarch64/sve/vcond_11.c index 3c9e340..4efcf3a 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/vcond_11.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/vcond_11.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize -march=armv8-a+sve" } */ +/* { dg-options "-O2 -ftree-vectorize -march=armv8-a+sve --param aarch64-sve-compare-costs=0" } */ #include diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vcond_11_run.c b/gcc/testsuite/gcc.target/aarch64/sve/vcond_11_run.c index 9a4edb8..4cbe4a6 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/vcond_11_run.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/vcond_11_run.c @@ -1,5 +1,5 @@ /* { dg-do run { target aarch64_sve_hw } } */ -/* { dg-options "-O2 -ftree-vectorize -march=armv8-a+sve" } */ +/* { dg-options "-O2 -ftree-vectorize -march=armv8-a+sve --param aarch64-sve-compare-costs=0" } */ #include "vcond_11.c" -- cgit v1.1 From bd87cc14ebdb6789e067fb1828d5808407c308b3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Nov 2020 11:51:59 +0100 Subject: tree-optimization/97623 - Avoid PRE hoist insertion iteration The recent previous change in this area limited hoist insertion iteration via a param but the following is IMHO better since we are not really interested in PRE opportunities exposed by hoisting but only the other way around. So this moves hoist insertion after PRE iteration finished and removes hoist insertion iteration alltogether. 2020-11-11 Richard Biener PR tree-optimization/97623 * params.opt (-param=max-pre-hoist-insert-iterations): Remove again. * doc/invoke.texi (max-pre-hoist-insert-iterations): Likewise. * tree-ssa-pre.c (insert): Move hoist insertion after PRE insertion iteration and do not iterate it. * gcc.dg/tree-ssa/ssa-hoist-3.c: Adjust. * gcc.dg/tree-ssa/ssa-hoist-7.c: Likewise. * gcc.dg/tree-ssa/ssa-pre-30.c: Likewise. --- gcc/doc/invoke.texi | 5 ----- gcc/params.opt | 4 ---- gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-3.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-7.c | 4 ++-- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c | 2 +- gcc/tree-ssa-pre.c | 34 +++++++++++++++++++---------- 6 files changed, 26 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 18ca759..8d0d213 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -13446,11 +13446,6 @@ is aborted and the load or store is not considered redundant. The number of queries is algorithmically limited to the number of stores on all paths from the load to the function entry. -@item max-pre-hoist-insert-iterations -The maximum number of iterations doing insertion during code -hoisting which is done as part of the partial redundancy elimination -insertion phase. - @item ira-max-loops-num IRA uses regional register allocation by default. If a function contains more loops than the number given by this parameter, only at most diff --git a/gcc/params.opt b/gcc/params.opt index a33a371..7bac39a 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -597,10 +597,6 @@ Maximum depth of sqrt chains to use when synthesizing exponentiation by a real c Common Joined UInteger Var(param_max_predicted_iterations) Init(100) IntegerRange(0, 65536) Param Optimization The maximum number of loop iterations we predict statically. --param=max-pre-hoist-insert-iterations= -Common Joined UInteger Var(param_max_pre_hoist_insert_iterations) Init(3) Param Optimization -The maximum number of insert iterations done for PRE code hoisting. - -param=max-reload-search-insns= Common Joined UInteger Var(param_max_reload_search_insns) Init(100) Param Optimization The maximum number of instructions to search backward when looking for equivalent reload. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-3.c index 51ba59c..de3051b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-3.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-3.c @@ -15,4 +15,4 @@ int test (int a, int b, int c, int g) /* We should hoist and CSE only the multiplication. */ /* { dg-final { scan-tree-dump-times " \\* " 1 "pre" } } */ -/* { dg-final { scan-tree-dump "Insertions: 1" "pre" } } */ +/* { dg-final { scan-tree-dump "HOIST inserted: 1" "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-7.c index ce9cec6..fdb6a3e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-hoist-7.c @@ -49,6 +49,6 @@ void foo (int a, int b, int c, int d, int e, int x, int y, int z) /* Now inserting x + y five times is unnecessary but the cascading cannot be avoided with the simple-minded dataflow. But make sure - we do the insertions all in the first iteration. */ -/* { dg-final { scan-tree-dump "insert iterations == 2" "pre" } } */ + we do not iterate PRE insertion. */ +/* { dg-final { scan-tree-dump "insert iterations == 1" "pre" } } */ /* { dg-final { scan-tree-dump "HOIST inserted: 5" "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c index 59af63a..cf93173 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-30.c @@ -24,4 +24,4 @@ bar (int b, int x) /* We should see the partial redundant loads of f even though they are using different types (of the same size). */ -/* { dg-final { scan-tree-dump-times "Replaced MEM" 2 "pre" } } */ +/* { dg-final { scan-tree-dump-times "Replaced MEM" 3 "pre" } } */ diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index da2b689..d90249c 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -3695,18 +3695,6 @@ insert (void) fprintf (dump_file, "Starting insert iteration %d\n", num_iterations); changed = false; - /* Insert expressions for hoisting. Do a backward walk here since - inserting into BLOCK exposes new opportunities in its predecessors. - Since PRE and hoist insertions can cause back-to-back iteration - limit that on the hoist side. */ - if (flag_code_hoisting - && num_iterations <= param_max_pre_hoist_insert_iterations) - for (int idx = rpo_num - 1; idx >= 0; --idx) - { - basic_block block = BASIC_BLOCK_FOR_FN (cfun, rpo[idx]); - if (EDGE_COUNT (block->succs) >= 2) - changed |= do_hoist_insertion (block); - } for (int idx = 0; idx < rpo_num; ++idx) { basic_block block = BASIC_BLOCK_FOR_FN (cfun, rpo[idx]); @@ -3754,6 +3742,28 @@ insert (void) statistics_histogram_event (cfun, "insert iterations", num_iterations); + /* AVAIL_OUT is not needed after insertion so we don't have to + propagate NEW_SETS from hoist insertion. */ + FOR_ALL_BB_FN (bb, cfun) + { + bitmap_set_pool.remove (NEW_SETS (bb)); + NEW_SETS (bb) = NULL; + } + + /* Insert expressions for hoisting. Do a backward walk here since + inserting into BLOCK exposes new opportunities in its predecessors. + Since PRE and hoist insertions can cause back-to-back iteration + and we are interested in PRE insertion exposed hoisting opportunities + but not in hoisting exposed PRE ones do hoist insertion only after + PRE insertion iteration finished and do not iterate it. */ + if (flag_code_hoisting) + for (int idx = rpo_num - 1; idx >= 0; --idx) + { + basic_block block = BASIC_BLOCK_FOR_FN (cfun, rpo[idx]); + if (EDGE_COUNT (block->succs) >= 2) + changed |= do_hoist_insertion (block); + } + free (rpo); } -- cgit v1.1 From 4ac93608d7e33a3e10bbd8d50259bc00a7d01237 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Nov 2020 12:49:57 +0100 Subject: testsuite/97797 - adjust GIMPLE tests for sizetype Tested on x86_64-unknown-linux-gnu, pushed. 2020-11-11 Richard Biener PR testsuite/97797 * gcc.dg/torture/ssa-fre-5.c: Use __SIZETYPE__ where appropriate. * gcc.dg/torture/ssa-fre-6.c: Likewise. --- gcc/testsuite/gcc.dg/torture/ssa-fre-5.c | 8 ++++---- gcc/testsuite/gcc.dg/torture/ssa-fre-6.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c b/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c index 180fd72..1915b9a 100644 --- a/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c +++ b/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c @@ -11,14 +11,14 @@ foo () int * p; int i; int x[4]; - long unsigned int _1; - long unsigned int _2; + __SIZETYPE__ _1; + __SIZETYPE__ _2; int _7; __BB(2): i_3 = 0; - _1 = (long unsigned int) i_3; - _2 = _1 * 4ul; + _1 = (__SIZETYPE__) i_3; + _2 = _1 * _Literal (__SIZETYPE__) 4; p_4 = _Literal (int *) &x + _2; __MEM ((v4si *)p_4) = _Literal (v4si) { 1, 2, 3, 4 }; _7 = x[0]; diff --git a/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c b/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c index 2c4235f..041d921 100644 --- a/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c +++ b/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c @@ -11,14 +11,14 @@ foo () int * p; int i; int x[4]; - long unsigned int _1; - long unsigned int _2; + __SIZETYPE__ _1; + __SIZETYPE__ _2; int _7; __BB(2): i_3 = 0; - _1 = (long unsigned int) i_3; - _2 = _1 * 4ul; + _1 = (__SIZETYPE__) i_3; + _2 = _1 * _Literal (__SIZETYPE__) 4; p_4 = _Literal (int *) &x + _2; __MEM ((v4si *)p_4) = _Literal (v4si) {}; _7 = x[0]; -- cgit v1.1 From 1f8fc1f458c4a66618c35d8e292fff6e9dce9f12 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 11 Nov 2020 13:53:01 +0100 Subject: Fix internal error with Shift_Right operator on signed type This is a regression present on the mainline and 10 branch in the form of an ICE with a shift operator applied to a variable of a signed type, and which is caused by a type mismatch. gcc/ada/ChangeLog: * gcc-interface/trans.c (gnat_to_gnu) : Also convert GNU_MAX_SHIFT if the type of the operation has been changed. * gcc-interface/utils.c (can_materialize_object_renaming_p): Add pair of missing parentheses. gcc/testsuite/ChangeLog: * gnat.dg/shift1.adb: New test. --- gcc/ada/gcc-interface/trans.c | 2 ++ gcc/ada/gcc-interface/utils.c | 2 +- gcc/testsuite/gnat.dg/shift1.adb | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gnat.dg/shift1.adb (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 059e1a4..d0663a2 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -7085,6 +7085,8 @@ gnat_to_gnu (Node_Id gnat_node) if (TREE_CODE (gnu_lhs) == INTEGER_CST && ignore_lhs_overflow) TREE_OVERFLOW (gnu_lhs) = TREE_OVERFLOW (gnu_old_lhs); gnu_rhs = convert (gnu_type, gnu_rhs); + if (gnu_max_shift) + gnu_max_shift = convert (gnu_type, gnu_max_shift); } /* For signed integer addition, subtraction and multiplication, do an diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index d50872f..dfde06e 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5837,7 +5837,7 @@ can_materialize_object_renaming_p (Node_Id expr) { expr = Original_Node (expr); - switch Nkind (expr) + switch (Nkind (expr)) { case N_Identifier: case N_Expanded_Name: diff --git a/gcc/testsuite/gnat.dg/shift1.adb b/gcc/testsuite/gnat.dg/shift1.adb new file mode 100644 index 0000000..85a0fec --- /dev/null +++ b/gcc/testsuite/gnat.dg/shift1.adb @@ -0,0 +1,15 @@ +-- { dg-do compile } +-- { dg-options "-gnatws" } + +procedure Shift1 is + + type T_Integer_8 is range -2 ** 7 .. 2 ** 7 - 1 + with Size => 8; + + pragma Provide_Shift_Operators (T_Integer_8); + + X : T_Integer_8; + +begin + X := Shift_Right (X, 1); +end; -- cgit v1.1 From 1c91516aeb8362696786e17f83d8366de9a31f81 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 11 Nov 2020 14:39:32 +0100 Subject: Fix internal error on chain of constants with -gnatc gcc/ada/ChangeLog: * gcc-interface/decl.c (gnat_to_gnu_entity) : In case the constant is not being defined, get the expression in type annotation mode only if its type is elementary. --- gcc/ada/gcc-interface/decl.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 4e6dc84..baae58a 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -667,21 +667,24 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) /* If we have a constant that we are not defining, get the expression it was defined to represent. This is necessary to avoid generating dumb - elaboration code in simple cases, but we may throw it away later if it + elaboration code in simple cases, and we may throw it away later if it is not a constant. But do not do it for dispatch tables because they are only referenced indirectly and we need to have a consistent view of the exported and of the imported declarations of the tables from external units for them to be properly merged in LTO mode. Moreover - simply do not retrieve the expression it if it is an allocator since + simply do not retrieve the expression if it is an allocator because the designated type might still be dummy at this point. Note that we invoke gnat_to_gnu_external and not gnat_to_gnu because the expression may contain N_Expression_With_Actions nodes and thus declarations of - objects from other units that we need to discard. */ + objects from other units that we need to discard. Note also that we + need to do it even if we are only annotating types, so as to be able + to validate representation clauses using constants. */ if (!definition && !No_Initialization (gnat_decl) && !Is_Dispatch_Table_Entity (gnat_entity) && Present (gnat_temp = Expression (gnat_decl)) - && Nkind (gnat_temp) != N_Allocator) + && Nkind (gnat_temp) != N_Allocator + && (Is_Elementary_Type (Etype (gnat_entity)) || !type_annotate_only)) gnu_expr = gnat_to_gnu_external (gnat_temp); /* ... fall through ... */ -- cgit v1.1 From ec1b8711945e99677fe5b135d343781bc2e106ad Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 11 Nov 2020 14:52:45 +0100 Subject: Fix segfault on elaboration of empty 1-element array at -O This is a rather obscure case where the elaboration of an empty array whose base type is an array type of length at most 1 goes awry when the code is compiled with optimization. gcc/ada/ChangeLog: * gcc-interface/trans.c (can_be_lower_p): Remove. (Regular_Loop_to_gnu): Add ENTRY_COND unconditionally if BOTTOM_COND is non-zero. gcc/testsuite/ChangeLog: * gnat.dg/opt89.adb: New test. --- gcc/ada/gcc-interface/trans.c | 49 ++++++----------------------------------- gcc/testsuite/gnat.dg/opt89.adb | 18 +++++++++++++++ 2 files changed, 25 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/opt89.adb (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index d0663a2..065fcd2 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -2814,38 +2814,6 @@ can_equal_max_val_p (tree val, tree type, bool reverse) return can_equal_min_or_max_val_p (val, type, !reverse); } -/* Return true if VAL1 can be lower than VAL2. */ - -static bool -can_be_lower_p (tree val1, tree val2) -{ - if (TREE_CODE (val1) == NOP_EXPR) - { - tree type = TREE_TYPE (TREE_OPERAND (val1, 0)); - if (can_be_lower_p (TYPE_MAX_VALUE (type), TYPE_MIN_VALUE (type))) - return true; - - val1 = TYPE_MIN_VALUE (type); - } - - if (TREE_CODE (val1) != INTEGER_CST) - return true; - - if (TREE_CODE (val2) == NOP_EXPR) - { - tree type = TREE_TYPE (TREE_OPERAND (val2, 0)); - if (can_be_lower_p (TYPE_MAX_VALUE (type), TYPE_MIN_VALUE (type))) - return true; - - val2 = TYPE_MAX_VALUE (type); - } - - if (TREE_CODE (val2) != INTEGER_CST) - return true; - - return tree_int_cst_lt (val1, val2); -} - /* Replace EXPR1 and EXPR2 by invariant expressions if possible. Return true if both expressions have been replaced and false otherwise. */ @@ -3126,19 +3094,16 @@ Regular_Loop_to_gnu (Node_Id gnat_node, tree *gnu_cond_expr_p) } /* If we use the BOTTOM_COND, we can turn the test into an inequality - test but we may have to add ENTRY_COND to protect the empty loop. */ + test but we have to add ENTRY_COND to protect the empty loop. */ if (LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt)) { test_code = NE_EXPR; - if (can_be_lower_p (gnu_high, gnu_low)) - { - gnu_cond_expr - = build3 (COND_EXPR, void_type_node, - build_binary_op (LE_EXPR, boolean_type_node, - gnu_low, gnu_high), - NULL_TREE, alloc_stmt_list ()); - set_expr_location_from_node (gnu_cond_expr, gnat_iter_scheme); - } + gnu_cond_expr + = build3 (COND_EXPR, void_type_node, + build_binary_op (LE_EXPR, boolean_type_node, + gnu_low, gnu_high), + NULL_TREE, alloc_stmt_list ()); + set_expr_location_from_node (gnu_cond_expr, gnat_iter_scheme); } /* Open a new nesting level that will surround the loop to declare the diff --git a/gcc/testsuite/gnat.dg/opt89.adb b/gcc/testsuite/gnat.dg/opt89.adb new file mode 100644 index 0000000..3752008 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt89.adb @@ -0,0 +1,18 @@ +-- { dg-do run } +-- { dg-options "-O" } + +procedure Opt89 is + + type Rec is record + I : Integer := 3; + end record; + + subtype Index is Natural range 0..0; + + type Arr is array (Index range <>) of Rec; + + X : Arr (0 .. -1); + +begin + null; +end; -- cgit v1.1 From 4e1a215870a4194c9ca884ef838103c094aa38c8 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 11 Nov 2020 15:08:16 +0100 Subject: Fix biased integer arithmetic The Ada compiler uses a biased representation when a size clause reserves fewer bits than normal either for the lower or for the upper bound. gcc/ada/ChangeLog: * gcc-interface/trans.c (build_binary_op_trapv): Convert operands to the result type before doing generic overflow checking. gcc/testsuite/ChangeLog: * gnat.dg/bias2.adb: New test. --- gcc/ada/gcc-interface/trans.c | 5 +++++ gcc/testsuite/gnat.dg/bias2.adb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 gcc/testsuite/gnat.dg/bias2.adb (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 065fcd2..7be8463 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -9361,6 +9361,11 @@ build_binary_op_trapv (enum tree_code code, tree gnu_type, tree left, /* If no operand is a constant, we use the generic implementation. */ if (TREE_CODE (lhs) != INTEGER_CST && TREE_CODE (rhs) != INTEGER_CST) { + /* First convert the operands to the result type like build_binary_op. + This is where the bias is made explicit for biased types. */ + lhs = convert (gnu_type, lhs); + rhs = convert (gnu_type, rhs); + /* Never inline a 64-bit mult for a 32-bit target, it's way too long. */ if (code == MULT_EXPR && precision == 64 && BITS_PER_WORD < 64) { diff --git a/gcc/testsuite/gnat.dg/bias2.adb b/gcc/testsuite/gnat.dg/bias2.adb new file mode 100644 index 0000000..a32e9a3 --- /dev/null +++ b/gcc/testsuite/gnat.dg/bias2.adb @@ -0,0 +1,33 @@ +-- { dg-do run } + +procedure Bias2 is + + type Biased_T is range 1 .. 2 ** 6; + for Biased_T'Size use 6; -- { dg-warning "biased representation" } + X, Y : Biased_T; + +begin + X := 1; + Y := 1; + if X + Y /= 2 then + raise Program_Error; + end if; + + X := 2; + Y := 1; + if X - Y /= 1 then + raise Program_Error; + end if; + + X := 2; + Y := 3; + if X * Y /= 6 then + raise Program_Error; + end if; + + X := 24; + Y := 3; + if X / Y /= 8 then + raise Program_Error; + end if; +end; -- cgit v1.1 From ce2d0ce29312a50296919565818edbb98543ae18 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 11 Nov 2020 15:24:28 +0100 Subject: Remove superfluous call to Base_Type gcc/ada/ChangeLog: * gcc-interface/gigi.h: Remove ^L characters throughout. * gcc-interface/decl.c: Likewise. * gcc-interface/utils.c: Likewise. * gcc-interface/utils2.c: Likewise. * gcc-interface/trans.c (gnat_to_gnu) : Do not explicitly go to the base type for the Has_Constrained_Partial_View flag. --- gcc/ada/gcc-interface/decl.c | 38 +++++++++++------------ gcc/ada/gcc-interface/gigi.h | 2 +- gcc/ada/gcc-interface/trans.c | 70 ++++++++++++++++++++---------------------- gcc/ada/gcc-interface/utils.c | 62 ++++++++++++++++++------------------- gcc/ada/gcc-interface/utils2.c | 32 +++++++++---------- 5 files changed, 101 insertions(+), 103 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index baae58a..fa17ad9 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -261,7 +261,7 @@ typedef struct { } intrin_binding_t; static bool intrin_profiles_compatible_p (intrin_binding_t *); - + /* Given GNAT_ENTITY, a GNAT defining identifier node, which denotes some Ada entity, return the equivalent GCC tree for that entity (a ..._DECL node) and associate the ..._DECL node with the input GNAT defining identifier. @@ -6578,7 +6578,7 @@ update_n_elem (tree n_elem, tree min, tree max) return n_elem; } - + /* Given GNAT_ENTITY, elaborate all expressions that are required to be elaborated at the point of its definition, but do nothing else. */ @@ -6635,7 +6635,7 @@ elaborate_entity (Entity_Id gnat_entity) } } - + /* Prepend to ATTR_LIST an entry for an attribute with provided TYPE, NAME, ARGS and ERROR_POINT. */ @@ -6750,7 +6750,7 @@ prepend_attributes (struct attrib **attr_list, Entity_Id gnat_entity) if (Nkind (gnat_temp) == N_Pragma) prepend_one_attribute_pragma (attr_list, gnat_temp); } - + /* Given a GNAT tree GNAT_EXPR, for an expression which is a value within a type definition (either a bound or a discriminant value) for GNAT_ENTITY, return the GCC tree to use for that expression. S is the suffix to use @@ -6957,7 +6957,7 @@ elaborate_reference (tree ref, Entity_Id gnat_entity, bool definition, struct er_data er = { gnat_entity, definition, 0 }; return gnat_rewrite_reference (ref, elaborate_reference_1, &er, init); } - + /* Given a GNU tree and a GNAT list of choices, generate an expression to test the value passed against the list of choices. */ @@ -7054,7 +7054,7 @@ choices_to_gnu (tree gnu_operand, Node_Id gnat_choices) return gnu_result; } - + /* Adjust PACKED setting as passed to gnat_to_gnu_field for a field of type FIELD_TYPE to be placed in RECORD_TYPE. Return the result. */ @@ -7467,7 +7467,7 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed, return gnu_field; } - + /* Return true if at least one member of COMPONENT_LIST needs strict alignment. */ @@ -8433,7 +8433,7 @@ components_to_record (Node_Id gnat_component_list, Entity_Id gnat_record_type, return (gnu_rep_list && !p_gnu_rep_list) || variants_have_rep; } - + /* Given GNU_SIZE, a GCC tree representing a size, return a Uint to be placed into an Esize, Component_Bit_Offset, or Component_Size value in the GNAT tree. */ @@ -8801,7 +8801,7 @@ annotate_rep (Entity_Id gnat_entity, tree gnu_type) } } } - + /* Scan all fields in GNU_TYPE and return a TREE_LIST where TREE_PURPOSE is the FIELD_DECL and TREE_VALUE a TREE_VEC containing the byte position, the value to be placed into DECL_OFFSET_ALIGN and the bit position. The list @@ -8959,7 +8959,7 @@ build_variant_list (tree gnu_qual_union_type, Node_Id gnat_variant_part, return gnu_list; } - + /* If SIZE has overflowed, return the maximum valid size, which is the upper bound of the signed sizetype in bits, rounded down to ALIGN. Otherwise return SIZE unmodified. */ @@ -9103,7 +9103,7 @@ validate_size (Uint uint_size, tree gnu_type, Entity_Id gnat_object, return size; } - + /* Similarly, but both validate and process a value of RM size. This routine is only called for types. */ @@ -9180,7 +9180,7 @@ set_rm_size (Uint uint_size, tree gnu_type, Entity_Id gnat_entity) && !TYPE_FAT_POINTER_P (gnu_type)) SET_TYPE_ADA_SIZE (gnu_type, size); } - + /* ALIGNMENT is a Uint giving the alignment specified for GNAT_ENTITY, a type or object whose present alignment is ALIGN. If this alignment is valid, return it. Otherwise, give an error and return ALIGN. */ @@ -9273,7 +9273,7 @@ validate_alignment (Uint alignment, Entity_Id gnat_entity, unsigned int align) return align; } - + /* Promote the alignment of GNU_TYPE corresponding to GNAT_ENTITY. Return a positive value on success or zero on failure. */ @@ -9320,7 +9320,7 @@ promote_object_alignment (tree gnu_type, Entity_Id gnat_entity) return align; } - + /* Verify that TYPE is something we can implement atomically. If not, issue an error for GNAT_ENTITY. COMPONENT_P is true if we are being called to process a component type. */ @@ -9388,7 +9388,7 @@ check_ok_for_atomic_type (tree type, Entity_Id gnat_entity, bool component_p) post_error_ne ("atomic access to & cannot be guaranteed", gnat_error_point, gnat_entity); } - + /* Helper for the intrin compatibility checks family. Evaluate whether two types are definitely incompatible. */ @@ -9543,7 +9543,7 @@ intrin_profiles_compatible_p (intrin_binding_t * inb) return return_compatible_p && arglists_compatible_p; } - + /* Return a FIELD_DECL node modeled on OLD_FIELD. FIELD_TYPE is its type and RECORD_TYPE is the type of the parent. If SIZE is nonzero, it is the specified size for this field. POS_LIST is a position list describing @@ -10157,7 +10157,7 @@ associate_original_type_to_packed_array (tree gnu_type, Entity_Id gnat_entity) return NULL_TREE; } } - + /* Given a type T, a FIELD_DECL F, and a replacement value R, return an equivalent type with adjusted size expressions where all occurrences of references to F in a PLACEHOLDER_EXPR have been replaced by R. @@ -10318,7 +10318,7 @@ substitute_in_type (tree t, tree f, tree r) return t; } } - + /* Return the RM size of GNU_TYPE. This is the actual number of bits needed to represent the object. */ @@ -10347,7 +10347,7 @@ rm_size (tree gnu_type) /* For other types, this is just the size. */ return TYPE_SIZE (gnu_type); } - + /* Return the name to be used for GNAT_ENTITY. If a type, create a fully-qualified name, possibly with type information encoding. Otherwise, return the name. */ diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index 355178e..328e5f3 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -325,7 +325,7 @@ extern int double_scalar_alignment; /* True if floating-point arithmetics may use wider intermediate results. */ extern bool fp_arith_may_widen; - + /* Data structures used to represent attributes. */ enum attrib_type diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 7be8463..4bd9c8d 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -255,7 +255,7 @@ static bool maybe_make_gnu_thunk (Entity_Id gnat_thunk, tree gnu_thunk); of configurations. */ static const char *extract_encoding (const char *) ATTRIBUTE_UNUSED; static const char *decode_name (const char *) ATTRIBUTE_UNUSED; - + /* This makes gigi's file_info_ptr visible in this translation unit, so that Sloc_to_locus can look it up when deciding whether to map decls to instances. */ @@ -735,7 +735,7 @@ gigi (Node_Id gnat_root, /* We cannot track the location of errors past this point. */ Current_Error_Node = Empty; } - + /* Return a subprogram decl corresponding to __gnat_rcheck_xx for the given CHECK if KIND is EXCEPTION_SIMPLE, or else to __gnat_rcheck_xx_ext. */ @@ -779,7 +779,7 @@ build_raise_check (int check, enum exception_info_kind kind) return result; } - + /* Return a positive value if an lvalue is required for GNAT_NODE, which is an N_Attribute_Reference. */ @@ -1599,7 +1599,7 @@ Pragma_to_gnu (Node_Id gnat_node) return gnu_result; } - + /* Check the inline status of nested function FNDECL wrt its parent function. If a non-inline nested function is referenced from an inline external @@ -1645,7 +1645,7 @@ check_inlining_for_nested_subprog (tree fndecl) DECL_UNINLINABLE (parent_decl) = 1; } } - + /* Return an expression for the length of TYPE, an integral type, computed in RESULT_TYPE, another integral type. @@ -2590,7 +2590,7 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) *gnu_result_type_p = gnu_result_type; return gnu_result; } - + /* Subroutine of gnat_to_gnu to translate gnat_node, an N_Case_Statement, to a GCC tree, which is returned. */ @@ -2715,7 +2715,7 @@ Case_Statement_to_gnu (Node_Id gnat_node) return gnu_result; } - + /* Return true if we are in the body of a loop. */ static inline bool @@ -3328,7 +3328,7 @@ Loop_Statement_to_gnu (Node_Id gnat_node) return gnu_result; } - + /* This page implements a form of Named Return Value optimization modeled on the C++ optimization of the same name. The main difference is that we disregard any semantical considerations when applying it here, the @@ -3820,7 +3820,7 @@ build_return_expr (tree ret_obj, tree ret_val) return build1 (RETURN_EXPR, void_type_node, result_expr); } - + /* Subroutine of gnat_to_gnu to process gnat_node, an N_Subprogram_Body. We don't return anything. */ @@ -4144,7 +4144,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) else rest_of_subprog_body_compilation (gnu_subprog_decl); } - + /* The type of an atomic access. */ typedef enum { NOT_ATOMIC, SIMPLE_ATOMIC, OUTER_ATOMIC } atomic_acces_t; @@ -4334,8 +4334,8 @@ not_atomic: *type = NOT_ATOMIC; *sync = false; } - - /* Return true if GNAT_NODE requires simple atomic access and, if so, set SYNC + +/* Return true if GNAT_NODE requires simple atomic access and, if so, set SYNC according to the associated synchronization setting. */ static inline bool @@ -5205,7 +5205,7 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, return gnu_result; } - + /* Subroutine of gnat_to_gnu to translate gnat_node, an N_Handled_Sequence_Of_Statements, to a GCC tree, which is returned. */ @@ -5444,7 +5444,7 @@ Handled_Sequence_Of_Statements_to_gnu (Node_Id gnat_node) return gnu_result; } - + /* Subroutine of gnat_to_gnu to translate gnat_node, an N_Exception_Handler, to a GCC tree, which is returned. This is the variant for front-end sjlj exception handling. */ @@ -5513,7 +5513,7 @@ Exception_Handler_to_gnu_fe_sjlj (Node_Id gnat_node) return build3 (COND_EXPR, void_type_node, gnu_choice, gnu_body, NULL_TREE); } - + /* Return true if no statement in GNAT_LIST can alter the control flow. */ static bool @@ -5720,7 +5720,7 @@ Exception_Handler_to_gnu_gcc (Node_Id gnat_node) return build2 (CATCH_EXPR, void_type_node, gnu_etypes_list, end_stmt_group ()); } - + /* Subroutine of gnat_to_gnu to generate code for an N_Compilation unit. */ static void @@ -5850,7 +5850,7 @@ Compilation_Unit_to_gnu (Node_Id gnat_node) /* Force the processing for all nodes that remain in the queue. */ process_deferred_decl_context (true); } - + /* Mark COND, a boolean expression, as predicating a call to a noreturn function, i.e. predict that it is very likely false, and return it. @@ -6064,7 +6064,7 @@ Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) return gnu_result; } - + /* Return true if GNAT_NODE is on the LHS of an assignment or an actual parameter of a call. */ @@ -7159,9 +7159,7 @@ gnat_to_gnu (Node_Id gnat_node) const Entity_Id gnat_desig_type = Designated_Type (Underlying_Type (Etype (gnat_node))); - /* The flag is effectively only set on the base types. */ - ignore_init_type - = Has_Constrained_Partial_View (Base_Type (gnat_desig_type)); + ignore_init_type = Has_Constrained_Partial_View (gnat_desig_type); gnu_init = gnat_to_gnu (Expression (gnat_temp)); gnu_init = maybe_unconstrained_array (gnu_init); @@ -8331,7 +8329,7 @@ gnat_to_gnu_external (Node_Id gnat_node) return gnu_result; } - + /* Return true if the statement list STMT_LIST is empty. */ static bool @@ -8375,7 +8373,7 @@ insert_code_for (Node_Id gnat_node) save_gnu_tree (gnat_node, NULL_TREE, true); } - + /* Start a new statement group chained to the previous group. */ void @@ -8647,7 +8645,7 @@ build_stmt_group (List_Id gnat_list, bool binding_p) return end_stmt_group (); } - + /* Generate GIMPLE in place for the expression at *EXPR_P. */ int @@ -8896,7 +8894,7 @@ gnat_gimplify_stmt (tree *stmt_p) gcc_unreachable (); } } - + /* Force a reference to each of the entities in GNAT_PACKAGE recursively. This routine is exclusively called in type_annotate mode, to compute DDA @@ -9022,7 +9020,7 @@ elaborate_all_entities (Node_Id gnat_node) if (Nkind (Unit (gnat_node)) == N_Package_Body) elaborate_all_entities (Library_Unit (gnat_node)); } - + /* Do the processing of GNAT_NODE, an N_Freeze_Entity. */ static void @@ -9162,7 +9160,7 @@ process_freeze_entity (Node_Id gnat_node) used_types_insert (TREE_TYPE (gnu_new)); } } - + /* Elaborate decls in the lists GNAT_DECLS and GNAT_DECLS2, if present. We make two passes, one to elaborate anything other than bodies (but we declare a function if there was no spec). The second pass @@ -9297,7 +9295,7 @@ process_decls (List_Id gnat_decls, List_Id gnat_decls2, add_stmt (gnat_to_gnu (gnat_decl)); } } - + /* Make a unary operation of kind CODE using build_unary_op, but guard the operation by an overflow check. CODE can be one of NEGATE_EXPR or ABS_EXPR. GNU_TYPE is the type desired for the result. Usually @@ -9545,7 +9543,7 @@ emit_check (tree gnu_cond, tree gnu_expr, int reason, Node_Id gnat_node) : build_int_cst (TREE_TYPE (gnu_expr), 0)), gnu_expr); } - + /* Return an expression that converts GNU_EXPR to GNAT_TYPE, doing overflow checks if OVERFLOW_P is true. If TRUNCATE_P is true, do a fp-to-integer conversion with truncation, otherwise round. GNAT_NODE is the GNAT node @@ -9730,7 +9728,7 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflow_p, return convert (gnu_type, gnu_result); } - + /* Return true if GNU_EXPR can be directly addressed. This is the case unless it is an expression involving computation or if it involves a reference to a bitfield or to an object not sufficiently aligned for @@ -9908,7 +9906,7 @@ addressable_p (tree gnu_expr, tree gnu_type) return false; } } - + /* Do the processing for the declaration of a GNAT_ENTITY, a type or subtype. If a Freeze node exists for the entity, delay the bulk of the processing. Otherwise make a GCC type for GNAT_ENTITY and set up the correspondence. */ @@ -9992,7 +9990,7 @@ process_type (Entity_Id gnat_entity) TREE_TYPE (gnu_new)); } } - + /* Subroutine of assoc_to_constructor: VALUES is a list of field associations, some of which are from RECORD_TYPE. Return a CONSTRUCTOR consisting of the associations that are from RECORD_TYPE. If we see an internal record, make @@ -10146,7 +10144,7 @@ pos_to_constructor (Node_Id gnat_expr, tree gnu_array_type) return gnat_build_constructor (gnu_array_type, gnu_expr_vec); } - + /* Process a N_Validate_Unchecked_Conversion node. */ static void @@ -10205,7 +10203,7 @@ validate_unchecked_conversion (Node_Id gnat_node) } } } - + /* Convert SLOC into LOCUS. Return true if SLOC corresponds to a source code location and false if it doesn't. If CLEAR_COLUMN is true, set the column information to 0. If DECL is given and SLOC @@ -10387,7 +10385,7 @@ set_end_locus_from_node (tree gnu_node, Node_Id gnat_node) return false; } } - + /* Return a colon-separated list of encodings contained in encoded Ada name. */ @@ -10408,7 +10406,7 @@ decode_name (const char *name) __gnat_decode (name, decoded, 0); return decoded; } - + /* Post an error message. MSG is the error message, properly annotated. NODE is the node at which to post the error and the node to use for the '&' substitution. */ diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index dfde06e..013fccd 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -357,7 +357,7 @@ add_deferred_decl_context (tree decl, Entity_Id gnat_scope, int force_global); computed. */ static void add_deferred_type_context (struct deferred_decl_context_node *n, tree type); - + /* Initialize data structures of the utils.c module. */ void @@ -397,7 +397,7 @@ destroy_gnat_utils (void) pad_type_hash_table->empty (); pad_type_hash_table = NULL; } - + /* GNAT_ENTITY is a GNAT tree node for an entity. Associate GNU_DECL, a GCC tree node, with GNAT_ENTITY. If GNU_DECL is not a ..._DECL node, abort. If NO_CHECK is true, the latter check is suppressed. @@ -438,7 +438,7 @@ present_gnu_tree (Entity_Id gnat_entity) { return PRESENT_GNU_TREE (gnat_entity); } - + /* Make a dummy type corresponding to GNAT_TYPE. */ tree @@ -533,7 +533,7 @@ build_dummy_unc_pointer_types (Entity_Id gnat_desig_type, tree gnu_desig_type) TYPE_REFERENCE_TO (gnu_desig_type) = gnu_fat_type; TYPE_OBJECT_RECORD_TYPE (gnu_desig_type) = gnu_object_type; } - + /* Return true if we are in the global binding level. */ bool @@ -663,7 +663,7 @@ gnat_zaplevel (void) level->chain = free_binding_level; free_binding_level = level; } - + /* Set the context of TYPE and its parallel types (if any) to CONTEXT. */ static void @@ -935,7 +935,7 @@ gnat_pushdecl (tree decl, Node_Id gnat_node) } } } - + /* Create a record type that contains a SIZE bytes long field of TYPE with a starting bit position so that it is aligned to ALIGN bits, and leaving at least ROOM bytes free before the field. BASE_ALIGN is the alignment the @@ -1772,7 +1772,7 @@ set_reverse_storage_order_on_pad_type (tree type) TYPE_REVERSE_STORAGE_ORDER (type) = 1; return canonicalize_pad_type (type); } - + /* Relate the alias sets of GNU_NEW_TYPE and GNU_OLD_TYPE according to OP. If this is a multi-dimensional array type, do this recursively. @@ -1847,7 +1847,7 @@ relate_alias_sets (tree gnu_new_type, tree gnu_old_type, enum alias_set_op op) record_component_aliases (gnu_new_type); } - + /* Record TYPE as a builtin type for Ada. NAME is the name of the type. ARTIFICIAL_P is true if the type was generated by the compiler. */ @@ -1863,7 +1863,7 @@ record_builtin_type (const char *name, tree type, bool artificial_p) if (debug_hooks->type_decl) debug_hooks->type_decl (type_decl, false); } - + /* Finish constructing the character type CHAR_TYPE. In Ada character types are enumeration types and, as a consequence, are @@ -2558,7 +2558,7 @@ split_plus (tree in, tree *pvar) else return bitsize_zero_node; } - + /* Return a copy of TYPE but safe to modify in any way. */ tree @@ -2595,7 +2595,7 @@ copy_type (tree type) return new_type; } - + /* Return a subtype of sizetype with range MIN to MAX and whose TYPE_INDEX_TYPE is INDEX. GNAT_NODE is used for the position of the associated TYPE_DECL. */ @@ -2634,8 +2634,8 @@ create_range_type (tree type, tree min, tree max) return range_type; } - - /* Return an extra subtype of TYPE with range MIN to MAX. */ + +/* Return an extra subtype of TYPE with range MIN to MAX. */ tree create_extra_subtype (tree type, tree min, tree max) @@ -2652,7 +2652,7 @@ create_extra_subtype (tree type, tree min, tree max) return subtype; } - + /* Return a TYPE_DECL node suitable for the TYPE_STUB_DECL field of TYPE. NAME gives the name of the type to be used in the declaration. */ @@ -2718,7 +2718,7 @@ create_type_decl (tree name, tree type, bool artificial_p, bool debug_info_p, return type_decl; } - + /* Return a VAR_DECL or CONST_DECL node. NAME gives the name of the variable. ASM_NAME is its assembler name @@ -2886,7 +2886,7 @@ create_var_decl (tree name, tree asm_name, tree type, tree init, return var_decl; } - + /* Return true if TYPE, an aggregate type, contains (or is) an array. If SELF_REFERENTIAL is true, then an additional requirement on the array is that it be self-referential. */ @@ -3097,7 +3097,7 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, return field_decl; } - + /* Return a PARM_DECL node with NAME and TYPE. */ tree @@ -3131,7 +3131,7 @@ create_param_decl (tree name, tree type) DECL_ARG_TYPE (param_decl) = type; return param_decl; } - + /* Process the attributes in ATTR_LIST for NODE, which is either a DECL or a TYPE. If IN_PLACE is true, the tree pointed to by NODE should not be changed. GNAT_NODE is used for the position of error messages. */ @@ -3420,7 +3420,7 @@ create_label_decl (tree name, Node_Id gnat_node) return label_decl; } - + /* Return a FUNCTION_DECL node. NAME is the name of the subprogram, ASM_NAME its assembler name, TYPE its type (a FUNCTION_TYPE or METHOD_TYPE node), PARAM_DECL_LIST the list of its parameters (a list of PARM_DECL nodes @@ -3558,7 +3558,7 @@ finish_subprog_decl (tree decl, tree asm_name, tree type) DECL_NAME (decl) = main_identifier_node; } } - + /* Set up the framework for generating code for SUBPROG_DECL, a subprogram body. This routine needs to be invoked before processing the declarations appearing in the subprogram. */ @@ -3830,7 +3830,7 @@ fntype_same_flags_p (const_tree t, tree cico_list, bool return_unconstrained_p, && TYPE_RETURN_BY_DIRECT_REF_P (t) == return_by_direct_ref_p && TREE_ADDRESSABLE (t) == return_by_invisi_ref_p; } - + /* EXP is an expression for the size of an object. If this size contains discriminant references, replace them with the maximum (if MAX_P) or minimum (if !MAX_P) possible value of the discriminant. @@ -4042,7 +4042,7 @@ max_size (tree exp, bool max_p) gcc_unreachable (); } - + /* Build a template of type TEMPLATE_TYPE from the array bounds of ARRAY_TYPE. EXPR is an expression that we can use to locate any PLACEHOLDER_EXPRs. Return a constructor for the template. */ @@ -4108,7 +4108,7 @@ build_template (tree template_type, tree array_type, tree expr) return gnat_build_constructor (template_type, template_elts); } - + /* Return true if TYPE is suitable for the element type of a vector. */ static bool @@ -4198,7 +4198,7 @@ build_vector_type_for_array (tree array_type, tree attribute) TYPE_REPRESENTATIVE_ARRAY (vector_type) = array_type; return vector_type; } - + /* Build a type to be used to represent an aliased object whose nominal type is an unconstrained array. This consists of a RECORD_TYPE containing a field of TEMPLATE_TYPE and a field of OBJECT_TYPE, which is an ARRAY_TYPE. @@ -4248,7 +4248,7 @@ build_unc_object_type_from_ptr (tree thin_fat_ptr_type, tree object_type, return build_unc_object_type (template_type, object_type, name, debug_info_p); } - + /* Update anything previously pointing to OLD_TYPE to point to NEW_TYPE. In the normal case this is just two adjustments, but we have more to do if NEW_TYPE is an UNCONSTRAINED_ARRAY_TYPE. */ @@ -4379,7 +4379,7 @@ update_pointer_to (tree old_type, tree new_type) TYPE_REFERENCE_TO (old_type) = NULL_TREE; } } - + /* Convert EXPR, a pointer to a constrained array, into a pointer to an unconstrained one. This involves making or finding a template. */ @@ -4483,7 +4483,7 @@ convert_to_fat_pointer (tree type, tree expr) CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (type)), template_addr); return gnat_build_constructor (type, v); } - + /* Create an expression whose value is that of EXPR, converted to type TYPE. The TREE_TYPE of the value is always TYPE. This function implements all reasonable @@ -5170,7 +5170,7 @@ convert_to_index_type (tree expr) return convert (sizetype, expr); } - + /* Remove all conversions that are done in EXP. This includes converting from a padded type or to a justified modular type. If TRUE_ADDRESS is true, always return the address of the containing object even if @@ -5205,7 +5205,7 @@ remove_conversions (tree exp, bool true_address) return exp; } - + /* If EXP's type is an UNCONSTRAINED_ARRAY_TYPE, return an expression that refers to the underlying array. If it has TYPE_CONTAINS_TEMPLATE_P, likewise return an expression pointing to the underlying array. */ @@ -5293,7 +5293,7 @@ maybe_unconstrained_array (tree exp) return exp; } - + /* Return true if EXPR is an expression that can be folded as an operand of a VIEW_CONVERT_EXPR. See ada-tree.h for a complete rationale. */ @@ -5687,7 +5687,7 @@ unchecked_convert (tree type, tree expr, bool notrunc_p) return expr; } - + /* Return the appropriate GCC tree code for the specified GNAT_TYPE, the latter being a record type as predicated by Is_Record_Type. */ diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c index c8a2d7c..316033b 100644 --- a/gcc/ada/gcc-interface/utils2.c +++ b/gcc/ada/gcc-interface/utils2.c @@ -73,7 +73,7 @@ get_base_type (tree type) return type; } - + /* EXP is a GCC tree representing an address. See if we can find how strictly the object at this address is aligned and, if so, return the alignment of the object in bits. Otherwise return 0. */ @@ -203,7 +203,7 @@ known_alignment (tree exp) return this_alignment; } - + /* We have a comparison or assignment operation on two types, T1 and T2, which are either both array types or both record types. T1 is assumed to be for the left hand side operand, and T2 for the right hand side. Return the @@ -271,7 +271,7 @@ find_common_type (tree t1, tree t2) could cause a bad self-referential reference. */ return NULL_TREE; } - + /* Return an expression tree representing an equality comparison of A1 and A2, two objects of type ARRAY_TYPE. The result should be of type RESULT_TYPE. @@ -533,7 +533,7 @@ compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2) build_binary_op (TRUTH_ORIF_EXPR, result_type, p1_array_is_null, same_bounds)); } - + /* Compute the result of applying OP_CODE to LHS and RHS, where both are of type TYPE. We know that TYPE is a modular type with a nonbinary modulus. */ @@ -629,7 +629,7 @@ nonbinary_modular_operation (enum tree_code op_code, tree type, tree lhs, return convert (type, result); } - + /* This page contains routines that implement the Ada semantics with regard to atomic objects. They are fully piggybacked on the middle-end support for atomic loads and stores. @@ -828,7 +828,7 @@ build_load_modify_store (tree dest, tree src, Node_Id gnat_node) /* Something went wrong earlier if we have not found the atomic load. */ gcc_unreachable (); } - + /* Make a binary operation of kind OP_CODE. RESULT_TYPE is the type desired for the result. Usually the operation is to be performed in that type. For INIT_EXPR and MODIFY_EXPR, RESULT_TYPE must be @@ -1323,7 +1323,7 @@ build_binary_op (enum tree_code op_code, tree result_type, return result; } - + /* Similar, but for unary operations. */ tree @@ -1683,7 +1683,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) return result; } - + /* Similar, but for COND_EXPR. */ tree @@ -1758,7 +1758,7 @@ build_compound_expr (tree result_type, tree stmt_operand, tree expr_operand) return result; } - + /* Conveniently construct a function call expression. FNDECL names the function to be called, N is the number of arguments, and the "..." parameters are the argument expressions. Unlike build_call_expr @@ -1776,7 +1776,7 @@ build_call_n_expr (tree fndecl, int n, ...) va_end (ap); return fn; } - + /* Build a goto to LABEL for a raise, with an optional call to Local_Raise. MSG gives the exception's identity for the call to Local_Raise, if any. */ @@ -1924,7 +1924,7 @@ build_call_raise_range (int msg, Node_Id gnat_node, char kind, convert (integer_type_node, first), convert (integer_type_node, last)); } - + /* qsort comparer for the bit positions of two constructor elements for record components. */ @@ -1987,7 +1987,7 @@ gnat_build_constructor (tree type, vec *v) TREE_READONLY (result) = TYPE_READONLY (type) || read_only || allconstant; return result; } - + /* Return a COMPONENT_REF to access FIELD in RECORD, or NULL_TREE if the field is not found in the record. Don't fold the result if NO_FOLD is true. */ @@ -2113,7 +2113,7 @@ build_component_ref (tree record, tree field, bool no_fold) build_call_raise (CE_Discriminant_Check_Failed, Empty, N_Raise_Constraint_Error)); } - + /* Helper for build_call_alloc_dealloc, with arguments to be interpreted identically. Process the case where a GNAT_PROC to call is provided. */ @@ -2326,7 +2326,7 @@ build_call_alloc_dealloc (tree gnu_obj, tree gnu_size, tree gnu_type, return maybe_wrap_malloc (gnu_size, gnu_type, gnat_node); } } - + /* Build a GCC tree that corresponds to allocating an object of TYPE whose initial value is INIT, if INIT is nonzero. Convert the expression to RESULT_TYPE, which must be some pointer type, and return the result. @@ -2457,7 +2457,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, return storage; } - + /* Indicate that we need to take the address of T and that it therefore should not be allocated in a register. Return true if successful. */ @@ -2505,7 +2505,7 @@ gnat_mark_addressable (tree t) return true; } } - + /* Return true if EXP is a stable expression for the purpose of the functions below and, therefore, can be returned unmodified by them. We accept things that are actual constants or that have already been handled. */ -- cgit v1.1 From 364ad1d44b43a22025814f7eb664173ce35b5878 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 11 Nov 2020 16:11:17 +0100 Subject: testsuite: Fix up scan-tree-dump-times regexps for 64-bit targets The added (?:_ull) match on 32-bit targets, but are equivalent to just adding _ull into the strings, i.e. require the _ull substrings, while the intent is that they are optional, so we should use (?:_ull)? instead. 2020-11-11 Jakub Jelinek * gfortran.dg/gomp/workshare-reduction-3.f90: Use (?:_ull)? instead of (?:_ull) in the scan-tree-dump-times directives. * gfortran.dg/gomp/workshare-reduction-26.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-27.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-28.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-36.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-37.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-38.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-39.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-40.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-41.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-42.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-43.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-44.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-45.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-46.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-47.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-56.f90: Likewise. * gfortran.dg/gomp/workshare-reduction-57.f90: Likewise. --- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 | 4 ++-- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 | 8 ++++---- gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 | 8 ++++---- 18 files changed, 40 insertions(+), 40 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 index d8633b6..d98f589 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 0, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 0, 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_maybe_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_maybe_nonmonotonic_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 index aada4d7..99a94f8 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 index e67e24b..bf28cba 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 4, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 4, 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 index e67e24b..bf28cba 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 4, 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 4, 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_runtime_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_runtime_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 index 82dc063..bfddf84 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 2, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 index 4fb64cf..183d30b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 index 08eaef0..3343388 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 2, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 index 732753c..a86a1e8 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 2, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 index 44ecfa8..fedbd8f 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 index a8b9912..a208b49 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 2, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 2, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 index c6709e3..0542eca 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 3, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 index 3cb0a66..bfd35c9 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 index 3a4867f..0cdc314 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 3, 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 index 1252ffc..a7130e9 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 3, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 index bf19198..e769574 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 index d2b03f6..06170d7 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 @@ -1,8 +1,8 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_start \[^\n\r]*, 3, 3, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_start \[^\n\r]*, 3, 3, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_nonmonotonic_guided_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_nonmonotonic_guided_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 index fb6175c..a5fa4c0 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 @@ -1,10 +1,10 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_doacross_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_doacross_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_post " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_wait " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_static_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)?_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)?_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_static_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 index 41b55ea..6c52aba 100644 --- a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 @@ -1,10 +1,10 @@ ! { dg-do compile } ! { dg-options "-O2 -fopenmp -fdump-tree-optimized" } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_doacross_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_doacross_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_post " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)_wait " 1 "optimized" } } -! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)_dynamic_next " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)?_post " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross(?:_ull)?_wait " 1 "optimized" } } +! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop(?:_ull)?_dynamic_next " 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } } ! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } } -- cgit v1.1 From 86cca5cc14602814b98e55aae313fbe237af1b04 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Nov 2020 16:09:17 +0100 Subject: Fix PRE topological expression set sorting This fixes sorted_array_from_bitmap_set to do a topological sort as required by re-using what PHI-translation does, namely a DFS walk with the help of bitmap_find_leader. The proper result is verified by extra checking in clean () (which would have tripped before) and for the testcase I'm working at during the last patches (PR97623) it is neutral in compile-time cost. 2020-11-11 Richard Biener * tree-ssa-pre.c (pre_expr_DFS): New function. (sorted_array_from_bitmap_set): Use it to properly topologically sort the expression set. (clean): Verify we've cleaned everything we should. --- gcc/tree-ssa-pre.c | 104 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 20 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index d90249c..6dea8c2 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -806,36 +806,92 @@ bitmap_set_free (bitmap_set_t set) } +/* DFS walk EXPR to its operands with leaders in SET, collecting + expressions in SET in postorder into POST. */ + +static void +pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap visited, + hash_set > &leader_set, + vec &post) +{ + if (!bitmap_set_bit (visited, get_expression_id (expr))) + return; + + switch (expr->kind) + { + case NARY: + { + vn_nary_op_t nary = PRE_EXPR_NARY (expr); + for (unsigned i = 0; i < nary->length; i++) + { + if (TREE_CODE (nary->op[i]) != SSA_NAME) + continue; + unsigned int op_val_id = VN_INFO (nary->op[i])->value_id; + /* If we already found a leader for the value we've + recursed already. Avoid the costly bitmap_find_leader. */ + if (!leader_set.add (op_val_id)) + { + pre_expr leader = bitmap_find_leader (set, op_val_id); + if (leader) + pre_expr_DFS (leader, set, visited, leader_set, post); + } + } + break; + } + case REFERENCE: + { + vn_reference_t ref = PRE_EXPR_REFERENCE (expr); + vec operands = ref->operands; + vn_reference_op_t operand; + for (unsigned i = 0; operands.iterate (i, &operand); i++) + { + tree op[3]; + op[0] = operand->op0; + op[1] = operand->op1; + op[2] = operand->op2; + for (unsigned n = 0; n < 3; ++n) + { + if (!op[n] || TREE_CODE (op[n]) != SSA_NAME) + continue; + unsigned op_val_id = VN_INFO (op[n])->value_id; + if (!leader_set.add (op_val_id)) + { + pre_expr leader = bitmap_find_leader (set, op_val_id); + if (leader) + pre_expr_DFS (leader, set, visited, leader_set, post); + } + } + } + break; + } + default:; + } + post.quick_push (expr); +} + /* Generate an topological-ordered array of bitmap set SET. */ static vec sorted_array_from_bitmap_set (bitmap_set_t set) { - unsigned int i, j; - bitmap_iterator bi, bj; + unsigned int i; + bitmap_iterator bi; vec result; /* Pre-allocate enough space for the array. */ - result.create (bitmap_count_bits (&set->expressions)); + size_t len = bitmap_count_bits (&set->expressions); + result.create (len); + hash_set > leader_set (2*len); - FOR_EACH_VALUE_ID_IN_SET (set, i, bi) + auto_bitmap visited (&grand_bitmap_obstack); + bitmap_tree_view (visited); + FOR_EACH_EXPR_ID_IN_SET (set, i, bi) { - /* The number of expressions having a given value is usually - relatively small. Thus, rather than making a vector of all - the expressions and sorting it by value-id, we walk the values - and check in the reverse mapping that tells us what expressions - have a given value, to filter those in our set. As a result, - the expressions are inserted in value-id order, which means - topological order. - - If this is somehow a significant lose for some cases, we can - choose which set to walk based on the set size. */ - bitmap exprset = value_expressions[i]; - EXECUTE_IF_SET_IN_BITMAP (exprset, 0, j, bj) - { - if (bitmap_bit_p (&set->expressions, j)) - result.quick_push (expression_for_id (j)); - } + pre_expr expr = expression_for_id (i); + /* Hoist insertion calls us with a value-set we have to and with, + do so. */ + if (bitmap_set_contains_value (set, get_expr_value_id (expr))) + pre_expr_DFS (expr, set, visited, leader_set, result); } return result; @@ -1988,6 +2044,14 @@ clean (bitmap_set_t set1, bitmap_set_t set2 = NULL) } } exprs.release (); + + if (flag_checking) + { + unsigned j; + bitmap_iterator bi; + FOR_EACH_EXPR_ID_IN_SET (set1, j, bi) + gcc_assert (valid_in_sets (set1, set2, expression_for_id (j))); + } } /* Clean the set of expressions that are no longer valid in SET because -- cgit v1.1 From 2e8b368c3d33fd8ddafdd37f8e1b2ba45d1a122e Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Nov 2020 18:15:57 +0100 Subject: Fix PRE NEW_SETS guarding Accesses to NEW_SETS should be properly guarded. Committed as obvious. 2020-11-11 Richard Biener PR tree-optimization/97623 * tree-ssa-pre.c (create_expression_by_pieces): Guard NEW_SETS access. (insert_into_preds_of_block): Likewise. --- gcc/tree-ssa-pre.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 6dea8c2..10d223b 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -3064,7 +3064,8 @@ create_expression_by_pieces (basic_block block, pre_expr expr, vn_info->value_id = get_next_value_id (); nameexpr = get_or_alloc_expr_for_name (forcedname); add_to_value (vn_info->value_id, nameexpr); - bitmap_value_replace_in_set (NEW_SETS (block), nameexpr); + if (NEW_SETS (block)) + bitmap_value_replace_in_set (NEW_SETS (block), nameexpr); bitmap_value_replace_in_set (AVAIL_OUT (block), nameexpr); } @@ -3231,8 +3232,8 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, bitmap_insert_into_set (PHI_GEN (block), newphi); bitmap_value_replace_in_set (AVAIL_OUT (block), newphi); - bitmap_insert_into_set (NEW_SETS (block), - newphi); + if (NEW_SETS (block)) + bitmap_insert_into_set (NEW_SETS (block), newphi); /* If we insert a PHI node for a conversion of another PHI node in the same basic-block try to preserve range information. -- cgit v1.1 From d6e5745a9a88314e27f387b2277299076862af67 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 10 Nov 2020 16:39:19 -0500 Subject: c++: Tweak tsubst_qualified_id location. Retain the location when tsubstituting a qualified-id so that our static_assert diagnostic can benefit. Don't create useless location wrappers for temporary variables. gcc/ChangeLog: PR c++/97518 * tree.c (maybe_wrap_with_location): Don't add a location wrapper around an artificial and ignored decl. gcc/cp/ChangeLog: PR c++/97518 * pt.c (tsubst_qualified_id): Use EXPR_LOCATION of the qualified-id. Use it to maybe_wrap_with_location the final expression. gcc/testsuite/ChangeLog: PR c++/97518 * g++.dg/diagnostic/static_assert3.C: New test. --- gcc/cp/pt.c | 5 ++-- gcc/testsuite/g++.dg/diagnostic/static_assert3.C | 36 ++++++++++++++++++++++++ gcc/tree.c | 4 +++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/static_assert3.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6ba114c..c592461 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16214,7 +16214,7 @@ tsubst_qualified_id (tree qualified_id, tree args, tree name; bool is_template; tree template_args; - location_t loc = UNKNOWN_LOCATION; + location_t loc = EXPR_LOCATION (qualified_id); gcc_assert (TREE_CODE (qualified_id) == SCOPE_REF); @@ -16223,7 +16223,6 @@ tsubst_qualified_id (tree qualified_id, tree args, if (TREE_CODE (name) == TEMPLATE_ID_EXPR) { is_template = true; - loc = EXPR_LOCATION (name); template_args = TREE_OPERAND (name, 1); if (template_args) template_args = tsubst_template_args (template_args, args, @@ -16351,6 +16350,8 @@ tsubst_qualified_id (tree qualified_id, tree args, if (REF_PARENTHESIZED_P (qualified_id)) expr = force_paren_expr (expr); + expr = maybe_wrap_with_location (expr, loc); + return expr; } diff --git a/gcc/testsuite/g++.dg/diagnostic/static_assert3.C b/gcc/testsuite/g++.dg/diagnostic/static_assert3.C new file mode 100644 index 0000000..5d36388 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/static_assert3.C @@ -0,0 +1,36 @@ +// PR c++/97518 +// { dg-do compile { target c++17 } } +// { dg-options "-fdiagnostics-show-caret" } + +template struct is_same { static constexpr bool value = false; }; +template struct is_same { static constexpr bool value = true; }; + +template +void f(T, U) +{ + static_assert(is_same::value && is_same::value); // { dg-error "56:static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert(is_same::value && is_same::value); + ^~~~~ + { dg-end-multiline-output "" } */ +// { dg-message ".is_same::value. evaluates to false" "" { target *-*-* } .-5 } + static_assert(is_same::value && is_same::value); // { dg-error "32:static assertion failed" } +/* { dg-begin-multiline-output "" } + static_assert(is_same::value && is_same::value); + ^~~~~ + { dg-end-multiline-output "" } */ +// { dg-message ".is_same::value. evaluates to false" "" { target *-*-* } .-5 } + static_assert(is_same::value + && is_same::value // { dg-error "35:static assertion failed" } + && is_same::value); +/* { dg-begin-multiline-output "" } + && is_same::value + ^~~~~ + { dg-end-multiline-output "" } */ +// { dg-message ".is_same::value. evaluates to false" "" { target *-*-* } .-6 } +} + +void g() +{ + f(0, 1.3); +} diff --git a/gcc/tree.c b/gcc/tree.c index 1d4a1da..1ad4ad5 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -15041,6 +15041,10 @@ maybe_wrap_with_location (tree expr, location_t loc) if (EXCEPTIONAL_CLASS_P (expr)) return expr; + /* Compiler-generated temporary variables don't need a wrapper. */ + if (DECL_P (expr) && DECL_ARTIFICIAL (expr) && DECL_IGNORED_P (expr)) + return expr; + /* If any auto_suppress_location_wrappers are active, don't create wrappers. */ if (suppress_location_wrappers > 0) -- cgit v1.1 From 61827d5d9a5a09a8c05d5e41f95b03ebc6c43f61 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Nov 2020 14:43:39 -0500 Subject: c++: Correct the handling of alignof(expr) [PR88115] We're currently neglecting to set the ALIGNOF_EXPR_STD_P flag on an ALIGNOF_EXPR when its operand is an expression. This leads to us handling alignof(expr) as if it were written __alignof__(expr), and returning the preferred alignment instead of the ABI alignment. In the testcase below, this causes the first and third static_assert to fail on x86. gcc/cp/ChangeLog: PR c++/88115 * cp-tree.h (cxx_sizeof_or_alignof_expr): Add bool parameter. * decl.c (fold_sizeof_expr): Pass false to cxx_sizeof_or_alignof_expr. * parser.c (cp_parser_unary_expression): Pass std_alignof to cxx_sizeof_or_alignof_expr. * pt.c (tsubst_copy): Pass false to cxx_sizeof_or_alignof_expr. (tsubst_copy_and_build): Pass std_alignof to cxx_sizeof_or_alignof_expr. * typeck.c (cxx_alignof_expr): Add std_alignof bool parameter and pass it to cxx_sizeof_or_alignof_type. Set ALIGNOF_EXPR_STD_P appropriately. (cxx_sizeof_or_alignof_expr): Add std_alignof bool parameter and pass it to cxx_alignof_expr. Assert op is either SIZEOF_EXPR or ALIGNOF_EXPR. libcc1/ChangeLog: PR c++/88115 * libcp1plugin.cc (plugin_build_unary_expr): Pass true to cxx_sizeof_or_alignof_expr. gcc/testsuite/ChangeLog: PR c++/88115 * g++.dg/cpp0x/alignof6.C: New test. --- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 2 +- gcc/cp/parser.c | 4 ++-- gcc/cp/pt.c | 3 ++- gcc/cp/typeck.c | 17 +++++++++++------ gcc/testsuite/g++.dg/cpp0x/alignof6.C | 19 +++++++++++++++++++ 6 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alignof6.C (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 230a1525..63724c0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7461,7 +7461,7 @@ extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qualification (int, int); extern int comp_cv_qual_signature (tree, tree); extern tree cxx_sizeof_or_alignof_expr (location_t, tree, - enum tree_code, bool); + enum tree_code, bool, bool); extern tree cxx_sizeof_or_alignof_type (location_t, tree, enum tree_code, bool, bool); extern tree cxx_alignas_expr (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 42e704e..c52111e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10335,7 +10335,7 @@ fold_sizeof_expr (tree t) else r = cxx_sizeof_or_alignof_expr (EXPR_LOCATION (t), TREE_OPERAND (t, 0), SIZEOF_EXPR, - false); + false, false); if (r == error_mark_node) r = size_one_node; return r; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3632281..4f59fc4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8335,8 +8335,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, "ISO C++ does not allow % " "with a non-type"); - ret = cxx_sizeof_or_alignof_expr (compound_loc, - operand, op, true); + ret = cxx_sizeof_or_alignof_expr (compound_loc, operand, op, + std_alignof, true); } /* For SIZEOF_EXPR, just issue diagnostics, but keep SIZEOF_EXPR with the original operand. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c592461..a932c21 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16790,6 +16790,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) else return cxx_sizeof_or_alignof_expr (input_location, expanded, SIZEOF_EXPR, + false, complain & tf_error); } else @@ -19732,7 +19733,7 @@ tsubst_copy_and_build (tree t, complain & tf_error); else r = cxx_sizeof_or_alignof_expr (input_location, - op1, TREE_CODE (t), + op1, TREE_CODE (t), std_alignof, complain & tf_error); if (TREE_CODE (t) == SIZEOF_EXPR && r != error_mark_node) { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 08e0c80..700e166 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1832,10 +1832,12 @@ cxx_sizeof_expr (location_t loc, tree e, tsubst_flags_t complain) /* Implement the __alignof keyword: Return the minimum required alignment of E, measured in bytes. For VAR_DECL's and FIELD_DECL's return DECL_ALIGN (which can be set from an - "aligned" __attribute__ specification). */ + "aligned" __attribute__ specification). STD_ALIGNOF acts + like in cxx_sizeof_or_alignof_type. */ static tree -cxx_alignof_expr (location_t loc, tree e, tsubst_flags_t complain) +cxx_alignof_expr (location_t loc, tree e, bool std_alignof, + tsubst_flags_t complain) { tree t; @@ -1848,6 +1850,7 @@ cxx_alignof_expr (location_t loc, tree e, tsubst_flags_t complain) TREE_SIDE_EFFECTS (e) = 0; TREE_READONLY (e) = 1; SET_EXPR_LOCATION (e, loc); + ALIGNOF_EXPR_STD_P (e) = std_alignof; return e; } @@ -1900,23 +1903,25 @@ cxx_alignof_expr (location_t loc, tree e, tsubst_flags_t complain) } else return cxx_sizeof_or_alignof_type (loc, TREE_TYPE (e), - ALIGNOF_EXPR, false, + ALIGNOF_EXPR, std_alignof, complain & tf_error); return fold_convert_loc (loc, size_type_node, t); } /* Process a sizeof or alignof expression E with code OP where the operand - is an expression. */ + is an expression. STD_ALIGNOF acts like in cxx_sizeof_or_alignof_type. */ tree cxx_sizeof_or_alignof_expr (location_t loc, tree e, enum tree_code op, - bool complain) + bool std_alignof, bool complain) { + gcc_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR); if (op == SIZEOF_EXPR) return cxx_sizeof_expr (loc, e, complain? tf_warning_or_error : tf_none); else - return cxx_alignof_expr (loc, e, complain? tf_warning_or_error : tf_none); + return cxx_alignof_expr (loc, e, std_alignof, + complain? tf_warning_or_error : tf_none); } /* Build a representation of an expression 'alignas(E).' Return the diff --git a/gcc/testsuite/g++.dg/cpp0x/alignof6.C b/gcc/testsuite/g++.dg/cpp0x/alignof6.C new file mode 100644 index 0000000..b1a463d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alignof6.C @@ -0,0 +1,19 @@ +// PR c++/88115 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-pedantic" } + +// Verify the non-standard extension alignof(expr) behaves like +// alignof(type) to yield the ABI alignment of the type, and that +// __alignof__(expr) behaves like __alignof__(type) to yield the +// preferred alignment of the type. + +static_assert(alignof(double{}) == alignof(double), ""); +static_assert(__alignof__(double{}) == __alignof__(double), ""); + +template +void f() { + static_assert(alignof(T{}) == alignof(T), ""); + static_assert(__alignof__(T{}) == __alignof__(T), ""); +} + +template void f(); -- cgit v1.1 From b1c9b3c3408c1ec8043f9b9e1a148f84bb7f3b25 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Nov 2020 15:11:23 -0500 Subject: c++: Change the mangling of __alignof__ [PR88115] This patch changes the mangling of __alignof__ to v111__alignof__, making its mangling distinct from that of alignof(type) and alignof(expr). How we mangle ALIGNOF_EXPR now depends on its ALIGNOF_EXPR_STD_P flag, which after the previous patch gets consistently set for alignof(type) as well as alignof(expr). gcc/c-family/ChangeLog: PR c++/88115 * c-opts.c (c_common_post_options): Update latest_abi_version. gcc/ChangeLog: PR c++/88115 * common.opt (-fabi-version): Document =15. * doc/invoke.texi (C++ Dialect Options): Likewise. gcc/cp/ChangeLog: PR c++/88115 * mangle.c (write_expression): Mangle __alignof_ differently from alignof when the ABI version is at least 15. libiberty/ChangeLog: PR c++/88115 * cp-demangle.c (d_print_comp_inner) : Don't print the "operator " prefix for __alignof__. : Always print parens around the operand of __alignof__. * testsuite/demangle-expected: Test demangling for __alignof__. gcc/testsuite/ChangeLog: PR c++/88115 * g++.dg/abi/macro0.C: Adjust. * g++.dg/cpp0x/alignof7.C: New test. * g++.dg/cpp0x/alignof8.C: New test. --- gcc/c-family/c-opts.c | 2 +- gcc/common.opt | 4 ++++ gcc/cp/mangle.c | 27 +++++++++++++++++++++++---- gcc/doc/invoke.texi | 3 +++ gcc/testsuite/g++.dg/abi/macro0.C | 2 +- gcc/testsuite/g++.dg/cpp0x/alignof7.C | 22 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/alignof8.C | 13 +++++++++++++ 7 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alignof7.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alignof8.C (limited to 'gcc') diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 0698e58..40e9222 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -945,7 +945,7 @@ c_common_post_options (const char **pfilename) /* Change flag_abi_version to be the actual current ABI level, for the benefit of c_cpp_builtins, and to make comparison simpler. */ - const int latest_abi_version = 14; + const int latest_abi_version = 15; /* Generate compatibility aliases for ABI v11 (7.1) by default. */ const int abi_compat_default = 11; diff --git a/gcc/common.opt b/gcc/common.opt index 7d0e0d9..9552ceb 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -960,9 +960,13 @@ Driver Undocumented ; 13: Fixes the accidental change in 12 to the calling convention for classes ; with deleted copy constructor and trivial move constructor. ; Default in G++ 8.2. +; ; 14: Corrects the mangling of nullptr expression. ; Default in G++ 10. ; +; 15: Changes the mangling of __alignof__ to be distinct from that of alignof. +; Default in G++ 11. +; ; Additional positive integers will be assigned as new versions of ; the ABI become the default version of the ABI. fabi-version= diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 9fd3001..5548e51 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3049,11 +3049,30 @@ write_expression (tree expr) else goto normal_expr; } - else if (TREE_CODE (expr) == ALIGNOF_EXPR - && TYPE_P (TREE_OPERAND (expr, 0))) + else if (TREE_CODE (expr) == ALIGNOF_EXPR) { - write_string ("at"); - write_type (TREE_OPERAND (expr, 0)); + if (!ALIGNOF_EXPR_STD_P (expr)) + { + if (abi_warn_or_compat_version_crosses (15)) + G.need_abi_warning = true; + if (abi_version_at_least (15)) + { + /* We used to mangle __alignof__ like alignof. */ + write_string ("v111__alignof__"); + if (TYPE_P (TREE_OPERAND (expr, 0))) + write_type (TREE_OPERAND (expr, 0)); + else + write_expression (TREE_OPERAND (expr, 0)); + return; + } + } + if (TYPE_P (TREE_OPERAND (expr, 0))) + { + write_string ("at"); + write_type (TREE_OPERAND (expr, 0)); + } + else + goto normal_expr; } else if (code == SCOPE_REF || code == BASELINK) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8d0d213..553cc07 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2807,6 +2807,9 @@ change in version 12. Version 14, which first appeared in G++ 10, corrects the mangling of the nullptr expression. +Version 15, which first appeared in G++ 11, changes the mangling of +@code{__alignof__} to be distinct from that of @code{alignof}. + See also @option{-Wabi}. @item -fabi-compat-version=@var{n} diff --git a/gcc/testsuite/g++.dg/abi/macro0.C b/gcc/testsuite/g++.dg/abi/macro0.C index 0810600..7c3c170 100644 --- a/gcc/testsuite/g++.dg/abi/macro0.C +++ b/gcc/testsuite/g++.dg/abi/macro0.C @@ -1,6 +1,6 @@ // This testcase will need to be kept in sync with c_common_post_options. // { dg-options "-fabi-version=0" } -#if __GXX_ABI_VERSION != 1014 +#if __GXX_ABI_VERSION != 1015 #error "Incorrect value of __GXX_ABI_VERSION" #endif diff --git a/gcc/testsuite/g++.dg/cpp0x/alignof7.C b/gcc/testsuite/g++.dg/cpp0x/alignof7.C new file mode 100644 index 0000000..a4d7f24 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alignof7.C @@ -0,0 +1,22 @@ +// PR c++/88115 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-pedantic" } + +// Verify we mangle __alignof__ differently from alignof. + +#include + +template void f1(decltype(alignof(T))) { } +template void f2(decltype(alignof(T{}))) { } +template void f3(decltype(__alignof__(T))) { } +template void f4(decltype(__alignof__(T{}))) { } + +template void f1(std::size_t); +template void f2(std::size_t); +template void f3(std::size_t); +template void f4(std::size_t); + +// { dg-final { scan-assembler "_Z2f1IiEvDTatT_E" } } +// { dg-final { scan-assembler "_Z2f2IiEvDTaztlT_EE" } } +// { dg-final { scan-assembler "_Z2f3IiEvDTv111__alignof__T_E" } } +// { dg-final { scan-assembler "_Z2f4IiEvDTv111__alignof__tlT_EE" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/alignof8.C b/gcc/testsuite/g++.dg/cpp0x/alignof8.C new file mode 100644 index 0000000..a9368e2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alignof8.C @@ -0,0 +1,13 @@ +// PR c++/88115 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-pedantic -fabi-version=14 -Wabi" } + +#include "alignof7.C" + +// { dg-warning "changes between" "" { target *-*-* } 11 } +// { dg-warning "changes between" "" { target *-*-* } 12 } + +// { dg-final { scan-assembler "_Z2f1IiEvDTatT_E" } } +// { dg-final { scan-assembler "_Z2f2IiEvDTaztlT_EE" } } +// { dg-final { scan-assembler "_Z2f3IiEvDTatT_E" } } +// { dg-final { scan-assembler "_Z2f4IiEvDTaztlT_EE" } } -- cgit v1.1 From 9227f81db7a0b38dd14ce4b48ca50c33cf8d5e1c Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Mon, 26 Oct 2020 22:12:22 +0000 Subject: Objective-C++ : Allow prefix attrs on linkage specs. For Objective-C++, this combines prefix attributes from before and after top level linkage specs. The "reference implementation" for Objective-C++ allows this, and system headers depend on it. e.g. __attribute__((__deprecated__)) extern "C" __attribute__((__visibility__("default"))) @interface MyClass ... @end Would consider the list of prefix attributes to the interface for MyClass to include both the visibility and deprecated ones. When we are compiling regular C++, this emits a warning and discards any prefix attributes before a linkage spec. gcc/cp/ChangeLog: * parser.c (cp_parser_declaration): Unless we are compiling for Ojective-C++, warn about and discard any attributes that prefix a linkage specification. --- gcc/cp/parser.c | 71 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4f59fc4..efcdce0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2187,7 +2187,7 @@ static void cp_parser_already_scoped_statement static void cp_parser_declaration_seq_opt (cp_parser *); static void cp_parser_declaration - (cp_parser *); + (cp_parser *, tree); static void cp_parser_toplevel_declaration (cp_parser *); static void cp_parser_block_declaration @@ -2238,7 +2238,7 @@ static tree cp_parser_alias_declaration static void cp_parser_asm_definition (cp_parser *); static void cp_parser_linkage_specification - (cp_parser *); + (cp_parser *, tree); static void cp_parser_static_assert (cp_parser *, bool); static tree cp_parser_decltype @@ -13496,7 +13496,7 @@ cp_parser_declaration_seq_opt (cp_parser* parser) __extension__ declaration */ static void -cp_parser_declaration (cp_parser* parser) +cp_parser_declaration (cp_parser* parser, tree prefix_attrs) { int saved_pedantic; @@ -13504,7 +13504,7 @@ cp_parser_declaration (cp_parser* parser) if (cp_parser_extension_opt (parser, &saved_pedantic)) { /* Parse the qualified declaration. */ - cp_parser_declaration (parser); + cp_parser_declaration (parser, prefix_attrs); /* Restore the PEDANTIC flag. */ pedantic = saved_pedantic; @@ -13521,11 +13521,50 @@ cp_parser_declaration (cp_parser* parser) tree attributes = NULL_TREE; + /* Conditionally, allow attributes to precede a linkage specification. */ + if (token1->keyword == RID_ATTRIBUTE) + { + cp_lexer_save_tokens (parser->lexer); + attributes = cp_parser_attributes_opt (parser); + gcc_checking_assert (attributes); + cp_token *t1 = cp_lexer_peek_token (parser->lexer); + cp_token *t2 = (t1->type == CPP_EOF + ? t1 : cp_lexer_peek_nth_token (parser->lexer, 2)); + if (t1->keyword == RID_EXTERN + && cp_parser_is_pure_string_literal (t2)) + { + cp_lexer_commit_tokens (parser->lexer); + /* We might have already been here. */ + if (!c_dialect_objc ()) + { + warning_at (token1->location, OPT_Wattributes, "attributes are" + " only permitted in this position for Objective-C++," + " ignored"); + attributes = NULL_TREE; + } + token1 = t1; + token2 = t2; + } + else + { + cp_lexer_rollback_tokens (parser->lexer); + attributes = NULL_TREE; + } + } + /* If we already had some attributes, and we've added more, then prepend. + Otherwise attributes just contains any that we just read. */ + if (prefix_attrs) + { + if (attributes) + TREE_CHAIN (prefix_attrs) = attributes; + attributes = prefix_attrs; + } + /* If the next token is `extern' and the following token is a string literal, then we have a linkage specification. */ if (token1->keyword == RID_EXTERN && cp_parser_is_pure_string_literal (token2)) - cp_parser_linkage_specification (parser); + cp_parser_linkage_specification (parser, attributes); /* If the next token is `template', then we have either a template declaration, an explicit instantiation, or an explicit specialization. */ @@ -13575,7 +13614,7 @@ cp_parser_declaration (cp_parser* parser) cp_parser_namespace_definition (parser); /* Objective-C++ declaration/definition. */ else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1->keyword)) - cp_parser_objc_declaration (parser, NULL_TREE); + cp_parser_objc_declaration (parser, attributes); else if (c_dialect_objc () && token1->keyword == RID_ATTRIBUTE && cp_parser_objc_valid_prefix_attributes (parser, &attributes)) @@ -13617,7 +13656,7 @@ cp_parser_toplevel_declaration (cp_parser* parser) } else /* Parse the declaration itself. */ - cp_parser_declaration (parser); + cp_parser_declaration (parser, NULL_TREE); } /* Parse a block-declaration. @@ -14726,7 +14765,7 @@ cp_parser_function_specifier_opt (cp_parser* parser, extern string-literal declaration */ static void -cp_parser_linkage_specification (cp_parser* parser) +cp_parser_linkage_specification (cp_parser* parser, tree prefix_attr) { tree linkage; @@ -14791,7 +14830,7 @@ cp_parser_linkage_specification (cp_parser* parser) saved_in_unbraced_linkage_specification_p = parser->in_unbraced_linkage_specification_p; parser->in_unbraced_linkage_specification_p = true; - cp_parser_declaration (parser); + cp_parser_declaration (parser, prefix_attr); parser->in_unbraced_linkage_specification_p = saved_in_unbraced_linkage_specification_p; } @@ -33099,7 +33138,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser) if (token->keyword == RID_EXTERN && cp_parser_is_pure_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2))) - cp_parser_linkage_specification (parser); + cp_parser_linkage_specification (parser, NULL_TREE); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) cp_parser_pragma (parser, pragma_objc_icode, NULL); @@ -33864,11 +33903,15 @@ static bool cp_parser_objc_valid_prefix_attributes (cp_parser* parser, tree *attrib) { cp_lexer_save_tokens (parser->lexer); - *attrib = cp_parser_attributes_opt (parser); - gcc_assert (*attrib); + tree addon = cp_parser_attributes_opt (parser); + gcc_checking_assert (addon); if (OBJC_IS_AT_KEYWORD (cp_lexer_peek_token (parser->lexer)->keyword)) { cp_lexer_commit_tokens (parser->lexer); + if (*attrib) + TREE_CHAIN (*attrib) = addon; + else + *attrib = addon; return true; } cp_lexer_rollback_tokens (parser->lexer); @@ -41892,7 +41935,7 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, switch (context) { case pragma_external: - cp_parser_declaration (parser); + cp_parser_declaration (parser, NULL_TREE); break; case pragma_member: cp_parser_member_declaration (parser); @@ -43449,7 +43492,7 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, } /* We only have to consider the pragma_external case here. */ - cp_parser_declaration (parser); + cp_parser_declaration (parser, NULL_TREE); if (parser->oacc_routine && !parser->oacc_routine->fndecl_seen) cp_ensure_no_oacc_routine (parser); -- cgit v1.1 From 5d46ec3db21d8c8926f15a634b2d6570536db5f1 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Mon, 16 Sep 2019 15:11:00 +0100 Subject: CFI-handling : Add a hook to allow target-specific Personality and LSDA indirections. At present, the output of .cfi_personality and .cfi_lsda assumes ELF semantics for indirections. This isn't suitable for all targets and is one blocker to moving Darwin to use .cfi_xxxx. The patch adds a target hook that allows non-ELF targets to use indirections appropriate to their needs. gcc/ChangeLog: * config/darwin-protos.h (darwin_make_eh_symbol_indirect): New. * config/darwin.c (darwin_make_eh_symbol_indirect): New. Use Mach-O semantics for personality and ldsa indirections. * config/darwin.h (TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT): New. * doc/tm.texi: Regenerate. * doc/tm.texi.in: Add TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT hook. * dwarf2out.c (dwarf2out_do_cfi_startproc): If the target defines a hook for indirecting personality and ldsa references, use that otherwise default to ELF semantics. * target.def (make_eh_symbol_indirect): New target hook. --- gcc/config/darwin-protos.h | 1 + gcc/config/darwin.c | 11 +++++++++++ gcc/config/darwin.h | 3 +++ gcc/doc/tm.texi | 4 ++++ gcc/doc/tm.texi.in | 2 ++ gcc/dwarf2out.c | 14 ++++++++++++-- gcc/target.def | 10 ++++++++++ 7 files changed, 43 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/darwin-protos.h b/gcc/config/darwin-protos.h index 49c540f..3f222c3 100644 --- a/gcc/config/darwin-protos.h +++ b/gcc/config/darwin-protos.h @@ -69,6 +69,7 @@ extern void darwin_non_lazy_pcrel (FILE *, rtx); extern void darwin_emit_unwind_label (FILE *, tree, int, int); extern void darwin_emit_except_table_label (FILE *); +extern rtx darwin_make_eh_symbol_indirect (rtx, bool); extern void darwin_pragma_ignore (struct cpp_reader *); extern void darwin_pragma_options (struct cpp_reader *); diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index dd4857f..3265e3e 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -2225,6 +2225,17 @@ darwin_emit_except_table_label (FILE *file) ASM_OUTPUT_LABEL (file, section_start_label); } +rtx +darwin_make_eh_symbol_indirect (rtx orig, bool ARG_UNUSED (pubvis)) +{ + if (DARWIN_PPC == 0 && TARGET_64BIT) + return orig; + + return gen_rtx_SYMBOL_REF (Pmode, + machopic_indirection_name (orig, + /*stub_p=*/false)); +} + /* Return, and mark as used, the name of the stub for the mcount function. Currently, this is only called by X86 code in the expansion of the FUNCTION_PROFILER macro, when stubs are enabled. */ diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index f9d4fec..5a76631 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -591,6 +591,9 @@ extern GTY(()) int darwin_ms_struct; /* Emit a label to separate the exception table. */ #define TARGET_ASM_EMIT_EXCEPT_TABLE_LABEL darwin_emit_except_table_label +/* Make an EH (personality or LDSA) symbol indirect as needed. */ +#define TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT darwin_make_eh_symbol_indirect + /* Our profiling scheme doesn't LP labels and counter words. */ #define NO_PROFILE_COUNTERS 1 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 833320b..a783a21 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9560,6 +9560,10 @@ given instruction. This is only used when @code{TARGET_EXCEPT_UNWIND_INFO} returns @code{UI_TARGET}. @end deftypefn +@deftypefn {Target Hook} rtx TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT (rtx @var{origsymbol}, bool @var{pubvis}) +If necessary, modify personality and LSDA references to handle indirection. The original symbol is in @code{origsymbol} and if @code{pubvis} is true the symbol is visible outside the TU. +@end deftypefn + @deftypevr {Target Hook} bool TARGET_ASM_UNWIND_EMIT_BEFORE_INSN True if the @code{TARGET_ASM_UNWIND_EMIT} hook should be called before the assembly for @var{insn} has been emitted, false if the hook should be called afterward. @end deftypevr diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 58109be..897f289 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -6456,6 +6456,8 @@ the jump-table. @hook TARGET_ASM_UNWIND_EMIT +@hook TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT + @hook TARGET_ASM_UNWIND_EMIT_BEFORE_INSN @node Exception Region Output diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index bc32a17..bea02f9 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -991,7 +991,12 @@ dwarf2out_do_cfi_startproc (bool second) in the assembler. Further, the assembler can't handle any of the weirder relocation types. */ if (enc & DW_EH_PE_indirect) - ref = dw2_force_const_mem (ref, true); + { + if (targetm.asm_out.make_eh_symbol_indirect != NULL) + ref = targetm.asm_out.make_eh_symbol_indirect (ref, true); + else + ref = dw2_force_const_mem (ref, true); + } fprintf (asm_out_file, "\t.cfi_personality %#x,", enc); output_addr_const (asm_out_file, ref); @@ -1009,7 +1014,12 @@ dwarf2out_do_cfi_startproc (bool second) SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL; if (enc & DW_EH_PE_indirect) - ref = dw2_force_const_mem (ref, true); + { + if (targetm.asm_out.make_eh_symbol_indirect != NULL) + ref = targetm.asm_out.make_eh_symbol_indirect (ref, true); + else + ref = dw2_force_const_mem (ref, true); + } fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc); output_addr_const (asm_out_file, ref); diff --git a/gcc/target.def b/gcc/target.def index b916635..71411d8 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -185,6 +185,16 @@ DEFHOOK void, (rtx personality), NULL) +/* If necessary, modify personality and LSDA references to handle + indirection. This is used when the assembler supports CFI directives. */ +DEFHOOK +(make_eh_symbol_indirect, + "If necessary, modify personality and LSDA references to handle indirection.\ + The original symbol is in @code{origsymbol} and if @code{pubvis} is true\ + the symbol is visible outside the TU.", + rtx, (rtx origsymbol, bool pubvis), + NULL) + /* Emit any directives required to unwind this instruction. */ DEFHOOK (unwind_emit, -- cgit v1.1 From 0f5f9ed5e5a041b636cc002451b1e8b2295f8e4f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 12 Nov 2020 00:16:39 +0000 Subject: Daily bump. --- gcc/ChangeLog | 175 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/ada/ChangeLog | 33 +++++++++ gcc/c-family/ChangeLog | 5 ++ gcc/cp/ChangeLog | 36 ++++++++++ gcc/fortran/ChangeLog | 9 +++ gcc/go/ChangeLog | 5 ++ gcc/testsuite/ChangeLog | 152 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 416 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 766ce5f..e515b38 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,178 @@ +2020-11-11 Iain Sandoe + + * config/darwin-protos.h (darwin_make_eh_symbol_indirect): New. + * config/darwin.c (darwin_make_eh_symbol_indirect): New. Use + Mach-O semantics for personality and ldsa indirections. + * config/darwin.h (TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT): New. + * doc/tm.texi: Regenerate. + * doc/tm.texi.in: Add TARGET_ASM_MAKE_EH_SYMBOL_INDIRECT hook. + * dwarf2out.c (dwarf2out_do_cfi_startproc): If the target defines + a hook for indirecting personality and ldsa references, use that + otherwise default to ELF semantics. + * target.def (make_eh_symbol_indirect): New target hook. + +2020-11-11 Patrick Palka + + PR c++/88115 + * common.opt (-fabi-version): Document =15. + * doc/invoke.texi (C++ Dialect Options): Likewise. + +2020-11-11 Marek Polacek + + PR c++/97518 + * tree.c (maybe_wrap_with_location): Don't add a location + wrapper around an artificial and ignored decl. + +2020-11-11 Richard Biener + + PR tree-optimization/97623 + * tree-ssa-pre.c (create_expression_by_pieces): Guard + NEW_SETS access. + (insert_into_preds_of_block): Likewise. + +2020-11-11 Richard Biener + + * tree-ssa-pre.c (pre_expr_DFS): New function. + (sorted_array_from_bitmap_set): Use it to properly + topologically sort the expression set. + (clean): Verify we've cleaned everything we should. + +2020-11-11 Richard Biener + + PR tree-optimization/97623 + * params.opt (-param=max-pre-hoist-insert-iterations): Remove + again. + * doc/invoke.texi (max-pre-hoist-insert-iterations): Likewise. + * tree-ssa-pre.c (insert): Move hoist insertion after PRE + insertion iteration and do not iterate it. + +2020-11-11 Richard Sandiford + + * config/aarch64/aarch64-sve.md (@vcond_mask_): Extend + from SVE_FULL to SVE_ALL. + (*vcond_mask_): Likewise. + (@aarch64_sel_dup): Likewise. + (vcond): Extend to... + (vcond): ...this, but requiring the + sizes of the container modes to match. + (vcondu): Extend to... + (vcondu): ...this. + (vec_cmp): Extend to... + (vec_cmp): ...this. + (vec_cmpu): Extend to... + (vec_cmpu): ...this. + (@aarch64_pred_cmp): Extend to... + (@aarch64_pred_cmp): ...this. + (*cmp_cc): Extend to... + (*cmp_cc): ...this. + (*cmp_ptest): Extend to... + (*cmp_ptest): ...this. + (*cmp_and): Extend to... + (*cmp_and): ...this. + +2020-11-11 Richard Sandiford + + * optabs-tree.c (expand_vec_cond_expr_p): Allow the compared values + and the selected values to have different mode sizes. + * gimple-isel.cc (gimple_expand_vec_cond_expr): Likewise. + +2020-11-11 Hongtao Liu + Hongyu Wang + + * common/config/i386/cpuinfo.h (get_available_features): + Detect AVXVNNI. + * common/config/i386/i386-common.c + (OPTION_MASK_ISA2_AVXVNNI_SET, + OPTION_MASK_ISA2_AVXVNNI_UNSET): New. + (OPTION_MASK_ISA2_AVX2_UNSET): Add AVXVNNI. + (ix86_hanlde_option): Handle -mavxvnni, unset avxvnni when + avx2 is disabled. + * common/config/i386/i386-cpuinfo.h (enum processor_features): + Add FEATURE_AVXVNNI. + * common/config/i386/i386-isas.h: Add ISA_NAMES_TABLE_ENTRY + for avxvnni. + * config.gcc: Add avxvnniintrin.h. + * config/i386/avx512vnnivlintrin.h: Reimplement 128/256 bit non-mask + intrinsics with macros to support unified interface. + * config/i386/avxvnniintrin.h: New header file. + * config/i386/cpuid.h (bit_AVXVNNI): New. + * config/i386/i386-builtins.c (def_builtin): Handle AVXVNNI mask + for unified builtin. + * config/i386/i386-builtin.def (BDESC): Adjust AVX512VNNI + builtins for AVXVNNI. + * config/i386/i386-c.c (ix86_target_macros_internal): Define + __AVXVNNI__. + * config/i386/i386-expand.c (ix86_expand_builtin): Handle bisa + for AVXVNNI to support unified intrinsic name, since there is no + dependency between AVX512VNNI and AVXVNNI. + * config/i386/i386-options.c (isa2_opts): Add -mavxvnni. + (ix86_valid_target_attribute_inner_p): Handle avxnnni. + (ix86_option_override_internal): Ditto. + * config/i386/i386.h (TARGET_AVXVNNI, TARGET_AVXVNNI_P, + TARGET_AVXVNNI_P, PTA_AVXVNNI): New. + (PTA_SAPPHIRERAPIDS): Add AVX_VNNI. + (PTA_ALDERLAKE): Likewise. + * config/i386/i386.md ("isa"): Add avxvnni, avx512vnnivl. + ("enabled"): Adjust for avxvnni and avx512vnnivl. + * config/i386/i386.opt: Add option -mavxvnni. + * config/i386/immintrin.h: Include avxvnniintrin.h. + * config/i386/sse.md (vpdpbusd_): Adjust for AVXVNNI. + (vpdpbusds_): Likewise. + (vpdpwssd_): Likewise. + (vpdpwssds_): Likewise. + (vpdpbusd_v16si): New. + (vpdpbusds_v16si): Likewise. + (vpdpwssd_v16si): Likewise. + (vpdpwssds_v16si): Likewise. + * doc/invoke.texi: Document -mavxvnni. + * doc/extend.texi: Document avxvnni. + * doc/sourcebuild.texi: Document target avxvnni. + +2020-11-11 Martin Liska + + * tree.c (copy_node): Fix spelling. + +2020-11-11 Richard Biener + + * tree-ssa-pre.c (phi_translate_set): Do not sort the + expression set topologically. + +2020-11-11 Aldy Hernandez + + * value-range.cc (irange::set): Early exit on VR_VARYING. + +2020-11-11 Zhiheng Xie + Nannan Zheng + + * config/aarch64/aarch64-simd-builtins.def: Add proper FLAG + for arithmetic operation intrinsics. + +2020-11-11 Strager Neds + + * cgraph.h (symtab_node::set_section_for_node): Declare new + overload. + (symtab_node::set_section_from_string): Rename from set_section. + (symtab_node::set_section_from_node): Declare. + * symtab.c (symtab_node::set_section_for_node): Define new + overload. + (symtab_node::set_section_from_string): Rename from set_section. + (symtab_node::set_section_from_node): Define. + (symtab_node::set_section): Call renamed set_section_from_string. + (symtab_node::set_section): Call new set_section_from_node. + +2020-11-11 Strager Neds + + * symtab.c (symtab_node::set_section_for_node): Extract reference + counting logic into ... + (retain_section_hash_entry): ... here (new function) and ... + (release_section_hash_entry): ... here (new function). + +2020-11-11 liuhongt + + * config/i386/i386.h (PTA_MOVDIRI, PTA_MOVDIR64B, + PTA_AMX_TILE, PTA_AMX_INT8, PTA_AMX_BF16, PTA_HRESET): + Formatting. + 2020-11-11 Ilya Leoshkevich * config/s390/s390.h (HAVE_TF): Use opaque value when diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index bb826fc..95634e0 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20201111 +20201112 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index e00b1a1..d131abf 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,36 @@ +2020-11-11 Eric Botcazou + + * gcc-interface/gigi.h: Remove ^L characters throughout. + * gcc-interface/decl.c: Likewise. + * gcc-interface/utils.c: Likewise. + * gcc-interface/utils2.c: Likewise. + * gcc-interface/trans.c (gnat_to_gnu) : Do not explicitly + go to the base type for the Has_Constrained_Partial_View flag. + +2020-11-11 Eric Botcazou + + * gcc-interface/trans.c (build_binary_op_trapv): Convert operands + to the result type before doing generic overflow checking. + +2020-11-11 Eric Botcazou + + * gcc-interface/trans.c (can_be_lower_p): Remove. + (Regular_Loop_to_gnu): Add ENTRY_COND unconditionally if + BOTTOM_COND is non-zero. + +2020-11-11 Eric Botcazou + + * gcc-interface/decl.c (gnat_to_gnu_entity) : In case + the constant is not being defined, get the expression in type + annotation mode only if its type is elementary. + +2020-11-11 Eric Botcazou + + * gcc-interface/trans.c (gnat_to_gnu) : Also convert + GNU_MAX_SHIFT if the type of the operation has been changed. + * gcc-interface/utils.c (can_materialize_object_renaming_p): Add + pair of missing parentheses. + 2020-11-07 Eric Botcazou * gcc-interface/Makefile.in: Force target_cpu to powerpc if the diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index bef7df3..772b0f5 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2020-11-11 Patrick Palka + + PR c++/88115 + * c-opts.c (c_common_post_options): Update latest_abi_version. + 2020-11-10 Jakub Jelinek PR c/97748 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dd0e82e..babb459 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,39 @@ +2020-11-11 Iain Sandoe + + * parser.c (cp_parser_declaration): Unless we are compiling for + Ojective-C++, warn about and discard any attributes that prefix + a linkage specification. + +2020-11-11 Patrick Palka + + PR c++/88115 + * mangle.c (write_expression): Mangle __alignof_ differently + from alignof when the ABI version is at least 15. + +2020-11-11 Patrick Palka + + PR c++/88115 + * cp-tree.h (cxx_sizeof_or_alignof_expr): Add bool parameter. + * decl.c (fold_sizeof_expr): Pass false to + cxx_sizeof_or_alignof_expr. + * parser.c (cp_parser_unary_expression): Pass std_alignof to + cxx_sizeof_or_alignof_expr. + * pt.c (tsubst_copy): Pass false to cxx_sizeof_or_alignof_expr. + (tsubst_copy_and_build): Pass std_alignof to + cxx_sizeof_or_alignof_expr. + * typeck.c (cxx_alignof_expr): Add std_alignof bool parameter + and pass it to cxx_sizeof_or_alignof_type. Set ALIGNOF_EXPR_STD_P + appropriately. + (cxx_sizeof_or_alignof_expr): Add std_alignof bool parameter + and pass it to cxx_alignof_expr. Assert op is either + SIZEOF_EXPR or ALIGNOF_EXPR. + +2020-11-11 Marek Polacek + + PR c++/97518 + * pt.c (tsubst_qualified_id): Use EXPR_LOCATION of the qualified-id. + Use it to maybe_wrap_with_location the final expression. + 2020-11-10 Marek Polacek PR c++/97518 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6a023af..6eb6500 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,12 @@ +2020-11-11 Jakub Jelinek + + PR fortran/97768 + * misc.c (gfc_typename): Use ex->value.character.length only if + ex->expr_type == EXPR_CONSTANT. If ex->ts.deferred, print : instead + of length. If ex->ts.u.cl && ex->ts.u.cl->length == NULL, print * + instead of length. Otherwise if character length is non-constant, + print just CHARACTER or CHARACTER(KIND=N). + 2020-11-10 Tobias Burnus * dump-parse-tree.c (show_omp_clauses): Handle new reduction enums. diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 4229488..06d8ecd 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2020-11-11 Alan Modra + + * go-gcc.cc (Gcc_backend::global_variable_set_init): Cast NULL to + avoid ambiguous overloaded call. + 2020-11-06 Nathan Sidwell * go-gcc.cc (Gcc_backend::call_expression): Rename diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 58726a8..cc2d10d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,155 @@ +2020-11-11 Patrick Palka + + PR c++/88115 + * g++.dg/abi/macro0.C: Adjust. + * g++.dg/cpp0x/alignof7.C: New test. + * g++.dg/cpp0x/alignof8.C: New test. + +2020-11-11 Patrick Palka + + PR c++/88115 + * g++.dg/cpp0x/alignof6.C: New test. + +2020-11-11 Marek Polacek + + PR c++/97518 + * g++.dg/diagnostic/static_assert3.C: New test. + +2020-11-11 Jakub Jelinek + + * gfortran.dg/gomp/workshare-reduction-3.f90: Use (?:_ull)? instead + of (?:_ull) in the scan-tree-dump-times directives. + * gfortran.dg/gomp/workshare-reduction-26.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-27.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-28.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-36.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-37.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-38.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-39.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-40.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-41.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-42.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-43.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-44.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-45.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-46.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-47.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-56.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-57.f90: Likewise. + +2020-11-11 Eric Botcazou + + * gnat.dg/bias2.adb: New test. + +2020-11-11 Eric Botcazou + + * gnat.dg/opt89.adb: New test. + +2020-11-11 Eric Botcazou + + * gnat.dg/shift1.adb: New test. + +2020-11-11 Richard Biener + + PR testsuite/97797 + * gcc.dg/torture/ssa-fre-5.c: Use __SIZETYPE__ where + appropriate. + * gcc.dg/torture/ssa-fre-6.c: Likewise. + +2020-11-11 Richard Biener + + PR tree-optimization/97623 + * gcc.dg/tree-ssa/ssa-hoist-3.c: Adjust. + * gcc.dg/tree-ssa/ssa-hoist-7.c: Likewise. + * gcc.dg/tree-ssa/ssa-pre-30.c: Likewise. + +2020-11-11 Richard Sandiford + + * gcc.target/aarch64/sve/cmp_1.c: New test. + * gcc.target/aarch64/sve/cmp_2.c: Likewise. + * gcc.target/aarch64/sve/cond_arith_1.c: Add --param + aarch64-sve-compare-costs=0 + * gcc.target/aarch64/sve/cond_arith_1_run.c: Likewise. + * gcc.target/aarch64/sve/cond_arith_3.c: Likewise. + * gcc.target/aarch64/sve/cond_arith_3_run.c: Likewise. + * gcc.target/aarch64/sve/mask_gather_load_7.c: Likewise. + * gcc.target/aarch64/sve/mask_load_slp_1.c: Likewise. + * gcc.target/aarch64/sve/vcond_11.c: Likewise. + * gcc.target/aarch64/sve/vcond_11_run.c: Likewise. + +2020-11-11 Hongtao Liu + Hongyu Wang + + * gcc.target/i386/avx512vl-vnni-1.c: Rename.. + * gcc.target/i386/avx512vl-vnni-1a.c: To This. + * gcc.target/i386/avx512vl-vnni-1b.c: New test. + * gcc.target/i386/avx512vl-vnni-2.c: Ditto. + * gcc.target/i386/avx512vl-vnni-3.c: Ditto. + * gcc.target/i386/avx-vnni-1.c: Ditto. + * gcc.target/i386/avx-vnni-2.c: Ditto. + * gcc.target/i386/avx-vnni-3.c: Ditto. + * gcc.target/i386/avx-vnni-4.c: Ditto. + * gcc.target/i386/avx-vnni-5.c: Ditto. + * gcc.target/i386/avx-vnni-6.c: Ditto. + * gcc.target/i386/avx-vpdpbusd-2.c: Ditto. + * gcc.target/i386/avx-vpdpbusds-2.c: Ditto. + * gcc.target/i386/avx-vpdpwssd-2.c: Ditto. + * gcc.target/i386/avx-vpdpwssds-2.c: Ditto. + * gcc.target/i386/vnni_inline_error.c: Ditto. + * gcc.target/i386/avx512vnnivl-builtin.c: Ditto. + * gcc.target/i386/avxvnni-builtin.c: Ditto. + * gcc.target/i386/funcspec-56.inc: Add new target attribute. + * gcc.target/i386/sse-12.c: Add -mavxvnni. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-14.c: Ditto. + * gcc.target/i386/sse-22.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * g++.dg/other/i386-2.C: Ditto. + * g++.dg/other/i386-3.C: Ditto. + * lib/target-supports.exp (check_effective_target_avxvnni): + New proc. + +2020-11-11 Tobias Burnus + + * gfortran.dg/gomp/workshare-reduction-26.f90: Add (?:_ull) to + scan-tree-dump-times regex for -m32. + * gfortran.dg/gomp/workshare-reduction-27.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-28.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-3.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-36.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-37.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-38.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-39.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-40.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-41.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-42.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-43.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-44.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-45.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-46.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-47.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-56.f90: Likewise. + * gfortran.dg/gomp/workshare-reduction-57.f90: Likewise. + +2020-11-11 Jakub Jelinek + + PR fortran/97768 + * gfortran.dg/pr97768_1.f90: New test. + * gfortran.dg/pr97768_2.f90: New test. + +2020-11-11 Nagaraju Mekala + + * gcc.target/microblaze/others/strings1.c: Update + to include $LC label. + +2020-11-11 David Edelsohn + + * c-c++-common/zero-scratch-regs-10.c: Skip on powerpc*-*-*. + * c-c++-common/zero-scratch-regs-11.c: Skip on powerpc*-*-*. + * c-c++-common/zero-scratch-regs-5.c: Skip on powerpc*-*-aix*. + * c-c++-common/zero-scratch-regs-8.c: Skip on powerpc*-*-*. + * c-c++-common/zero-scratch-regs-9.c: Skip on powerpc*-*-*. + 2020-11-10 Marek Polacek PR c++/97518 -- cgit v1.1 From 5e00ad3ffbfb4df7242c313a0d836f5b538eb2fb Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 11 Nov 2020 21:16:45 -0500 Subject: analyzer: warn on invalid shift counts [PR97424] This patch implements -Wanalyzer-shift-count-negative and -Wanalyzer-shift-count-overflow, analogous to the C/C++ warnings -Wshift-count-negative and -Wshift-count-overflow, but implemented via interprocedural path analysis rather than via parsing in a front end, and thus capable of detecting interprocedural cases that the warnings implemented in the front ends can miss. gcc/analyzer/ChangeLog: PR tree-optimization/97424 * analyzer.opt (Wanalyzer-shift-count-negative): New. (Wanalyzer-shift-count-overflow): New. * region-model.cc (class shift_count_negative_diagnostic): New. (class shift_count_overflow_diagnostic): New. (region_model::get_gassign_result): Complain about shift counts that are negative or are >= the operand's type's width. gcc/ChangeLog: PR tree-optimization/97424 * doc/invoke.texi (Static Analyzer Options): Add -Wno-analyzer-shift-count-negative and -Wno-analyzer-shift-count-overflow. (-Wno-analyzer-shift-count-negative): New. (-Wno-analyzer-shift-count-overflow): New. gcc/testsuite/ChangeLog: PR tree-optimization/97424 * gcc.dg/analyzer/invalid-shift-1.c: New test. --- gcc/analyzer/analyzer.opt | 8 ++ gcc/analyzer/region-model.cc | 102 ++++++++++++++++++++++++ gcc/doc/invoke.texi | 33 ++++++++ gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c | 34 ++++++++ 4 files changed, 177 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c (limited to 'gcc') diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index c9df6dc..bbf9e42 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -98,6 +98,14 @@ Wanalyzer-null-dereference Common Var(warn_analyzer_null_dereference) Init(1) Warning Warn about code paths in which a NULL pointer is dereferenced. +Wanalyzer-shift-count-negative +Common Var(warn_analyzer_shift_count_negative) Init(1) Warning +Warn about code paths in which a shift with negative count is attempted. + +Wanalyzer-shift-count-overflow +Common Var(warn_analyzer_shift_count_overflow) Init(1) Warning +Warn about code paths in which a shift with count >= width of type is attempted. + Wanalyzer-stale-setjmp-buffer Common Var(warn_analyzer_stale_setjmp_buffer) Init(1) Warning Warn about code paths in which a longjmp rewinds to a jmp_buf saved in a stack frame that has returned. diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index d30047b..57c657b 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -363,6 +363,88 @@ private: enum poison_kind m_pkind; }; +/* A subclass of pending_diagnostic for complaining about shifts + by negative counts. */ + +class shift_count_negative_diagnostic +: public pending_diagnostic_subclass +{ +public: + shift_count_negative_diagnostic (const gassign *assign, tree count_cst) + : m_assign (assign), m_count_cst (count_cst) + {} + + const char *get_kind () const FINAL OVERRIDE + { + return "shift_count_negative_diagnostic"; + } + + bool operator== (const shift_count_negative_diagnostic &other) const + { + return (m_assign == other.m_assign + && same_tree_p (m_count_cst, other.m_count_cst)); + } + + bool emit (rich_location *rich_loc) FINAL OVERRIDE + { + return warning_at (rich_loc, OPT_Wanalyzer_shift_count_negative, + "shift by negative count (%qE)", m_count_cst); + } + + label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE + { + return ev.formatted_print ("shift by negative amount here (%qE)", m_count_cst); + } + +private: + const gassign *m_assign; + tree m_count_cst; +}; + +/* A subclass of pending_diagnostic for complaining about shifts + by counts >= the width of the operand type. */ + +class shift_count_overflow_diagnostic +: public pending_diagnostic_subclass +{ +public: + shift_count_overflow_diagnostic (const gassign *assign, + int operand_precision, + tree count_cst) + : m_assign (assign), m_operand_precision (operand_precision), + m_count_cst (count_cst) + {} + + const char *get_kind () const FINAL OVERRIDE + { + return "shift_count_overflow_diagnostic"; + } + + bool operator== (const shift_count_overflow_diagnostic &other) const + { + return (m_assign == other.m_assign + && m_operand_precision == other.m_operand_precision + && same_tree_p (m_count_cst, other.m_count_cst)); + } + + bool emit (rich_location *rich_loc) FINAL OVERRIDE + { + return warning_at (rich_loc, OPT_Wanalyzer_shift_count_overflow, + "shift by count (%qE) >= precision of type (%qi)", + m_count_cst, m_operand_precision); + } + + label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE + { + return ev.formatted_print ("shift by count %qE here", m_count_cst); + } + +private: + const gassign *m_assign; + int m_operand_precision; + tree m_count_cst; +}; + /* If ASSIGN is a stmt that can be modelled via set_value (lhs_reg, SVALUE, CTXT) for some SVALUE, get the SVALUE. @@ -514,6 +596,26 @@ region_model::get_gassign_result (const gassign *assign, const svalue *rhs1_sval = get_rvalue (rhs1, ctxt); const svalue *rhs2_sval = get_rvalue (rhs2, ctxt); + if (ctxt && (op == LSHIFT_EXPR || op == RSHIFT_EXPR)) + { + /* "INT34-C. Do not shift an expression by a negative number of bits + or by greater than or equal to the number of bits that exist in + the operand." */ + if (const tree rhs2_cst = rhs2_sval->maybe_get_constant ()) + if (TREE_CODE (rhs2_cst) == INTEGER_CST) + { + if (tree_int_cst_sgn (rhs2_cst) < 0) + ctxt->warn (new shift_count_negative_diagnostic + (assign, rhs2_cst)); + else if (compare_tree_int (rhs2_cst, + TYPE_PRECISION (TREE_TYPE (rhs1))) + >= 0) + ctxt->warn (new shift_count_overflow_diagnostic + (assign, TYPE_PRECISION (TREE_TYPE (rhs1)), + rhs2_cst)); + } + } + const svalue *sval_binop = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op, rhs1_sval, rhs2_sval); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 553cc07..69bf1fa 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -425,6 +425,8 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-null-dereference @gol -Wno-analyzer-possible-null-argument @gol -Wno-analyzer-possible-null-dereference @gol +-Wno-analyzer-shift-count-negative @gol +-Wno-analyzer-shift-count-overflow @gol -Wno-analyzer-stale-setjmp-buffer @gol -Wno-analyzer-tainted-array-index @gol -Wanalyzer-too-complex @gol @@ -8897,6 +8899,8 @@ Enabling this option effectively enables the following warnings: -Wanalyzer-possible-null-dereference @gol -Wanalyzer-null-argument @gol -Wanalyzer-null-dereference @gol +-Wanalyzer-shift-count-negative @gol +-Wanalyzer-shift-count-overflow @gol -Wanalyzer-stale-setjmp-buffer @gol -Wanalyzer-tainted-array-index @gol -Wanalyzer-unsafe-call-within-signal-handler @gol @@ -9030,6 +9034,35 @@ This warning requires @option{-fanalyzer}, which enables it; use This diagnostic warns for paths through the code in which a value known to be NULL is dereferenced. +@item -Wno-analyzer-shift-count-negative +@opindex Wanalyzer-shift-count-negative +@opindex Wno-analyzer-shift-count-negative +This warning requires @option{-fanalyzer}, which enables it; use +@option{-Wno-analyzer-shift-count-negative} to disable it. + +This diagnostic warns for paths through the code in which a +shift is attempted with a negative count. It is analogous to +the @option{-Wshift-count-negative} diagnostic implemented in +the C/C++ front ends, but is implemented based on analyzing +interprocedural paths, rather than merely parsing the syntax tree. +However, the analyzer does not prioritize detection of such paths, so +false negatives are more likely relative to other warnings. + +@item -Wno-analyzer-shift-count-overflow +@opindex Wanalyzer-shift-count-overflow +@opindex Wno-analyzer-shift-count-overflow +This warning requires @option{-fanalyzer}, which enables it; use +@option{-Wno-analyzer-shift-count-overflow} to disable it. + +This diagnostic warns for paths through the code in which a +shift is attempted with a count greater than or equal to the +precision of the operand's type. It is analogous to +the @option{-Wshift-count-overflow} diagnostic implemented in +the C/C++ front ends, but is implemented based on analyzing +interprocedural paths, rather than merely parsing the syntax tree. +However, the analyzer does not prioritize detection of such paths, so +false negatives are more likely relative to other warnings. + @item -Wno-analyzer-stale-setjmp-buffer @opindex Wanalyzer-stale-setjmp-buffer @opindex Wno-analyzer-stale-setjmp-buffer diff --git a/gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c b/gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c new file mode 100644 index 0000000..08e5272 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c @@ -0,0 +1,34 @@ +/* PR tree-optimization/97424. */ + +#include + +static inline uint32_t +_dl_hwcaps_subdirs_build_bitmask (int subdirs, int active) +{ + /* Leading subdirectories that are not active. */ + int inactive = subdirs - active; + if (inactive == 32) + return 0; + + uint32_t mask; + if (subdirs != 32) + mask = (1 << subdirs) - 1; /* { dg-message "shift by count \\('33'\\) >= precision of type \\('\[0-9\]+'\\)" } */ + else + mask = -1; + return mask ^ ((1U << inactive) - 1); /* { dg-message "shift by negative count \\('-1'\\)" } */ +} + +void f1 (int); + +void +f2 (void) +{ + f1 (_dl_hwcaps_subdirs_build_bitmask (1, 2)); + f1 (_dl_hwcaps_subdirs_build_bitmask (33, 31)); +} + +static int __attribute__((noinline)) op3 (int op, int c) { return op << c; } /* { dg-message "shift by negative count \\('-1'\\)" } */ +int test_3 (void) { return op3 (1, -1); } + +static int __attribute__((noinline)) op4 (int op, int c) { return op << c; } +int test_4 (void) { return op4 (1, 0); } -- cgit v1.1 From 8069928d5c2a99973ac16a49d6c25bc4dc886e14 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 11 Nov 2020 21:18:59 -0500 Subject: analyzer: precision-of-wording for -Wanalyzer-stale-setjmp-buffer This patch adds a custom event to paths emitted by -Wanalyzer-stale-setjmp-buffer highlighting the place where the pertinent stack frame is popped, and updates the final event in the path to reference this. gcc/analyzer/ChangeLog: * checker-path.h (checker_event::get_id_ptr): New. * diagnostic-manager.cc (path_builder::path_builder): Add "sd" param and use it to initialize new field "m_sd". (path_builder::get_pending_diagnostic): New. (path_builder::m_sd): New field. (diagnostic_manager::emit_saved_diagnostic): Pass sd to path_builder ctor. (diagnostic_manager::add_events_for_superedge): Call new maybe_add_custom_events_for_superedge vfunc. * engine.cc (stale_jmp_buf::stale_jmp_buf): Add "setjmp_point" param and use it to initialize new field "m_setjmp_point". Initialize new field "m_stack_pop_event". (stale_jmp_buf::maybe_add_custom_events_for_superedge): New vfunc implementation. (stale_jmp_buf::describe_final_event): New vfunc implementation. (stale_jmp_buf::m_setjmp_point): New field. (stale_jmp_buf::m_stack_pop_event): New field. (exploded_node::on_longjmp): Pass setjmp_point to stale_jmp_buf ctor. * pending-diagnostic.h (pending_diagnostic::maybe_add_custom_events_for_superedge): New vfunc. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/setjmp-5.c: Update expected path output to show an event where the pertinent stack frame is popped. Update expected message from final event to reference this event. --- gcc/analyzer/checker-path.h | 6 ++++ gcc/analyzer/diagnostic-manager.cc | 18 +++++++++-- gcc/analyzer/engine.cc | 55 ++++++++++++++++++++++++++++++-- gcc/analyzer/pending-diagnostic.h | 15 +++++++++ gcc/testsuite/gcc.dg/analyzer/setjmp-5.c | 13 ++++++-- 5 files changed, 99 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h index 7b86d48..a00b3cf 100644 --- a/gcc/analyzer/checker-path.h +++ b/gcc/analyzer/checker-path.h @@ -97,6 +97,12 @@ public: virtual bool is_function_entry_p () const { return false; } virtual bool is_return_p () const { return false; } + /* For use with %@. */ + const diagnostic_event_id_t *get_id_ptr () const + { + return &m_emission_id; + } + void dump (pretty_printer *pp) const; public: diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 93f270f..13f6dd2 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -161,15 +161,22 @@ class path_builder public: path_builder (const exploded_graph &eg, const exploded_path &epath, - const feasibility_problem *problem) + const feasibility_problem *problem, + const saved_diagnostic &sd) : m_eg (eg), m_diag_enode (epath.get_final_enode ()), + m_sd (sd), m_reachability (eg, m_diag_enode), m_feasibility_problem (problem) {} const exploded_node *get_diag_node () const { return m_diag_enode; } + pending_diagnostic *get_pending_diagnostic () const + { + return m_sd.m_d; + } + bool reachable_from_p (const exploded_node *src_enode) const { return m_reachability.reachable_from_p (src_enode); @@ -190,6 +197,8 @@ private: /* The enode where the diagnostic occurs. */ const exploded_node *m_diag_enode; + const saved_diagnostic &m_sd; + /* Precompute all enodes from which the diagnostic is reachable. */ enode_reachability m_reachability; @@ -629,7 +638,7 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, pretty_printer *pp = global_dc->printer->clone (); /* Precompute all enodes from which the diagnostic is reachable. */ - path_builder pb (eg, epath, sd.get_feasibility_problem ()); + path_builder pb (eg, epath, sd.get_feasibility_problem (), sd); /* This is the diagnostic_path subclass that will be built for the diagnostic. */ @@ -1175,6 +1184,11 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb, { gcc_assert (eedge.m_sedge); + /* Give diagnostics an opportunity to override this function. */ + pending_diagnostic *pd = pb.get_pending_diagnostic (); + if (pd->maybe_add_custom_events_for_superedge (eedge, emission_path)) + return; + /* Don't add events for insignificant edges at verbosity levels below 3. */ if (m_verbosity < 3) if (!significant_edge_p (pb, eedge)) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index d247ebb..0a8e5b8 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1277,8 +1277,10 @@ valid_longjmp_stack_p (const program_point &longjmp_point, class stale_jmp_buf : public pending_diagnostic_subclass { public: - stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call) - : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call) + stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call, + const program_point &setjmp_point) + : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call), + m_setjmp_point (setjmp_point), m_stack_pop_event (NULL) {} bool emit (rich_location *richloc) FINAL OVERRIDE @@ -1299,9 +1301,56 @@ public: && m_longjmp_call == other.m_longjmp_call); } + bool + maybe_add_custom_events_for_superedge (const exploded_edge &eedge, + checker_path *emission_path) + FINAL OVERRIDE + { + /* Detect exactly when the stack first becomes invalid, + and issue an event then. */ + if (m_stack_pop_event) + return false; + const exploded_node *src_node = eedge.m_src; + const program_point &src_point = src_node->get_point (); + const exploded_node *dst_node = eedge.m_dest; + const program_point &dst_point = dst_node->get_point (); + if (valid_longjmp_stack_p (src_point, m_setjmp_point) + && !valid_longjmp_stack_p (dst_point, m_setjmp_point)) + { + /* Compare with diagnostic_manager::add_events_for_superedge. */ + const int src_stack_depth = src_point.get_stack_depth (); + m_stack_pop_event = new custom_event + (src_point.get_location (), + src_point.get_fndecl (), + src_stack_depth, + "stack frame is popped here, invalidating saved environment"); + emission_path->add_event (m_stack_pop_event); + return false; + } + return false; + } + + label_text describe_final_event (const evdesc::final_event &ev) + { + if (m_stack_pop_event) + return ev.formatted_print + ("%qs called after enclosing function of %qs returned at %@", + get_user_facing_name (m_longjmp_call), + get_user_facing_name (m_setjmp_call), + m_stack_pop_event->get_id_ptr ()); + else + return ev.formatted_print + ("%qs called after enclosing function of %qs has returned", + get_user_facing_name (m_longjmp_call), + get_user_facing_name (m_setjmp_call));; + } + + private: const gcall *m_setjmp_call; const gcall *m_longjmp_call; + program_point m_setjmp_point; + custom_event *m_stack_pop_event; }; /* Handle LONGJMP_CALL, a call to longjmp or siglongjmp. @@ -1344,7 +1393,7 @@ exploded_node::on_longjmp (exploded_graph &eg, /* Verify that the setjmp's call_stack hasn't been popped. */ if (!valid_longjmp_stack_p (longjmp_point, setjmp_point)) { - ctxt->warn (new stale_jmp_buf (setjmp_call, longjmp_call)); + ctxt->warn (new stale_jmp_buf (setjmp_call, longjmp_call, setjmp_point)); return; } diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h index b1ff268..ce626f6 100644 --- a/gcc/analyzer/pending-diagnostic.h +++ b/gcc/analyzer/pending-diagnostic.h @@ -246,6 +246,21 @@ class pending_diagnostic } /* End of precision-of-wording vfuncs. */ + + /* Vfunc for extending/overriding creation of the events for an + exploded_edge that corresponds to a superedge, allowing for custom + events to be created that are pertinent to a particular + pending_diagnostic subclass. + + For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a + custom event showing when the pertinent stack frame is popped + (and thus the point at which the jmp_buf becomes invalid). */ + + virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &, + checker_path *) + { + return false; + } }; /* A template to make it easier to make subclasses of pending_diagnostic. diff --git a/gcc/testsuite/gcc.dg/analyzer/setjmp-5.c b/gcc/testsuite/gcc.dg/analyzer/setjmp-5.c index bf5b9bf..4787fa3 100644 --- a/gcc/testsuite/gcc.dg/analyzer/setjmp-5.c +++ b/gcc/testsuite/gcc.dg/analyzer/setjmp-5.c @@ -51,18 +51,25 @@ void outer (void) | | | | | (4) 'setjmp' called here | + 'inner': event 5 + | + | NN | } + | | ^ + | | | + | | (5) stack frame is popped here, invalidating saved environment + | <------+ | - 'outer': events 5-6 + 'outer': events 6-7 | | NN | inner (); | | ^~~~~~~~ | | | - | | (5) returning to 'outer' from 'inner' + | | (6) returning to 'outer' from 'inner' | NN | | NN | longjmp (env, 42); | | ~~~~~~~~~~~~~~~~~ | | | - | | (6) here + | | (7) 'longjmp' called after enclosing function of 'setjmp' returned at (5) | { dg-end-multiline-output "" } */ -- cgit v1.1 From d33bc98f5bc65f2505fcaefb0f9055ec67fe36d2 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Wed, 11 Nov 2020 21:18:23 -0600 Subject: testsuite: Adjust pr96789.c by disabling loop vect New test gcc.dg/tree-ssa/pr96789.c fails on arm-none-linux-gnueabihf since loop vectorizer is able to optimize the two loops which operate on array tmp with load_lanes feature support, it make dse3 fail to find expected inputs. As Richard suggested, this patch is to replace option -ftree-vectorize to -ftree-slp-vectorize -fno-tree-loop-vectorize. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr96789.c: Adjusted by disabling loop vectorization. --- gcc/testsuite/gcc.dg/tree-ssa/pr96789.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96789.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96789.c index d6139a0..5704952 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr96789.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96789.c @@ -1,5 +1,8 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -funroll-loops -ftree-vectorize -fdump-tree-dse-details" } */ +/* Disable loop vectorization to avoid that loop vectorizer + optimizes those two loops that operate tmp array so that + subsequent dse3 won't eliminate expected tmp stores. */ +/* { dg-options "-O2 -funroll-loops -ftree-slp-vectorize -fno-tree-loop-vectorize -fdump-tree-dse-details" } */ /* Test if scalar cleanup pass takes effects, mainly check its secondary pass DSE can remove dead stores on array -- cgit v1.1 From 87b7d45e358e4df93b6a93b2e7a55b123ea76f5d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 10 Nov 2020 18:02:04 -0500 Subject: dwarf2: Set DW_AT_declaration for undefined fns [PR97060] If DECL_INITIAL isn't set, we can't emit anything about the body of the function, so add the declaration attribute. gcc/ChangeLog: PR debug/97060 * dwarf2out.c (gen_subprogram_die): It's a declaration if DECL_INITIAL isn't set. gcc/testsuite/ChangeLog: PR debug/97060 * gcc.dg/debug/dwarf2/pr97060.c: New test. --- gcc/dwarf2out.c | 1 + gcc/testsuite/gcc.dg/debug/dwarf2/pr97060.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr97060.c (limited to 'gcc') diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index bea02f9..4452b9fa 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -22859,6 +22859,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) available. */ int declaration = (current_function_decl != decl + || (!DECL_INITIAL (decl) && !origin) || class_or_namespace_scope_p (context_die)); /* A declaration that has been previously dumped needs no diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr97060.c b/gcc/testsuite/gcc.dg/debug/dwarf2/pr97060.c new file mode 100644 index 0000000..c07b904 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr97060.c @@ -0,0 +1,13 @@ +/* PR debug/97060 */ +/* { dg-do compile } */ +/* { dg-options "-g -dA" } */ +/* { dg-final { scan-assembler-times "DW_AT_declaration" 2 } } */ + +extern int foo (unsigned int, unsigned int); + +int +bar (void) +{ + foo (1, 2); + return 0; +} -- cgit v1.1 From 7ea19dcafb8d373732158eb48adbf7bfc8d8ba27 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Thu, 12 Nov 2020 08:20:43 +0100 Subject: IBM Z: Rename mode attr tointvec to TOINTVEC Just a preparation to add a lower-case tointvec. gcc/ChangeLog: * config/s390/vector.md: Rename tointvec to TOINTVEC. * config/s390/vx-builtins.md: Likewise. --- gcc/config/s390/vector.md | 142 ++++++++++++++++++++--------------------- gcc/config/s390/vx-builtins.md | 50 +++++++-------- 2 files changed, 96 insertions(+), 96 deletions(-) (limited to 'gcc') diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 31d3239..58b8999 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -137,7 +137,7 @@ ; Resulting mode of a vector comparison. For floating point modes an ; integer vector mode with the same element size is picked. -(define_mode_attr tointvec [(V1QI "V1QI") (V2QI "V2QI") (V4QI "V4QI") (V8QI "V8QI") (V16QI "V16QI") +(define_mode_attr TOINTVEC [(V1QI "V1QI") (V2QI "V2QI") (V4QI "V4QI") (V8QI "V8QI") (V16QI "V16QI") (V1HI "V1HI") (V2HI "V2HI") (V4HI "V4HI") (V8HI "V8HI") (V1SI "V1SI") (V2SI "V2SI") (V4SI "V4SI") (V1DI "V1DI") (V2DI "V2DI") @@ -697,12 +697,12 @@ (define_expand "vcond_mask_" [(set (match_operand:V 0 "register_operand" "") (if_then_else:V - (eq (match_operand: 3 "register_operand" "") + (eq (match_operand: 3 "register_operand" "") (match_dup 4)) (match_operand:V 2 "register_operand" "") (match_operand:V 1 "register_operand" "")))] "TARGET_VX" - "operands[4] = CONST0_RTX (mode);") + "operands[4] = CONST0_RTX (mode);") ; We only have HW support for byte vectors. The middle-end is @@ -1586,8 +1586,8 @@ ; vfcesb, vfcedb, wfcexb: non-signaling "==" comparison (a == b) (define_insn "*vec_cmpeq_quiet_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (eq: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (eq: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))] "TARGET_VX" "fceb\t%v0,%v1,%v2" @@ -1595,45 +1595,45 @@ ; vfchsb, vfchdb, wfchxb: non-signaling > comparison (!(b u>= a)) (define_insn "vec_cmpgt_quiet_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unge: (match_operand:VFT 2 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unge: (match_operand:VFT 2 "register_operand" "v") (match_operand:VFT 1 "register_operand" "v"))))] "TARGET_VX" "fchb\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) (define_expand "vec_cmplt_quiet_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unge: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v"))))] "TARGET_VX") ; vfchesb, vfchedb, wfchexb: non-signaling >= comparison (!(a u< b)) (define_insn "vec_cmpge_quiet_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unlt: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unlt: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v"))))] "TARGET_VX" "fcheb\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) (define_expand "vec_cmple_quiet_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unlt: (match_operand:VFT 2 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unlt: (match_operand:VFT 2 "register_operand" "v") (match_operand:VFT 1 "register_operand" "v"))))] "TARGET_VX") ; vfkesb, vfkedb, wfkexb: signaling == comparison ((a >= b) & (b >= a)) (define_insn "*vec_cmpeq_signaling_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (and: - (ge: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (and: + (ge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")) - (ge: (match_dup 2) + (ge: (match_dup 2) (match_dup 1))))] "TARGET_VXE" "fkeb\t%v0,%v1,%v2" @@ -1641,16 +1641,16 @@ ; vfkhsb, vfkhdb, wfkhxb: signaling > comparison (a > b) (define_insn "*vec_cmpgt_signaling_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (gt: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (gt: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))] "TARGET_VXE" "fkhb\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) (define_insn "*vec_cmpgt_signaling_finite_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (gt: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (gt: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))] "TARGET_NONSIGNALING_VECTOR_COMPARE_OK" "fchb\t%v0,%v1,%v2" @@ -1658,16 +1658,16 @@ ; vfkhesb, vfkhedb, wfkhexb: signaling >= comparison (a >= b) (define_insn "*vec_cmpge_signaling_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (ge: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (ge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))] "TARGET_VXE" "fkheb\t%v0,%v1,%v2" [(set_attr "op_type" "VRR")]) (define_insn "*vec_cmpge_signaling_finite_nocc" - [(set (match_operand: 0 "register_operand" "=v") - (ge: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (ge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))] "TARGET_NONSIGNALING_VECTOR_COMPARE_OK" "fcheb\t%v0,%v1,%v2" @@ -1679,84 +1679,84 @@ ; UNGT a u> b -> !!(b u< a) (define_expand "vec_cmpungt" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unlt: (match_operand:VFT 2 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unlt: (match_operand:VFT 2 "register_operand" "v") (match_operand:VFT 1 "register_operand" "v")))) (set (match_dup 0) - (not: (match_dup 0)))] + (not: (match_dup 0)))] "TARGET_VX") ; UNGE a u>= b -> !!(a u>= b) (define_expand "vec_cmpunge" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unge: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))) (set (match_dup 0) - (not: (match_dup 0)))] + (not: (match_dup 0)))] "TARGET_VX") ; UNEQ a u== b -> !(!(a u>= b) | !(b u>= a)) (define_expand "vec_cmpuneq" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unge: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unge: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))) (set (match_dup 3) - (not: - (unge: (match_dup 2) + (not: + (unge: (match_dup 2) (match_dup 1)))) (set (match_dup 0) - (ior: (match_dup 0) + (ior: (match_dup 0) (match_dup 3))) (set (match_dup 0) - (not: (match_dup 0)))] + (not: (match_dup 0)))] "TARGET_VX" { - operands[3] = gen_reg_rtx (mode); + operands[3] = gen_reg_rtx (mode); }) ; LTGT a <> b -> a > b | b > a (define_expand "vec_cmpltgt" - [(set (match_operand: 0 "register_operand" "=v") - (gt: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (gt: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v"))) - (set (match_dup 3) (gt: (match_dup 2) (match_dup 1))) - (set (match_dup 0) (ior: (match_dup 0) (match_dup 3)))] + (set (match_dup 3) (gt: (match_dup 2) (match_dup 1))) + (set (match_dup 0) (ior: (match_dup 0) (match_dup 3)))] "TARGET_VXE" { - operands[3] = gen_reg_rtx (mode); + operands[3] = gen_reg_rtx (mode); }) ; ORDERED (a, b): !(a u< b) | !(a u>= b) (define_expand "vec_cmpordered" - [(set (match_operand: 0 "register_operand" "=v") - (not: - (unlt: (match_operand:VFT 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (not: + (unlt: (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")))) (set (match_dup 3) - (not: - (unge: (match_dup 1) + (not: + (unge: (match_dup 1) (match_dup 2)))) (set (match_dup 0) - (ior: (match_dup 0) + (ior: (match_dup 0) (match_dup 3)))] "TARGET_VX" { - operands[3] = gen_reg_rtx (mode); + operands[3] = gen_reg_rtx (mode); }) ; UNORDERED (a, b): !ORDERED (a, b) (define_expand "vec_cmpunordered" - [(match_operand: 0 "register_operand" "=v") + [(match_operand: 0 "register_operand" "=v") (match_operand:VFT 1 "register_operand" "v") (match_operand:VFT 2 "register_operand" "v")] "TARGET_VX" { emit_insn (gen_vec_cmpordered (operands[0], operands[1], operands[2])); emit_insn (gen_rtx_SET (operands[0], - gen_rtx_NOT (mode, operands[0]))); + gen_rtx_NOT (mode, operands[0]))); DONE; }) @@ -1835,7 +1835,7 @@ (define_split [(set (match_operand:V 0 "register_operand" "") (if_then_else:V - (eq (match_operand: 3 "register_operand" "") + (eq (match_operand: 3 "register_operand" "") (match_operand:V 4 "const0_operand" "")) (match_operand:V 1 "const0_operand" "") (match_operand:V 2 "all_ones_operand" "")))] @@ -1849,7 +1849,7 @@ (define_split [(set (match_operand:V 0 "register_operand" "") (if_then_else:V - (eq (match_operand: 3 "register_operand" "") + (eq (match_operand: 3 "register_operand" "") (match_operand:V 4 "const0_operand" "")) (match_operand:V 1 "all_ones_operand" "") (match_operand:V 2 "const0_operand" "")))] @@ -1863,7 +1863,7 @@ (define_split [(set (match_operand:V 0 "register_operand" "") (if_then_else:V - (ne (match_operand: 3 "register_operand" "") + (ne (match_operand: 3 "register_operand" "") (match_operand:V 4 "const0_operand" "")) (match_operand:V 1 "all_ones_operand" "") (match_operand:V 2 "const0_operand" "")))] @@ -1877,7 +1877,7 @@ (define_split [(set (match_operand:V 0 "register_operand" "") (if_then_else:V - (ne (match_operand: 3 "register_operand" "") + (ne (match_operand: 3 "register_operand" "") (match_operand:V 4 "const0_operand" "")) (match_operand:V 1 "const0_operand" "") (match_operand:V 2 "all_ones_operand" "")))] @@ -1891,8 +1891,8 @@ (define_insn "*vec_sel0" [(set (match_operand:V 0 "register_operand" "=v") (if_then_else:V - (eq (match_operand: 3 "register_operand" "v") - (match_operand: 4 "const0_operand" "")) + (eq (match_operand: 3 "register_operand" "v") + (match_operand: 4 "const0_operand" "")) (match_operand:V 1 "register_operand" "v") (match_operand:V 2 "register_operand" "v")))] "TARGET_VX" @@ -1903,8 +1903,8 @@ (define_insn "*vec_sel0" [(set (match_operand:V 0 "register_operand" "=v") (if_then_else:V - (eq (not: (match_operand: 3 "register_operand" "v")) - (match_operand: 4 "const0_operand" "")) + (eq (not: (match_operand: 3 "register_operand" "v")) + (match_operand: 4 "const0_operand" "")) (match_operand:V 1 "register_operand" "v") (match_operand:V 2 "register_operand" "v")))] "TARGET_VX" @@ -1915,8 +1915,8 @@ (define_insn "*vec_sel1" [(set (match_operand:V 0 "register_operand" "=v") (if_then_else:V - (eq (match_operand: 3 "register_operand" "v") - (match_operand: 4 "all_ones_operand" "")) + (eq (match_operand: 3 "register_operand" "v") + (match_operand: 4 "all_ones_operand" "")) (match_operand:V 1 "register_operand" "v") (match_operand:V 2 "register_operand" "v")))] "TARGET_VX" @@ -1927,8 +1927,8 @@ (define_insn "*vec_sel1" [(set (match_operand:V 0 "register_operand" "=v") (if_then_else:V - (eq (not: (match_operand: 3 "register_operand" "v")) - (match_operand: 4 "all_ones_operand" "")) + (eq (not: (match_operand: 3 "register_operand" "v")) + (match_operand: 4 "all_ones_operand" "")) (match_operand:V 1 "register_operand" "v") (match_operand:V 2 "register_operand" "v")))] "TARGET_VX" diff --git a/gcc/config/s390/vx-builtins.md b/gcc/config/s390/vx-builtins.md index 010db4d..2bbed19 100644 --- a/gcc/config/s390/vx-builtins.md +++ b/gcc/config/s390/vx-builtins.md @@ -76,7 +76,7 @@ (define_insn "vec_gather_element" [(set (match_operand:V_HW_32_64 0 "register_operand" "=v") (unspec:V_HW_32_64 [(match_operand:V_HW_32_64 1 "register_operand" "0") - (match_operand: 2 "register_operand" "v") + (match_operand: 2 "register_operand" "v") (match_operand:BLK 3 "memory_operand" "R") (match_operand:QI 4 "const_mask_operand" "C")] UNSPEC_VEC_GATHER))] @@ -477,7 +477,7 @@ (define_insn "vec_scatter_element_" [(set (mem: (plus: (unspec: - [(match_operand: 1 "register_operand" "v") + [(match_operand: 1 "register_operand" "v") (match_operand:QI 3 "const_mask_operand" "C")] UNSPEC_VEC_EXTRACT) (match_operand:DI 2 "address_operand" "ZQ"))) @@ -492,7 +492,7 @@ ; multiplexing here in the expander. (define_expand "vec_scatter_element" [(match_operand:V_HW_32_64 0 "register_operand" "") - (match_operand: 1 "register_operand" "") + (match_operand: 1 "register_operand" "") (match_operand 2 "address_operand" "") (match_operand:QI 3 "const_mask_operand" "")] "TARGET_VX" @@ -813,8 +813,8 @@ }) (define_expand "vec_cmp" - [(set (match_operand: 0 "register_operand" "=v") - (fpcmp: (match_operand:VF_HW 1 "register_operand" "v") + [(set (match_operand: 0 "register_operand" "=v") + (fpcmp: (match_operand:VF_HW 1 "register_operand" "v") (match_operand:VF_HW 2 "register_operand" "v")))] "TARGET_VX" { @@ -1050,7 +1050,7 @@ (define_expand "vec_slb" [(set (match_operand:V_HW 0 "register_operand" "") (unspec:V_HW [(match_operand:V_HW 1 "register_operand" "") - (match_operand: 2 "register_operand" "")] + (match_operand: 2 "register_operand" "")] UNSPEC_VEC_SLB))] "TARGET_VX" { @@ -1121,7 +1121,7 @@ (define_insn "vec_srab" [(set (match_operand:V_HW 0 "register_operand" "=v") (unspec:V_HW [(match_operand:V_HW 1 "register_operand" "v") - (match_operand: 2 "register_operand" "v")] + (match_operand: 2 "register_operand" "v")] UNSPEC_VEC_SRAB))] "TARGET_VX" "vsrab\t%v0,%v1,%v2" @@ -1146,7 +1146,7 @@ (define_expand "vec_srb" [(set (match_operand:V_HW 0 "register_operand" "") (unspec:V_HW [(match_operand:V_HW 1 "register_operand" "") - (match_operand: 2 "register_operand" "")] + (match_operand: 2 "register_operand" "")] UNSPEC_VEC_SRLB))] "TARGET_VX" { @@ -1229,7 +1229,7 @@ (define_expand "vec_test_mask_int" [(set (reg:CCRAW CC_REGNUM) (unspec:CCRAW [(match_operand:V_HW 1 "register_operand" "") - (match_operand: 2 "register_operand" "")] + (match_operand: 2 "register_operand" "")] UNSPEC_VEC_TEST_MASK)) (set (match_operand:SI 0 "register_operand" "") (unspec:SI [(reg:CCRAW CC_REGNUM)] UNSPEC_CC_TO_INT))] @@ -1238,7 +1238,7 @@ (define_insn "*vec_test_mask" [(set (reg:CCRAW CC_REGNUM) (unspec:CCRAW [(match_operand:V_HW 0 "register_operand" "v") - (match_operand: 1 "register_operand" "v")] + (match_operand: 1 "register_operand" "v")] UNSPEC_VEC_TEST_MASK))] "TARGET_VX" "vtm\t%v0,%v1" @@ -1946,7 +1946,7 @@ (unspec:CCRAW [(match_operand:VF_HW 1 "register_operand" "v") (match_operand:HI 2 "const_int_operand" "J")] UNSPEC_VEC_VFTCICC)) - (clobber (match_scratch: 0 "=v"))] + (clobber (match_scratch: 0 "=v"))] "TARGET_VX && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'J', \"J\")" "ftcib\t%v0,%v1,%x2" [(set_attr "op_type" "VRR")]) @@ -1957,7 +1957,7 @@ (unspec:CCRAW [(match_operand:VF_HW 0 "register_operand") (match_operand:HI 1 "const_int_operand")] UNSPEC_VEC_VFTCICC)) - (clobber (scratch:))]) + (clobber (scratch:))]) (set (match_operand:SI 2 "register_operand" "") (unspec:SI [(reg:CCRAW CC_REGNUM)] UNSPEC_CC_TO_INT))] "TARGET_VX && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[1]), 'J', \"J\")") @@ -2083,7 +2083,7 @@ [(set (reg:VFCMP CC_REGNUM) (compare:VFCMP (match_operand:VF_HW 0 "register_operand" "v") (match_operand:VF_HW 1 "register_operand" "v"))) - (clobber (match_scratch: 2 "=v"))] + (clobber (match_scratch: 2 "=v"))] "TARGET_VX" "fcbs\t%v2,%v0,%v1" [(set_attr "op_type" "VRR")]) @@ -2094,8 +2094,8 @@ [(set (reg:CCVEQ CC_REGNUM) (compare:CCVEQ (match_operand:VF_HW 1 "register_operand" "v") (match_operand:VF_HW 2 "register_operand" "v"))) - (set (match_operand: 0 "register_operand" "=v") - (eq: (match_dup 1) (match_dup 2)))]) + (set (match_operand: 0 "register_operand" "=v") + (eq: (match_dup 1) (match_dup 2)))]) (set (match_operand:SI 3 "memory_operand" "") (unspec:SI [(reg:CCVEQ CC_REGNUM)] UNSPEC_CC_TO_INT))] "TARGET_VX") @@ -2105,8 +2105,8 @@ [(set (reg:CCVFH CC_REGNUM) (compare:CCVFH (match_operand:VF_HW 1 "register_operand" "v") (match_operand:VF_HW 2 "register_operand" "v"))) - (set (match_operand: 0 "register_operand" "=v") - (gt: (match_dup 1) (match_dup 2)))]) + (set (match_operand: 0 "register_operand" "=v") + (gt: (match_dup 1) (match_dup 2)))]) (set (match_operand:SI 3 "memory_operand" "") (unspec:SI [(reg:CCVIH CC_REGNUM)] UNSPEC_CC_TO_INT))] "TARGET_VX") @@ -2116,8 +2116,8 @@ [(set (reg:CCVFHE CC_REGNUM) (compare:CCVFHE (match_operand:VF_HW 1 "register_operand" "v") (match_operand:VF_HW 2 "register_operand" "v"))) - (set (match_operand: 0 "register_operand" "=v") - (ge: (match_dup 1) (match_dup 2)))]) + (set (match_operand: 0 "register_operand" "=v") + (ge: (match_dup 1) (match_dup 2)))]) (set (match_operand:SI 3 "memory_operand" "") (unspec:SI [(reg:CCVFHE CC_REGNUM)] UNSPEC_CC_TO_INT))] "TARGET_VX") @@ -2131,8 +2131,8 @@ [(set (reg:CCVEQ CC_REGNUM) (compare:CCVEQ (match_operand:VF_HW 0 "register_operand" "v") (match_operand:VF_HW 1 "register_operand" "v"))) - (set (match_operand: 2 "register_operand" "=v") - (eq: (match_dup 0) (match_dup 1)))] + (set (match_operand: 2 "register_operand" "=v") + (eq: (match_dup 0) (match_dup 1)))] "TARGET_VX" "fcebs\t%v2,%v0,%v1" [(set_attr "op_type" "VRR")]) @@ -2142,8 +2142,8 @@ [(set (reg:CCVFH CC_REGNUM) (compare:CCVFH (match_operand:VF_HW 0 "register_operand" "v") (match_operand:VF_HW 1 "register_operand" "v"))) - (set (match_operand: 2 "register_operand" "=v") - (gt: (match_dup 0) (match_dup 1)))] + (set (match_operand: 2 "register_operand" "=v") + (gt: (match_dup 0) (match_dup 1)))] "TARGET_VX" "fchbs\t%v2,%v0,%v1" [(set_attr "op_type" "VRR")]) @@ -2153,8 +2153,8 @@ [(set (reg:CCVFHE CC_REGNUM) (compare:CCVFHE (match_operand:VF_HW 0 "register_operand" "v") (match_operand:VF_HW 1 "register_operand" "v"))) - (set (match_operand: 2 "register_operand" "=v") - (ge: (match_dup 0) (match_dup 1)))] + (set (match_operand: 2 "register_operand" "=v") + (ge: (match_dup 0) (match_dup 1)))] "TARGET_VX" "fchebs\t%v2,%v0,%v1" [(set_attr "op_type" "VRR")]) -- cgit v1.1 From 5d9ade39b8720b61cf63a8be181fb3b487f6ac5b Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Thu, 12 Nov 2020 08:20:43 +0100 Subject: IBM Z: Fix PR97326: Enable fp compares in vec_cmp gcc/ChangeLog: PR target/97326 * config/s390/vector.md: Support vector floating point modes in vec_cmp. --- gcc/config/s390/vector.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 58b8999..fef6864 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -145,6 +145,16 @@ (V1SF "V1SI") (V2SF "V2SI") (V4SF "V4SI") (V1DF "V1DI") (V2DF "V2DI") (V1TF "V1TI") (TF "V1TI")]) + +(define_mode_attr tointvec [(V1QI "v1qi") (V2QI "v2qi") (V4QI "v4qi") (V8QI "v8qi") (V16QI "v16qi") + (V1HI "v1hi") (V2HI "v2hi") (V4HI "v4hi") (V8HI "v8hi") + (V1SI "v1si") (V2SI "v2si") (V4SI "v4si") + (V1DI "v1di") (V2DI "v2di") + (V1TI "v1ti") + (V1SF "v1si") (V2SF "v2si") (V4SF "v4si") + (V1DF "v1di") (V2DF "v2di") + (V1TF "v1ti") (TF "v1ti")]) + (define_mode_attr vw [(SF "w") (V1SF "w") (V2SF "v") (V4SF "v") (DF "w") (V1DF "w") (V2DF "v") (TF "w") (V1TF "w")]) @@ -1546,14 +1556,14 @@ }) ;; -;; Integer compares +;; Compares ;; -(define_expand "vec_cmp" - [(set (match_operand:VI_HW 0 "register_operand" "") - (match_operator:VI_HW 1 "" - [(match_operand:VI_HW 2 "register_operand" "") - (match_operand:VI_HW 3 "register_operand" "")]))] +(define_expand "vec_cmp" + [(set (match_operand: 0 "register_operand" "") + (match_operator: 1 "" + [(match_operand:V_HW 2 "register_operand" "") + (match_operand:V_HW 3 "register_operand" "")]))] "TARGET_VX" { s390_expand_vec_compare (operands[0], GET_CODE(operands[1]), operands[2], operands[3]); -- cgit v1.1 From fc531c2ed3ce456efca946e995544b216b3c16df Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Nov 2020 10:46:04 +0100 Subject: c++: Fix up constexpr CLEANUP_POINT_EXPR and TRY_FINALLY_EXPR handling [PR97790] As the testcase shows, CLEANUP_POINT_EXPR (and I think TRY_FINALLY_EXPR too) suffer from the same problem that I was trying to fix in r10-3597-g1006c9d4395a939820df76f37c7b085a4a1a003f for CLEANUP_STMT, namely that if in the middle of the body expression of those stmts is e.g. return stmt, goto, break or continue (something that changes *jump_target and makes it start skipping stmts), we then skip the cleanups too, which is not appropriate - the cleanups were either queued up during the non-skipping execution of the body (for CLEANUP_POINT_EXPR), or for TRY_FINALLY_EXPR are relevant already after entering the body block. > Would it make sense to always use a NULL jump_target when evaluating > cleanups? I was afraid of that, especially for TRY_FINALLY_EXPR, but it seems that during constexpr evaluation the cleanups will most often be just very simple destructor calls (or calls to cleanup attribute functions). Furthermore, for neither of these 3 tree codes we'll reach that code if jump_target && *jump_target initially (there is a return NULL_TREE much earlier for those except for trees that could embed labels etc. in it and clearly these 3 don't count in that). 2020-11-12 Jakub Jelinek PR c++/97790 * constexpr.c (cxx_eval_constant_expression) : Don't pass jump_target to cxx_eval_constant_expression when evaluating the cleanups. * g++.dg/cpp2a/constexpr-dtor9.C: New test. --- gcc/cp/constexpr.c | 34 ++++++++++------------------ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C | 31 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C (limited to 'gcc') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index b6f9c43..e6ab5ee 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6018,8 +6018,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) cxx_eval_constant_expression (ctx, cleanup, false, - non_constant_p, overflow_p, - jump_target); + non_constant_p, overflow_p); } break; @@ -6030,29 +6029,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (!*non_constant_p) /* Also evaluate the cleanup. */ cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), true, - non_constant_p, overflow_p, - jump_target); + non_constant_p, overflow_p); break; case CLEANUP_STMT: - { - tree initial_jump_target = jump_target ? *jump_target : NULL_TREE; - r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, - non_constant_p, overflow_p, - jump_target); - if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) - { - iloc_sentinel ils (loc); - /* Also evaluate the cleanup. If we weren't skipping at the - start of the CLEANUP_BODY, change jump_target temporarily - to &initial_jump_target, so that even a return or break or - continue in the body doesn't skip the cleanup. */ - cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, - non_constant_p, overflow_p, - jump_target ? &initial_jump_target - : NULL); - } - } + r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, + non_constant_p, overflow_p, + jump_target); + if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) + { + iloc_sentinel ils (loc); + /* Also evaluate the cleanup. */ + cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, + non_constant_p, overflow_p); + } break; /* These differ from cxx_eval_unary_expression in that this doesn't diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C new file mode 100644 index 0000000..975e5fc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C @@ -0,0 +1,31 @@ +// PR c++/97790 +// { dg-do compile { target c++20 } } + +struct S +{ + int *d; + int n; + constexpr S () : d(new int[1]{}), n(1) {} + constexpr ~S () { delete [] d; } +}; + +constexpr S +foo () +{ + return S (); +} + +constexpr int +bar () +{ + return foo ().n; +} + +constexpr int +baz () +{ + return S ().n; +} + +constexpr int a = baz (); +constexpr int b = bar (); -- cgit v1.1 From 64326bb428ac750ec3b0f56c06dfb98277cd41b5 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 12 Nov 2020 09:10:51 +0100 Subject: tree-optimization/97806 - fix PRE expression post order This fixes the postorder compute for the case of multiple expression leaders for a value. 2020-11-12 Richard Biener PR tree-optimization/97806 * tree-ssa-pre.c (pre_expr_DFS): New overload for visiting values, visiting all leaders for a value. Use a bitmap for visited values. (sorted_array_from_bitmap_set): Walk over values and adjust. * gcc.dg/pr97806.c: New testcase. --- gcc/testsuite/gcc.dg/pr97806.c | 16 ++++++++++ gcc/tree-ssa-pre.c | 70 ++++++++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr97806.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr97806.c b/gcc/testsuite/gcc.dg/pr97806.c new file mode 100644 index 0000000..9ec3299 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr97806.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int b; +long c; +int g(); +void h(long *); +void i(long *); +void d() { + int e, f = b - e; + if (g()) + h(&c + f); + else + i(&c + f); + __builtin_memset(0, 0, f * 8); +} diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 10d223b..eb18173 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -805,16 +805,36 @@ bitmap_set_free (bitmap_set_t set) bitmap_clear (&set->values); } +static void +pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap expr_visited, + bitmap val_visited, vec &post); + +/* DFS walk leaders of VAL to their operands with leaders in SET, collecting + expressions in SET in postorder into POST. */ + +static void +pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap expr_visited, + bitmap val_visited, vec &post) +{ + unsigned int i; + bitmap_iterator bi; + + /* Iterate over all leaders and DFS recurse. Borrowed from + bitmap_find_leader. */ + bitmap exprset = value_expressions[val]; + EXECUTE_IF_AND_IN_BITMAP (exprset, &set->expressions, 0, i, bi) + pre_expr_DFS (expression_for_id (i), + set, expr_visited, val_visited, post); +} /* DFS walk EXPR to its operands with leaders in SET, collecting expressions in SET in postorder into POST. */ static void -pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap visited, - hash_set > &leader_set, - vec &post) +pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap expr_visited, + bitmap val_visited, vec &post) { - if (!bitmap_set_bit (visited, get_expression_id (expr))) + if (!bitmap_set_bit (expr_visited, get_expression_id (expr))) return; switch (expr->kind) @@ -829,12 +849,9 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap visited, unsigned int op_val_id = VN_INFO (nary->op[i])->value_id; /* If we already found a leader for the value we've recursed already. Avoid the costly bitmap_find_leader. */ - if (!leader_set.add (op_val_id)) - { - pre_expr leader = bitmap_find_leader (set, op_val_id); - if (leader) - pre_expr_DFS (leader, set, visited, leader_set, post); - } + if (bitmap_bit_p (&set->values, op_val_id) + && bitmap_set_bit (val_visited, op_val_id)) + pre_expr_DFS (op_val_id, set, expr_visited, val_visited, post); } break; } @@ -854,12 +871,10 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap visited, if (!op[n] || TREE_CODE (op[n]) != SSA_NAME) continue; unsigned op_val_id = VN_INFO (op[n])->value_id; - if (!leader_set.add (op_val_id)) - { - pre_expr leader = bitmap_find_leader (set, op_val_id); - if (leader) - pre_expr_DFS (leader, set, visited, leader_set, post); - } + if (bitmap_bit_p (&set->values, op_val_id) + && bitmap_set_bit (val_visited, op_val_id)) + pre_expr_DFS (op_val_id, + set, expr_visited, val_visited, post); } } break; @@ -879,20 +894,15 @@ sorted_array_from_bitmap_set (bitmap_set_t set) vec result; /* Pre-allocate enough space for the array. */ - size_t len = bitmap_count_bits (&set->expressions); - result.create (len); - hash_set > leader_set (2*len); - - auto_bitmap visited (&grand_bitmap_obstack); - bitmap_tree_view (visited); - FOR_EACH_EXPR_ID_IN_SET (set, i, bi) - { - pre_expr expr = expression_for_id (i); - /* Hoist insertion calls us with a value-set we have to and with, - do so. */ - if (bitmap_set_contains_value (set, get_expr_value_id (expr))) - pre_expr_DFS (expr, set, visited, leader_set, result); - } + result.create (bitmap_count_bits (&set->expressions)); + + auto_bitmap expr_visited (&grand_bitmap_obstack); + auto_bitmap val_visited (&grand_bitmap_obstack); + bitmap_tree_view (expr_visited); + bitmap_tree_view (val_visited); + FOR_EACH_VALUE_ID_IN_SET (set, i, bi) + if (bitmap_set_bit (val_visited, i)) + pre_expr_DFS (i, set, expr_visited, val_visited, result); return result; } -- cgit v1.1 From 7f445b5d6116000f1a6527f2164836cbc7c01dee Mon Sep 17 00:00:00 2001 From: Alex Coplan Date: Thu, 12 Nov 2020 10:03:21 +0000 Subject: aarch64: Fix SVE2 BCAX pattern [PR97730] This patch adds a missing not to the SVE2 BCAX (Bitwise clear and exclusive or) pattern, fixing the PR. Since SVE doesn't have an unpredicated not instruction, we need to use a (vacuously) predicated not here. To ensure that the predicate is instantiated correctly (to all 1s) for the intrinsics, we pull out a separate expander from the define_insn. From the ISA reference [1]: > Bitwise AND elements of the second source vector with the > corresponding inverted elements of the third source vector, then > exclusive OR the results with corresponding elements of the first > source vector. [1] : https://developer.arm.com/docs/ddi0602/g/a64-sve-instructions-alphabetic-order/bcax-bitwise-clear-and-exclusive-or gcc/ChangeLog: PR target/97730 * config/aarch64/aarch64-sve2.md (@aarch64_sve2_bcax): Change to define_expand, add missing (trivially-predicated) not rtx to fix wrong code bug. (*aarch64_sve2_bcax): New. gcc/testsuite/ChangeLog: PR target/97730 * gcc.target/aarch64/sve2/bcax_1.c (OP): Add missing bitwise not to match correct bcax semantics. * gcc.dg/vect/pr97730.c: New test. --- gcc/config/aarch64/aarch64-sve2.md | 31 +++++++++++++++++++++++--- gcc/testsuite/gcc.dg/vect/pr97730.c | 12 ++++++++++ gcc/testsuite/gcc.target/aarch64/sve2/bcax_1.c | 2 +- 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/pr97730.c (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md index 0cafd0b..12dc9aa 100644 --- a/gcc/config/aarch64/aarch64-sve2.md +++ b/gcc/config/aarch64/aarch64-sve2.md @@ -786,17 +786,42 @@ ;; ------------------------------------------------------------------------- ;; Unpredicated exclusive OR of AND. -(define_insn "@aarch64_sve2_bcax" +(define_expand "@aarch64_sve2_bcax" + [(set (match_operand:SVE_FULL_I 0 "register_operand") + (xor:SVE_FULL_I + (and:SVE_FULL_I + (unspec:SVE_FULL_I + [(match_dup 4) + (not:SVE_FULL_I + (match_operand:SVE_FULL_I 3 "register_operand"))] + UNSPEC_PRED_X) + (match_operand:SVE_FULL_I 2 "register_operand")) + (match_operand:SVE_FULL_I 1 "register_operand")))] + "TARGET_SVE2" + { + operands[4] = CONSTM1_RTX (mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve2_bcax" [(set (match_operand:SVE_FULL_I 0 "register_operand" "=w, ?&w") (xor:SVE_FULL_I (and:SVE_FULL_I - (match_operand:SVE_FULL_I 2 "register_operand" "w, w") - (match_operand:SVE_FULL_I 3 "register_operand" "w, w")) + (unspec:SVE_FULL_I + [(match_operand 4) + (not:SVE_FULL_I + (match_operand:SVE_FULL_I 3 "register_operand" "w, w"))] + UNSPEC_PRED_X) + (match_operand:SVE_FULL_I 2 "register_operand" "w, w")) (match_operand:SVE_FULL_I 1 "register_operand" "0, w")))] "TARGET_SVE2" "@ bcax\t%0.d, %0.d, %2.d, %3.d movprfx\t%0, %1\;bcax\t%0.d, %0.d, %2.d, %3.d" + "&& !CONSTANT_P (operands[4])" + { + operands[4] = CONSTM1_RTX (mode); + } [(set_attr "movprfx" "*,yes")] ) diff --git a/gcc/testsuite/gcc.dg/vect/pr97730.c b/gcc/testsuite/gcc.dg/vect/pr97730.c new file mode 100644 index 0000000..af4bca4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr97730.c @@ -0,0 +1,12 @@ +/* { dg-additional-options "-O1" } */ +unsigned b = 0xce8e5a48, c = 0xb849691a; +unsigned a[8080]; +int main() { + a[0] = b; + c = c; + unsigned f = 0xb1e8; + for (int h = 0; h < 5; h++) + a[h] = (b & c) ^ f; + if (a[0] != 0x8808f9e0) + __builtin_abort(); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/bcax_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/bcax_1.c index 4b0d5a9..7c31afc 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve2/bcax_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve2/bcax_1.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-details --save-temps" } */ -#define OP(x,y,z) ((x) ^ ((y) & (z))) +#define OP(x,y,z) ((x) ^ (~(y) & (z))) #include "bitsel_1.c" -- cgit v1.1 From 512c6ba04102295fccc62a173ee0086ca733c920 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 12 Nov 2020 11:29:12 +0100 Subject: Avoid PRE insert iteration when possible The following make sure to only iterate PRE insertion when necessary - which is when AVAIL_OUT of a predecessor of a block we already visited changed (that's backedge destinations). To not regress this also makes sure to locally iterate insertion since even topological sort of expressions isn't enough to guarantee we get all opportunities of a block in one iteration. This avoids costly re-compute of the topologically sorted expression array (more micro-optimization is possible here). 2020-11-12 Richard Biener * tree-ssa-pre.c (bitmap_value_replace_in_set): Return whether we have changed anything. (do_pre_regular_insertion): Get topologically sorted array of expressions from caller. (do_pre_partial_partial_insertion): Likewise. (insert): Compute topologically sorted arrays of expressions here and locally iterate actual insertion. Iterate only when AVAIL_OUT of an already visited block source changed. --- gcc/tree-ssa-pre.c | 86 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 29 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index eb18173..9db1b02 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -524,7 +524,7 @@ static struct static bool do_partial_partial; static pre_expr bitmap_find_leader (bitmap_set_t, unsigned int); static void bitmap_value_insert_into_set (bitmap_set_t, pre_expr); -static void bitmap_value_replace_in_set (bitmap_set_t, pre_expr); +static bool bitmap_value_replace_in_set (bitmap_set_t, pre_expr); static void bitmap_set_copy (bitmap_set_t, bitmap_set_t); static bool bitmap_set_contains_value (bitmap_set_t, unsigned int); static void bitmap_insert_into_set (bitmap_set_t, pre_expr); @@ -974,14 +974,14 @@ bitmap_set_equal (bitmap_set_t a, bitmap_set_t b) } /* Replace an instance of EXPR's VALUE with EXPR in SET if it exists, - and add it otherwise. */ + and add it otherwise. Return true if any changes were made. */ -static void +static bool bitmap_value_replace_in_set (bitmap_set_t set, pre_expr expr) { unsigned int val = get_expr_value_id (expr); if (value_id_constant_p (val)) - return; + return false; if (bitmap_set_contains_value (set, val)) { @@ -1002,13 +1002,14 @@ bitmap_value_replace_in_set (bitmap_set_t set, pre_expr expr) if (bitmap_clear_bit (&set->expressions, i)) { bitmap_set_bit (&set->expressions, get_expression_id (expr)); - return; + return i != get_expression_id (expr); } } gcc_unreachable (); } - else - bitmap_insert_into_set (set, expr); + + bitmap_insert_into_set (set, expr); + return true; } /* Insert EXPR into SET if EXPR's value is not already present in @@ -3158,7 +3159,8 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, && expr->kind != REFERENCE) { if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Skipping insertion of phi for partial redundancy: Looks like an induction variable\n"); + fprintf (dump_file, "Skipping insertion of phi for partial " + "redundancy: Looks like an induction variable\n"); nophi = true; } } @@ -3166,6 +3168,10 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, /* Make the necessary insertions. */ FOR_EACH_EDGE (pred, ei, block->preds) { + /* When we are not inserting a PHI node do not bother inserting + into places that do not dominate the anticipated computations. */ + if (nophi && !dominated_by_p (CDI_DOMINATORS, block, pred->src)) + continue; gimple_seq stmts = NULL; tree builtexpr; bprime = pred->src; @@ -3308,15 +3314,14 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, */ static bool -do_pre_regular_insertion (basic_block block, basic_block dom) +do_pre_regular_insertion (basic_block block, basic_block dom, + vec exprs) { bool new_stuff = false; - vec exprs; pre_expr expr; auto_vec avail; int i; - exprs = sorted_array_from_bitmap_set (ANTIC_IN (block)); avail.safe_grow (EDGE_COUNT (block->preds), true); FOR_EACH_VEC_ELT (exprs, i, expr) @@ -3464,7 +3469,6 @@ do_pre_regular_insertion (basic_block block, basic_block dom) } } - exprs.release (); return new_stuff; } @@ -3476,15 +3480,14 @@ do_pre_regular_insertion (basic_block block, basic_block dom) remove the later computation. */ static bool -do_pre_partial_partial_insertion (basic_block block, basic_block dom) +do_pre_partial_partial_insertion (basic_block block, basic_block dom, + vec exprs) { bool new_stuff = false; - vec exprs; pre_expr expr; auto_vec avail; int i; - exprs = sorted_array_from_bitmap_set (PA_IN (block)); avail.safe_grow (EDGE_COUNT (block->preds), true); FOR_EACH_VEC_ELT (exprs, i, expr) @@ -3599,7 +3602,6 @@ do_pre_partial_partial_insertion (basic_block block, basic_block dom) } } - exprs.release (); return new_stuff; } @@ -3759,7 +3761,10 @@ insert (void) NEW_SETS (bb) = bitmap_set_new (); int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (cfun)); + int *bb_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun) + 1); int rpo_num = pre_and_rev_post_order_compute (NULL, rpo, false); + for (int i = 0; i < rpo_num; ++i) + bb_rpo[rpo[i]] = i; int num_iterations = 0; bool changed; @@ -3783,26 +3788,47 @@ insert (void) /* First, update the AVAIL_OUT set with anything we may have inserted higher up in the dominator tree. */ newset = NEW_SETS (dom); - if (newset) + + /* Note that we need to value_replace both NEW_SETS, and + AVAIL_OUT. For both the case of NEW_SETS, the value may be + represented by some non-simple expression here that we want + to replace it with. */ + bool avail_out_changed = false; + FOR_EACH_EXPR_ID_IN_SET (newset, i, bi) { - /* Note that we need to value_replace both NEW_SETS, and - AVAIL_OUT. For both the case of NEW_SETS, the value may be - represented by some non-simple expression here that we want - to replace it with. */ - FOR_EACH_EXPR_ID_IN_SET (newset, i, bi) - { - pre_expr expr = expression_for_id (i); - bitmap_value_replace_in_set (NEW_SETS (block), expr); - bitmap_value_replace_in_set (AVAIL_OUT (block), expr); - } + pre_expr expr = expression_for_id (i); + bitmap_value_replace_in_set (NEW_SETS (block), expr); + avail_out_changed + |= bitmap_value_replace_in_set (AVAIL_OUT (block), expr); + } + /* We need to iterate if AVAIL_OUT of an already processed + block source. */ + if (avail_out_changed && !changed) + { + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, block->succs) + if (bb_rpo[e->src->index] < idx) + changed = true; } /* Insert expressions for partial redundancies. */ if (flag_tree_pre && !single_pred_p (block)) { - changed |= do_pre_regular_insertion (block, dom); + vec exprs + = sorted_array_from_bitmap_set (ANTIC_IN (block)); + /* Sorting is not perfect, iterate locally. */ + while (do_pre_regular_insertion (block, dom, exprs)) + ; + exprs.release (); if (do_partial_partial) - changed |= do_pre_partial_partial_insertion (block, dom); + { + exprs = sorted_array_from_bitmap_set (PA_IN (block)); + while (do_pre_partial_partial_insertion (block, dom, + exprs)) + ; + exprs.release (); + } } } } @@ -3821,6 +3847,7 @@ insert (void) propagate NEW_SETS from hoist insertion. */ FOR_ALL_BB_FN (bb, cfun) { + bitmap_set_free (NEW_SETS (bb)); bitmap_set_pool.remove (NEW_SETS (bb)); NEW_SETS (bb) = NULL; } @@ -3840,6 +3867,7 @@ insert (void) } free (rpo); + free (bb_rpo); } -- cgit v1.1 From 3c3beb1a8137460bc485f9fbe3be8b21ee7f91a2 Mon Sep 17 00:00:00 2001 From: Thomas Koenig Date: Thu, 12 Nov 2020 12:49:53 +0100 Subject: Add test case for PR 97799. gcc/testsuite/ChangeLog: * gfortran.dg/entry_23.f: New test. --- gcc/testsuite/gfortran.dg/entry_23.f | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/entry_23.f (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/entry_23.f b/gcc/testsuite/gfortran.dg/entry_23.f new file mode 100644 index 0000000..ebc5f66 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/entry_23.f @@ -0,0 +1,57 @@ +! { dg-do run } +! PR 97799 - this used to segfault intermittently. +! Test case by George Hockney. + PROGRAM MAIN + IMPLICIT NONE + + character *(20) CA(4) ! four cells of length 20 + + call CHAR_ENTRY(CA) ! call char_sub through entry + + write (*,*) CA ! write result -- not needed for bug + call CHAR_SUB(CA) ! call char_sb directly -- not needed + write (*,*) CA ! write result -- not needed for bug + STOP + END + + + + SUBROUTINE CHAR_SUB(CARRAY) ! sets carray cells to 'Something' + IMPLICIT NONE + + CHARACTER*(*) CARRAY(*) + + integer i + integer nelts + + nelts = 4 ! same as size of array in main program + write (*,*) 'CHAR_SUB' + write (*,*) 'len(carray(1))', len(carray(1)) ! len is OK at 20 + call flush() ! since the next loop segfaults + do 1 i=1, nelts + CARRAY(i) = 'Something' + 1 continue + RETURN + END + + + SUBROUTINE TOP_ENTRY +! +! TOP_ENTRY is never called directly. It organizes entry points +! and sometimes saves variables for other entry points. Its +! signature does not matter for the failure +! + IMPLICIT NONE +! +! Declare input variables for all entry points. Just one here +! + CHARACTER*(*) CARRAY(*) +! +! Entry point CHAR_ENTRY +! + ENTRY CHAR_ENTRY( CARRAY) + CALL CHAR_SUB(CARRAY) + RETURN + + END SUBROUTINE TOP_ENTRY + -- cgit v1.1 From b71ff8c15f5a7d6b1cc1524b4d27843f0d88dbda Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Thu, 12 Nov 2020 14:13:45 +0100 Subject: Fortran: improve location data for OpenACC/OpenMP directives [PR97782] gcc/fortran/ChangeLog: PR fortran/97782 * trans-openmp.c (gfc_trans_oacc_construct, gfc_trans_omp_parallel_do, gfc_trans_omp_parallel_do_simd, gfc_trans_omp_parallel_sections, gfc_trans_omp_parallel_workshare, gfc_trans_omp_sections gfc_trans_omp_single, gfc_trans_omp_task, gfc_trans_omp_teams gfc_trans_omp_target, gfc_trans_omp_target_data, gfc_trans_omp_workshare): Use code->loc instead of input_location when building the OMP_/OACC_ construct. gcc/testsuite/ChangeLog: PR fortran/97782 * gfortran.dg/goacc/classify-kernels-unparallelized.f95: Move dg-message one line up. * gfortran.dg/goacc/classify-kernels.f95: Likewise. --- gcc/fortran/trans-openmp.c | 50 +++++++++++----------- .../goacc/classify-kernels-unparallelized.f95 | 4 +- .../gfortran.dg/goacc/classify-kernels.f95 | 4 +- 3 files changed, 30 insertions(+), 28 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index d2559bd..6b4ad6a 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -3922,8 +3922,8 @@ gfc_trans_oacc_construct (gfc_code *code) oacc_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, code->loc, false, true); stmt = gfc_trans_omp_code (code->block->next, true); - stmt = build2_loc (input_location, construct_code, void_type_node, stmt, - oacc_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), construct_code, + void_type_node, stmt, oacc_clauses); gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); } @@ -5351,8 +5351,8 @@ gfc_trans_omp_parallel_do (gfc_code *code, stmtblock_t *pblock, } else if (TREE_CODE (stmt) != BIND_EXPR) stmt = build3_v (BIND_EXPR, NULL, stmt, NULL_TREE); - stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, + void_type_node, stmt, omp_clauses); OMP_PARALLEL_COMBINED (stmt) = 1; gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); @@ -5394,8 +5394,8 @@ gfc_trans_omp_parallel_do_simd (gfc_code *code, stmtblock_t *pblock, stmt = build3_v (BIND_EXPR, NULL, stmt, NULL_TREE); if (flag_openmp) { - stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, + void_type_node, stmt, omp_clauses); OMP_PARALLEL_COMBINED (stmt) = 1; } gfc_add_expr_to_block (&block, stmt); @@ -5421,8 +5421,8 @@ gfc_trans_omp_parallel_sections (gfc_code *code) stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); else poplevel (0, 0); - stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, + void_type_node, stmt, omp_clauses); OMP_PARALLEL_COMBINED (stmt) = 1; gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); @@ -5444,8 +5444,8 @@ gfc_trans_omp_parallel_workshare (gfc_code *code) pushlevel (); stmt = gfc_trans_omp_workshare (code, &workshare_clauses); stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); - stmt = build2_loc (input_location, OMP_PARALLEL, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, + void_type_node, stmt, omp_clauses); OMP_PARALLEL_COMBINED (stmt) = 1; gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); @@ -5457,6 +5457,7 @@ gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses) stmtblock_t block, body; tree omp_clauses, stmt; bool has_lastprivate = clauses->lists[OMP_LIST_LASTPRIVATE] != NULL; + location_t loc = gfc_get_location (&code->loc); gfc_start_block (&block); @@ -5477,8 +5478,7 @@ gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses) } stmt = gfc_finish_block (&body); - stmt = build2_loc (input_location, OMP_SECTIONS, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (loc, OMP_SECTIONS, void_type_node, stmt, omp_clauses); gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); @@ -5489,8 +5489,8 @@ gfc_trans_omp_single (gfc_code *code, gfc_omp_clauses *clauses) { tree omp_clauses = gfc_trans_omp_clauses (NULL, clauses, code->loc); tree stmt = gfc_trans_omp_code (code->block->next, true); - stmt = build2_loc (input_location, OMP_SINGLE, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_SINGLE, void_type_node, + stmt, omp_clauses); return stmt; } @@ -5506,8 +5506,8 @@ gfc_trans_omp_task (gfc_code *code) pushlevel (); stmt = gfc_trans_omp_code (code->block->next, true); stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); - stmt = build2_loc (input_location, OMP_TASK, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_TASK, void_type_node, + stmt, omp_clauses); gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); } @@ -5649,8 +5649,8 @@ gfc_trans_omp_teams (gfc_code *code, gfc_omp_clauses *clausesa, if (flag_openmp) { stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); - stmt = build2_loc (input_location, OMP_TEAMS, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_TEAMS, + void_type_node, stmt, omp_clauses); if (combined) OMP_TEAMS_COMBINED (stmt) = 1; } @@ -5753,8 +5753,8 @@ gfc_trans_omp_target (gfc_code *code) } if (flag_openmp) { - stmt = build2_loc (input_location, OMP_TARGET, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_TARGET, + void_type_node, stmt, omp_clauses); if (code->op != EXEC_OMP_TARGET) OMP_TARGET_COMBINED (stmt) = 1; cfun->has_omp_target = true; @@ -5815,8 +5815,8 @@ gfc_trans_omp_target_data (gfc_code *code) omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, code->loc); stmt = gfc_trans_omp_code (code->block->next, true); - stmt = build2_loc (input_location, OMP_TARGET_DATA, void_type_node, stmt, - omp_clauses); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_TARGET_DATA, + void_type_node, stmt, omp_clauses); gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); } @@ -5876,6 +5876,7 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) bool singleblock_in_progress = false; /* True if previous gfc_code in workshare construct is not workshared. */ bool prev_singleunit; + location_t loc = gfc_get_location (&code->loc); code = code->block->next; @@ -5966,7 +5967,7 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) { /* Finish single block and add it to pblock. */ tmp = gfc_finish_block (&singleblock); - tmp = build2_loc (input_location, OMP_SINGLE, + tmp = build2_loc (loc, OMP_SINGLE, void_type_node, tmp, NULL_TREE); gfc_add_expr_to_block (pblock, tmp); /* Add current gfc_code to pblock. */ @@ -5982,6 +5983,7 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) gfc_init_block (&singleblock); gfc_add_expr_to_block (&singleblock, res); singleblock_in_progress = true; + loc = gfc_get_location (&code->loc); } else /* Add the new statement to the block. */ @@ -5996,7 +5998,7 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) { /* Finish single block and add it to pblock. */ tmp = gfc_finish_block (&singleblock); - tmp = build2_loc (input_location, OMP_SINGLE, void_type_node, tmp, + tmp = build2_loc (loc, OMP_SINGLE, void_type_node, tmp, clauses->nowait ? build_omp_clause (input_location, OMP_CLAUSE_NOWAIT) : NULL_TREE); diff --git a/gcc/testsuite/gfortran.dg/goacc/classify-kernels-unparallelized.f95 b/gcc/testsuite/gfortran.dg/goacc/classify-kernels-unparallelized.f95 index 0877242..6cca3d6 100644 --- a/gcc/testsuite/gfortran.dg/goacc/classify-kernels-unparallelized.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/classify-kernels-unparallelized.f95 @@ -19,8 +19,8 @@ program main call setup(a, b) - !$acc kernels copyin (a(0:n-1), b(0:n-1)) copyout (c(0:n-1)) - do i = 0, n - 1 ! { dg-message "optimized: assigned OpenACC seq loop parallelism" } + !$acc kernels copyin (a(0:n-1), b(0:n-1)) copyout (c(0:n-1)) ! { dg-message "optimized: assigned OpenACC seq loop parallelism" } + do i = 0, n - 1 c(i) = a(f (i)) + b(f (i)) end do !$acc end kernels diff --git a/gcc/testsuite/gfortran.dg/goacc/classify-kernels.f95 b/gcc/testsuite/gfortran.dg/goacc/classify-kernels.f95 index f2c4736..715a983 100644 --- a/gcc/testsuite/gfortran.dg/goacc/classify-kernels.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/classify-kernels.f95 @@ -15,8 +15,8 @@ program main call setup(a, b) - !$acc kernels copyin (a(0:n-1), b(0:n-1)) copyout (c(0:n-1)) - do i = 0, n - 1 ! { dg-message "optimized: assigned OpenACC gang loop parallelism" } + !$acc kernels copyin (a(0:n-1), b(0:n-1)) copyout (c(0:n-1)) ! { dg-message "optimized: assigned OpenACC gang loop parallelism" } + do i = 0, n - 1 c(i) = a(i) + b(i) end do !$acc end kernels -- cgit v1.1 From 071a31a53388229213f323ecdc680ff8aeda456c Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 12 Nov 2020 14:56:40 +0100 Subject: Add support for copy specifiers in fnspec * attr-fnspec.h: Update topleve comment. (attr_fnspec::arg_direct_p): Accept 1...9. (attr_fnspec::arg_maybe_written_p): Reject 1...9. (attr_fnspec::arg_copied_to_arg_p): New member function. * builtins.c (builtin_fnspec): Update fnspec of block copy. * tree-ssa-alias.c (attr_fnspec::verify): Update. --- gcc/attr-fnspec.h | 28 ++++++++++++++++++++++++---- gcc/builtins.c | 16 ++++++++-------- gcc/tree-ssa-alias.c | 35 ++++++++++++++++++++++------------- 3 files changed, 54 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h index 28135328..b4b49e9 100644 --- a/gcc/attr-fnspec.h +++ b/gcc/attr-fnspec.h @@ -41,6 +41,9 @@ written and does not escape 'w' or 'W' specifies that the memory pointed to by the parameter does not escape + '1'....'9' specifies that the memory pointed to by the parameter is + copied to memory pointed to by different parameter + (as in memcpy). '.' specifies that nothing is known. The uppercase letter in addition specifies that the memory pointed to by the parameter is not dereferenced. For 'r' only read applies @@ -51,8 +54,8 @@ ' ' nothing is known 't' the size of value written/read corresponds to the size of of the pointed-to type of the argument type - '1'...'9' the size of value written/read is given by the specified - argument + '1'...'9' specifies the size of value written/read is given by the + specified argument */ #ifndef ATTR_FNSPEC_H @@ -122,7 +125,8 @@ public: { unsigned int idx = arg_idx (i); gcc_checking_assert (arg_specified_p (i)); - return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W'; + return str[idx] == 'R' || str[idx] == 'O' + || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9'); } /* True if argument is used. */ @@ -161,6 +165,7 @@ public: unsigned int idx = arg_idx (i); gcc_checking_assert (arg_specified_p (i)); return str[idx] != 'r' && str[idx] != 'R' + && (str[idx] < '1' || str[idx] > '9') && str[idx] != 'x' && str[idx] != 'X'; } @@ -190,6 +195,21 @@ public: return str[idx + 1] == 't'; } + /* Return true if memory pointer to by argument is copied to a memory + pointed to by a different argument (as in memcpy). + In this case set ARG. */ + bool + arg_copied_to_arg_p (unsigned int i, unsigned int *arg) + { + unsigned int idx = arg_idx (i); + gcc_checking_assert (arg_specified_p (i)); + if (str[idx] < '1' || str[idx] > '9') + return false; + *arg = str[idx] - '1'; + return true; + } + + /* True if the argument does not escape. */ bool arg_noescape_p (unsigned int i) @@ -230,7 +250,7 @@ public: return str[1] != 'c' && str[1] != 'C'; } - /* Return true if all memory written by the function + /* Return true if all memory written by the function is specified by fnspec. */ bool global_memory_written_p () diff --git a/gcc/builtins.c b/gcc/builtins.c index da25343..4ec1766 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -12939,16 +12939,16 @@ builtin_fnspec (tree callee) argument. */ case BUILT_IN_STRCAT: case BUILT_IN_STRCAT_CHK: - return "1cW R "; + return "1cW 1 "; case BUILT_IN_STRNCAT: case BUILT_IN_STRNCAT_CHK: - return "1cW R3"; + return "1cW 13"; case BUILT_IN_STRCPY: case BUILT_IN_STRCPY_CHK: - return "1cO R "; + return "1cO 1 "; case BUILT_IN_STPCPY: case BUILT_IN_STPCPY_CHK: - return ".cO R "; + return ".cO 1 "; case BUILT_IN_STRNCPY: case BUILT_IN_MEMCPY: case BUILT_IN_MEMMOVE: @@ -12957,15 +12957,15 @@ builtin_fnspec (tree callee) case BUILT_IN_STRNCPY_CHK: case BUILT_IN_MEMCPY_CHK: case BUILT_IN_MEMMOVE_CHK: - return "1cO3R3"; + return "1cO313"; case BUILT_IN_MEMPCPY: case BUILT_IN_MEMPCPY_CHK: - return ".cO3R3"; + return ".cO313"; case BUILT_IN_STPNCPY: case BUILT_IN_STPNCPY_CHK: - return ".cO3R3"; + return ".cO313"; case BUILT_IN_BCOPY: - return ".cR3O3"; + return ".c23O3"; case BUILT_IN_BZERO: return ".cO2"; case BUILT_IN_MEMCMP: diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index e64011d..b1e8e5b 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -3797,6 +3797,8 @@ attr_fnspec::verify () default: err = true; } + if (err) + internal_error ("invalid fn spec attribute \"%s\"", str); /* Now check all parameters. */ for (unsigned int i = 0; arg_specified_p (i); i++) @@ -3813,21 +3815,28 @@ attr_fnspec::verify () case 'w': case 'W': case '.': + if ((str[idx + 1] >= '1' && str[idx + 1] <= '9') + || str[idx + 1] == 't') + { + if (str[idx] != 'r' && str[idx] != 'R' + && str[idx] != 'w' && str[idx] != 'W' + && str[idx] != 'o' && str[idx] != 'O') + err = true; + if (str[idx] != 't' + /* Size specified is scalar, so it should be described + by ". " if specified at all. */ + && (arg_specified_p (str[idx + 1] - '1') + && str[arg_idx (str[idx + 1] - '1')] != '.')) + err = true; + } + else if (str[idx + 1] != ' ') + err = true; break; default: - err = true; + if (str[idx] < '1' || str[idx] > '9') + err = true; } - if ((str[idx + 1] >= '1' && str[idx + 1] <= '9') - || str[idx + 1] == 't') - { - if (str[idx] != 'r' && str[idx] != 'R' - && str[idx] != 'w' && str[idx] != 'W' - && str[idx] != 'o' && str[idx] != 'O') - err = true; - } - else if (str[idx + 1] != ' ') - err = true; + if (err) + internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i); } - if (err) - internal_error ("invalid fn spec attribute \"%s\"", str); } -- cgit v1.1 From cb808c583de59ea568fd240144cd9db07272f45e Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Thu, 12 Nov 2020 08:59:35 -0500 Subject: Specify reason of -Winvalid-pch warning gcc/c-family PR pch/86674 * c-pch.c (c_common_valid_pch): Use cpp_warning with CPP_W_INVALID_PCH reason to fix -Werror=invalid-pch and -Wno-error=invalid-pch switches. libcpp PR pch/86674 * files.c (_cpp_find_file): Use CPP_DL_NOTE not CPP_DL_ERROR in call to cpp_error. --- gcc/c-family/c-pch.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c index a2292f4..9c0bd0b 100644 --- a/gcc/c-family/c-pch.c +++ b/gcc/c-family/c-pch.c @@ -211,8 +211,7 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) fatal_error (input_location, "cannot read %s: %m", name); else if (sizeread != IDENT_LENGTH + 16) { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, "%s: too short to be a PCH file", + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: too short to be a PCH file", name); return 2; } @@ -220,27 +219,22 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) pch_ident = get_ident(); if (memcmp (ident, pch_ident, IDENT_LENGTH) != 0) { - if (cpp_get_options (pfile)->warn_invalid_pch) - { - if (memcmp (ident, pch_ident, 5) == 0) - /* It's a PCH, for the right language, but has the wrong version. - */ - cpp_error (pfile, CPP_DL_WARNING, + if (memcmp (ident, pch_ident, 5) == 0) + /* It's a PCH, for the right language, but has the wrong version. */ + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: not compatible with this GCC version", name); - else if (memcmp (ident, pch_ident, 4) == 0) - /* It's a PCH for the wrong language. */ - cpp_error (pfile, CPP_DL_WARNING, "%s: not for %s", name, + else if (memcmp (ident, pch_ident, 4) == 0) + /* It's a PCH for the wrong language. */ + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: not for %s", name, lang_hooks.name); - else - /* Not any kind of PCH. */ - cpp_error (pfile, CPP_DL_WARNING, "%s: not a PCH file", name); - } + else + /* Not any kind of PCH. */ + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: not a PCH file", name); return 2; } if (memcmp (ident + IDENT_LENGTH, executable_checksum, 16) != 0) { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: created by a different GCC executable", name); return 2; } @@ -257,8 +251,7 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) if (v.debug_info_type != write_symbols && write_symbols != NO_DEBUG) { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: created with -g%s, but used with -g%s", name, debug_type_names[v.debug_info_type], debug_type_names[write_symbols]); @@ -271,8 +264,7 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) for (i = 0; i < MATCH_SIZE; i++) if (*pch_matching[i].flag_var != v.match[i]) { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: settings for %s do not match", name, pch_matching[i].flag_name); return 2; @@ -287,8 +279,7 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) check one function. */ if (v.pch_init != &pch_init) { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: had text segment at different address", name); return 2; } @@ -305,8 +296,7 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) free (this_file_data); if (msg != NULL) { - if (cpp_get_options (pfile)->warn_invalid_pch) - cpp_error (pfile, CPP_DL_WARNING, "%s: %s", name, msg); + cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: %s", name, msg); return 2; } } -- cgit v1.1 From 896db49a442a15a1fa1f641cd0385da1ba1794e3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 12 Nov 2020 15:05:03 +0100 Subject: More PRE compile-time optimizations This fixes a bug in bitmap_list_view which could end up with a NULL head->current which makes followup searches fail. Oops. It also further optimizes the PRE DFS walk by removing useless stuff and special-casing bitmaps with just one element for EXECUTE_IF_AND_IN_BITMAP which makes a quite big difference. 2020-11-12 Richard Biener * bitmap.c (bitmap_list_view): Restore head->current. * tree-ssa-pre.c (pre_expr_DFS): Elide expr_visited bitmap. Special-case value expression bitmaps with one element. (bitmap_find_leader): Likewise. (sorted_array_from_bitmap_set): Elide expr_visited bitmap. --- gcc/bitmap.c | 5 +++++ gcc/tree-ssa-pre.c | 40 +++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 17 deletions(-) (limited to 'gcc') diff --git a/gcc/bitmap.c b/gcc/bitmap.c index 810b80b..c849b0d 100644 --- a/gcc/bitmap.c +++ b/gcc/bitmap.c @@ -678,6 +678,11 @@ bitmap_list_view (bitmap head) } head->tree_form = false; + if (!head->current) + { + head->current = head->first; + head->indx = head->current ? head->current->indx : 0; + } } /* Convert bitmap HEAD from linked-list view to splay-tree view. diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 9db1b02..e25cec7 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -806,15 +806,15 @@ bitmap_set_free (bitmap_set_t set) } static void -pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap expr_visited, - bitmap val_visited, vec &post); +pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap val_visited, + vec &post); /* DFS walk leaders of VAL to their operands with leaders in SET, collecting expressions in SET in postorder into POST. */ static void -pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap expr_visited, - bitmap val_visited, vec &post) +pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap val_visited, + vec &post) { unsigned int i; bitmap_iterator bi; @@ -822,21 +822,25 @@ pre_expr_DFS (unsigned val, bitmap_set_t set, bitmap expr_visited, /* Iterate over all leaders and DFS recurse. Borrowed from bitmap_find_leader. */ bitmap exprset = value_expressions[val]; + if (!exprset->first->next) + { + EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi) + if (bitmap_bit_p (&set->expressions, i)) + pre_expr_DFS (expression_for_id (i), set, val_visited, post); + return; + } + EXECUTE_IF_AND_IN_BITMAP (exprset, &set->expressions, 0, i, bi) - pre_expr_DFS (expression_for_id (i), - set, expr_visited, val_visited, post); + pre_expr_DFS (expression_for_id (i), set, val_visited, post); } /* DFS walk EXPR to its operands with leaders in SET, collecting expressions in SET in postorder into POST. */ static void -pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap expr_visited, - bitmap val_visited, vec &post) +pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap val_visited, + vec &post) { - if (!bitmap_set_bit (expr_visited, get_expression_id (expr))) - return; - switch (expr->kind) { case NARY: @@ -851,7 +855,7 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap expr_visited, recursed already. Avoid the costly bitmap_find_leader. */ if (bitmap_bit_p (&set->values, op_val_id) && bitmap_set_bit (val_visited, op_val_id)) - pre_expr_DFS (op_val_id, set, expr_visited, val_visited, post); + pre_expr_DFS (op_val_id, set, val_visited, post); } break; } @@ -873,8 +877,7 @@ pre_expr_DFS (pre_expr expr, bitmap_set_t set, bitmap expr_visited, unsigned op_val_id = VN_INFO (op[n])->value_id; if (bitmap_bit_p (&set->values, op_val_id) && bitmap_set_bit (val_visited, op_val_id)) - pre_expr_DFS (op_val_id, - set, expr_visited, val_visited, post); + pre_expr_DFS (op_val_id, set, val_visited, post); } } break; @@ -896,13 +899,11 @@ sorted_array_from_bitmap_set (bitmap_set_t set) /* Pre-allocate enough space for the array. */ result.create (bitmap_count_bits (&set->expressions)); - auto_bitmap expr_visited (&grand_bitmap_obstack); auto_bitmap val_visited (&grand_bitmap_obstack); - bitmap_tree_view (expr_visited); bitmap_tree_view (val_visited); FOR_EACH_VALUE_ID_IN_SET (set, i, bi) if (bitmap_set_bit (val_visited, i)) - pre_expr_DFS (i, set, expr_visited, val_visited, result); + pre_expr_DFS (i, set, val_visited, result); return result; } @@ -1883,6 +1884,11 @@ bitmap_find_leader (bitmap_set_t set, unsigned int val) bitmap_iterator bi; bitmap exprset = value_expressions[val]; + if (!exprset->first->next) + EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi) + if (bitmap_bit_p (&set->expressions, i)) + return expression_for_id (i); + EXECUTE_IF_AND_IN_BITMAP (exprset, &set->expressions, 0, i, bi) return expression_for_id (i); } -- cgit v1.1 From f8f575d7593b7a859326d6db477d93946fdbbbfc Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 12 Nov 2020 17:15:19 +0100 Subject: Compare field offsets in operand_equal_p and OEP_ADDRESS_OF * fold-const.c (operand_compare::operand_equal_p): Compare field offsets in operand_equal_p and OEP_ADDRESS_OF. (operand_compare::hash_operand): Update. --- gcc/fold-const.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/fold-const.c b/gcc/fold-const.c index c47557d..ddf18f2 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -3312,10 +3312,32 @@ operand_compare::operand_equal_p (const_tree arg0, const_tree arg1, case COMPONENT_REF: /* Handle operand 2 the same as for ARRAY_REF. Operand 0 may be NULL when we're called to compare MEM_EXPRs. */ - if (!OP_SAME_WITH_NULL (0) - || !OP_SAME (1)) + if (!OP_SAME_WITH_NULL (0)) return false; + /* Most of time we only need to compare FIELD_DECLs for equality. + However when determining address look into actual offsets. + These may match for unions and unshared record types. */ flags &= ~OEP_ADDRESS_OF; + if (!OP_SAME (1)) + { + if (flags & OEP_ADDRESS_OF) + { + if (TREE_OPERAND (arg0, 2) + || TREE_OPERAND (arg1, 2)) + return OP_SAME_WITH_NULL (2); + tree field0 = TREE_OPERAND (arg0, 1); + tree field1 = TREE_OPERAND (arg1, 1); + + if (!operand_equal_p (DECL_FIELD_OFFSET (field0), + DECL_FIELD_OFFSET (field1), flags) + || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0), + DECL_FIELD_BIT_OFFSET (field1), + flags)) + return false; + } + else + return false; + } return OP_SAME_WITH_NULL (2); case BIT_FIELD_REF: @@ -3787,9 +3809,26 @@ operand_compare::hash_operand (const_tree t, inchash::hash &hstate, sflags = flags; break; + case COMPONENT_REF: + if (sflags & OEP_ADDRESS_OF) + { + hash_operand (TREE_OPERAND (t, 0), hstate, flags); + if (TREE_OPERAND (t, 2)) + hash_operand (TREE_OPERAND (t, 2), hstate, + flags & ~OEP_ADDRESS_OF); + else + { + tree field = TREE_OPERAND (t, 1); + hash_operand (DECL_FIELD_OFFSET (field), + hstate, flags & ~OEP_ADDRESS_OF); + hash_operand (DECL_FIELD_BIT_OFFSET (field), + hstate, flags & ~OEP_ADDRESS_OF); + } + return; + } + break; case ARRAY_REF: case ARRAY_RANGE_REF: - case COMPONENT_REF: case BIT_FIELD_REF: sflags &= ~OEP_ADDRESS_OF; break; -- cgit v1.1 From 876b45db81a708616d70b1ab66b71bd503809c21 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 11 Nov 2020 20:18:06 -0500 Subject: system: Add WARN_UNUSED_RESULT I'd like to have the option of marking functions with __attribute__ ((__warn_unused_result__)), so this patch adds a macro. And use it for maybe_wrap_with_location, it's always a bug if the return value is not used, which happened to me and got me confused. gcc/ChangeLog: * system.h (WARN_UNUSED_RESULT): Define for GCC >= 3.4. * tree.h (maybe_wrap_with_location): Add WARN_UNUSED_RESULT. --- gcc/system.h | 6 ++++++ gcc/tree.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/system.h b/gcc/system.h index b0f3f1d..6f6ab61 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -789,6 +789,12 @@ extern void fancy_abort (const char *, int, const char *) #define ALWAYS_INLINE inline #endif +#if GCC_VERSION >= 3004 +#define WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#else +#define WARN_UNUSED_RESULT +#endif + /* Use gcc_unreachable() to mark unreachable locations (like an unreachable default case of a switch. Do not use gcc_assert(0). */ #if (GCC_VERSION >= 4005) && !ENABLE_ASSERT_CHECKING diff --git a/gcc/tree.h b/gcc/tree.h index 684be10..9a713cd 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1214,7 +1214,7 @@ get_expr_source_range (tree expr) extern void protected_set_expr_location (tree, location_t); extern void protected_set_expr_location_if_unset (tree, location_t); -extern tree maybe_wrap_with_location (tree, location_t); +WARN_UNUSED_RESULT extern tree maybe_wrap_with_location (tree, location_t); extern int suppress_location_wrappers; -- cgit v1.1 From b86aedb0cc083efe712e530a723f1237051a6b56 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Thu, 12 Nov 2020 19:56:07 +0100 Subject: ipa-cp: Work with time benefits and frequencies in sreals This patch converts the variables that hold time benefits and frequencies in IPA-CP from plain integers to sreals, avoiding the need to cap them to avoid overflows and also fixing a potential underflows. Size costs corresponding to individual constants are left as ints so that they do not take up too much space. Care must be taken that adding it up does not overflow, especially in the case of prop_size_cost, because in cases of extremely long chains of lattice dependencies it can overflow (e.g. in testsuite/gcc.dg/ipa/pr50744.c). The overall size is already tracked in long ints. gcc/ChangeLog: 2020-11-11 Martin Jambor * ipa-cp.c (class ipcp_value_base): Change the type of local_time_benefit and prop_time_benefit to sreal. Adjust the constructor initializer. (ipcp_lattice::print): Dump sreals. (struct caller_statistics): Change the type of freq_sum to sreal. (gather_caller_stats): Work with sreal freq_sum. (incorporate_penalties): Work with sreal evaluation. (good_cloning_opportunity_p): Adjusted for sreal sreal time_benefit and freq_sum. Bail out if size_cost is INT_MAX. (perform_estimation_of_a_value): Work with sreal time_benefit. Avoid unnecessary capping. (estimate_local_effects): Pass sreal time benefit to good_cloning_opportunity_p without capping it. Adjust dumping. (safe_add): If there can be overflow, return INT_MAX. (propagate_effects): Work with sreal times. (get_info_about_necessary_edges): Work with sreal frequencies. (decide_about_value): Likewise and with sreal time benefits. --- gcc/ipa-cp.c | 151 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 82 insertions(+), 69 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 465b072..f29f216 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -156,16 +156,22 @@ public: class ipcp_value_base { public: - /* Time benefit and size cost that specializing the function for this value - would bring about in this function alone. */ - int local_time_benefit, local_size_cost; - /* Time benefit and size cost that specializing the function for this value - can bring about in it's callees (transitively). */ - int prop_time_benefit, prop_size_cost; + /* Time benefit and that specializing the function for this value would bring + about in this function alone. */ + sreal local_time_benefit; + /* Time benefit that specializing the function for this value can bring about + in it's callees. */ + sreal prop_time_benefit; + /* Size cost that specializing the function for this value would bring about + in this function alone. */ + int local_size_cost; + /* Size cost that specializing the function for this value can bring about in + it's callees. */ + int prop_size_cost; ipcp_value_base () - : local_time_benefit (0), local_size_cost (0), - prop_time_benefit (0), prop_size_cost (0) {} + : local_time_benefit (0), prop_time_benefit (0), + local_size_cost (0), prop_size_cost (0) {} }; /* Describes one particular value stored in struct ipcp_lattice. */ @@ -499,10 +505,10 @@ ipcp_lattice::print (FILE * f, bool dump_sources, bool dump_benefits) } if (dump_benefits) - fprintf (f, " [loc_time: %i, loc_size: %i, " - "prop_time: %i, prop_size: %i]\n", - val->local_time_benefit, val->local_size_cost, - val->prop_time_benefit, val->prop_size_cost); + fprintf (f, " [loc_time: %g, loc_size: %i, " + "prop_time: %g, prop_size: %i]\n", + val->local_time_benefit.to_double (), val->local_size_cost, + val->prop_time_benefit.to_double (), val->prop_size_cost); } if (!dump_benefits) fprintf (f, "\n"); @@ -668,7 +674,8 @@ ipcp_versionable_function_p (struct cgraph_node *node) struct caller_statistics { profile_count count_sum; - int n_calls, n_hot_calls, freq_sum; + sreal freq_sum; + int n_calls, n_hot_calls; }; /* Initialize fields of STAT to zeroes. */ @@ -696,7 +703,7 @@ gather_caller_stats (struct cgraph_node *node, void *data) { if (cs->count.ipa ().initialized_p ()) stats->count_sum += cs->count.ipa (); - stats->freq_sum += cs->frequency (); + stats->freq_sum += cs->sreal_frequency (); stats->n_calls++; if (cs->maybe_hot_p ()) stats->n_hot_calls ++; @@ -3224,9 +3231,9 @@ hint_time_bonus (cgraph_node *node, const ipa_call_estimates &estimates) /* If there is a reason to penalize the function described by INFO in the cloning goodness evaluation, do so. */ -static inline int64_t +static inline sreal incorporate_penalties (cgraph_node *node, ipa_node_params *info, - int64_t evaluation) + sreal evaluation) { if (info->node_within_scc && !info->node_is_self_scc) evaluation = (evaluation @@ -3247,8 +3254,9 @@ incorporate_penalties (cgraph_node *node, ipa_node_params *info, potential new clone in FREQUENCIES. */ static bool -good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit, - int freq_sum, profile_count count_sum, int size_cost) +good_cloning_opportunity_p (struct cgraph_node *node, sreal time_benefit, + sreal freq_sum, profile_count count_sum, + int size_cost) { if (time_benefit == 0 || !opt_for_fn (node->decl, flag_ipa_cp_clone) @@ -3256,50 +3264,56 @@ good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit, return false; gcc_assert (size_cost > 0); + if (size_cost == INT_MAX) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " good_cloning_opportunity_p returning " + "false because of size overflow.\n"); + return false; + } class ipa_node_params *info = IPA_NODE_REF (node); int eval_threshold = opt_for_fn (node->decl, param_ipa_cp_eval_threshold); if (max_count > profile_count::zero ()) { - int factor = RDIV (count_sum.probability_in - (max_count).to_reg_br_prob_base () - * 1000, REG_BR_PROB_BASE); - int64_t evaluation = (((int64_t) time_benefit * factor) - / size_cost); + + sreal factor = count_sum.probability_in (max_count).to_sreal (); + sreal evaluation = (time_benefit * factor) / size_cost; evaluation = incorporate_penalties (node, info, evaluation); + evaluation *= 1000; if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, " good_cloning_opportunity_p (time: %i, " - "size: %i, count_sum: ", time_benefit, size_cost); + fprintf (dump_file, " good_cloning_opportunity_p (time: %g, " + "size: %i, count_sum: ", time_benefit.to_double (), + size_cost); count_sum.dump (dump_file); - fprintf (dump_file, "%s%s) -> evaluation: " "%" PRId64 - ", threshold: %i\n", + fprintf (dump_file, "%s%s) -> evaluation: %.2f, threshold: %i\n", info->node_within_scc ? (info->node_is_self_scc ? ", self_scc" : ", scc") : "", info->node_calling_single_call ? ", single_call" : "", - evaluation, eval_threshold); + evaluation.to_double (), eval_threshold); } - return evaluation >= eval_threshold; + return evaluation.to_int () >= eval_threshold; } else { - int64_t evaluation = (((int64_t) time_benefit * freq_sum) - / size_cost); + sreal evaluation = (time_benefit * freq_sum) / size_cost; evaluation = incorporate_penalties (node, info, evaluation); + evaluation *= 1000; if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " good_cloning_opportunity_p (time: %i, " - "size: %i, freq_sum: %i%s%s) -> evaluation: " - "%" PRId64 ", threshold: %i\n", - time_benefit, size_cost, freq_sum, + fprintf (dump_file, " good_cloning_opportunity_p (time: %g, " + "size: %i, freq_sum: %g%s%s) -> evaluation: %.2f, " + "threshold: %i\n", + time_benefit.to_double (), size_cost, freq_sum.to_double (), info->node_within_scc ? (info->node_is_self_scc ? ", self_scc" : ", scc") : "", info->node_calling_single_call ? ", single_call" : "", - evaluation, eval_threshold); + evaluation.to_double (), eval_threshold); - return evaluation >= eval_threshold; + return evaluation.to_int () >= eval_threshold; } } @@ -3411,13 +3425,10 @@ perform_estimation_of_a_value (cgraph_node *node, int removable_params_cost, int est_move_cost, ipcp_value_base *val) { - int time_benefit; + sreal time_benefit; ipa_call_estimates estimates; estimate_ipcp_clone_size_and_time (node, avals, &estimates); - sreal time_delta = estimates.nonspecialized_time - estimates.time; - if (time_delta > 65535) - time_delta = 65535; /* Extern inline functions have no cloning local time benefits because they will be inlined anyway. The only reason to clone them is if it enables @@ -3425,10 +3436,10 @@ perform_estimation_of_a_value (cgraph_node *node, if (DECL_EXTERNAL (node->decl) && DECL_DECLARED_INLINE_P (node->decl)) time_benefit = 0; else - time_benefit = time_delta.to_int () - + devirtualization_time_bonus (node, avals) - + hint_time_bonus (node, estimates) - + removable_params_cost + est_move_cost; + time_benefit = (estimates.nonspecialized_time - estimates.time) + + (devirtualization_time_bonus (node, avals) + + hint_time_bonus (node, estimates) + + removable_params_cost + est_move_cost); int size = estimates.size; gcc_checking_assert (size >=0); @@ -3509,10 +3520,8 @@ estimate_local_effects (struct cgraph_node *node) fprintf (dump_file, " Decided to specialize for all " "known contexts, code not going to grow.\n"); } - else if (good_cloning_opportunity_p (node, - MIN ((time).to_int (), 65536), - stats.freq_sum, stats.count_sum, - size)) + else if (good_cloning_opportunity_p (node, time, stats.freq_sum, + stats.count_sum, size)) { if (size + overall_size <= get_max_overall_size (node)) { @@ -3561,8 +3570,9 @@ estimate_local_effects (struct cgraph_node *node) print_ipcp_constant_value (dump_file, val->value); fprintf (dump_file, " for "); ipa_dump_param (dump_file, info, i); - fprintf (dump_file, ": time_benefit: %i, size: %i\n", - val->local_time_benefit, val->local_size_cost); + fprintf (dump_file, ": time_benefit: %g, size: %i\n", + val->local_time_benefit.to_double (), + val->local_size_cost); } } avals.m_known_vals[i] = NULL_TREE; @@ -3595,8 +3605,9 @@ estimate_local_effects (struct cgraph_node *node) print_ipcp_constant_value (dump_file, val->value); fprintf (dump_file, " for "); ipa_dump_param (dump_file, info, i); - fprintf (dump_file, ": time_benefit: %i, size: %i\n", - val->local_time_benefit, val->local_size_cost); + fprintf (dump_file, ": time_benefit: %g, size: %i\n", + val->local_time_benefit.to_double (), + val->local_size_cost); } } avals.m_known_contexts[i] = ipa_polymorphic_call_context (); @@ -3637,10 +3648,11 @@ estimate_local_effects (struct cgraph_node *node) fprintf (dump_file, " for "); ipa_dump_param (dump_file, info, i); fprintf (dump_file, "[%soffset: " HOST_WIDE_INT_PRINT_DEC - "]: time_benefit: %i, size: %i\n", + "]: time_benefit: %g, size: %i\n", plats->aggs_by_ref ? "ref " : "", aglat->offset, - val->local_time_benefit, val->local_size_cost); + val->local_time_benefit.to_double (), + val->local_size_cost); } agg->items.pop (); @@ -3830,13 +3842,13 @@ propagate_constants_topo (class ipa_topo_info *topo) /* Return the sum of A and B if none of them is bigger than INT_MAX/2, return - the bigger one if otherwise. */ + INT_MAX. */ static int safe_add (int a, int b) { if (a > INT_MAX/2 || b > INT_MAX/2) - return a > b ? a : b; + return INT_MAX; else return a + b; } @@ -3855,12 +3867,12 @@ value_topo_info::propagate_effects () { ipcp_value_source *src; ipcp_value *val; - int time = 0, size = 0; + sreal time = 0; + int size = 0; for (val = base; val; val = val->scc_next) { - time = safe_add (time, - val->local_time_benefit + val->prop_time_benefit); + time = time + val->local_time_benefit + val->prop_time_benefit; size = safe_add (size, val->local_size_cost + val->prop_size_cost); } @@ -3869,8 +3881,7 @@ value_topo_info::propagate_effects () if (src->val && src->cs->maybe_hot_p ()) { - src->val->prop_time_benefit = safe_add (time, - src->val->prop_time_benefit); + src->val->prop_time_benefit = time + src->val->prop_time_benefit; src->val->prop_size_cost = safe_add (size, src->val->prop_size_cost); } @@ -4162,11 +4173,12 @@ get_next_cgraph_edge_clone (struct cgraph_edge *cs) template static bool get_info_about_necessary_edges (ipcp_value *val, cgraph_node *dest, - int *freq_sum, - profile_count *count_sum, int *caller_count) + sreal *freq_sum, profile_count *count_sum, + int *caller_count) { ipcp_value_source *src; - int freq = 0, count = 0; + sreal freq = 0; + int count = 0; profile_count cnt = profile_count::zero (); bool hot = false; bool non_self_recursive = false; @@ -4179,7 +4191,7 @@ get_info_about_necessary_edges (ipcp_value *val, cgraph_node *dest, if (cgraph_edge_brings_value_p (cs, src, dest, val)) { count++; - freq += cs->frequency (); + freq += cs->sreal_frequency (); if (cs->count.ipa ().initialized_p ()) cnt += cs->count.ipa (); hot |= cs->maybe_hot_p (); @@ -5448,7 +5460,8 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, ipcp_value *val, ipa_auto_call_arg_values *avals) { struct ipa_agg_replacement_value *aggvals; - int freq_sum, caller_count; + int caller_count; + sreal freq_sum; profile_count count_sum; vec callers; @@ -5487,8 +5500,8 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, freq_sum, count_sum, val->local_size_cost) && !good_cloning_opportunity_p (node, - safe_add (val->local_time_benefit, - val->prop_time_benefit), + val->local_time_benefit + + val->prop_time_benefit, freq_sum, count_sum, safe_add (val->local_size_cost, val->prop_size_cost))) -- cgit v1.1 From 25a0d08b7f979ab3c6e970e1eb966c1b5ddbe9ac Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Thu, 12 Nov 2020 19:56:07 +0100 Subject: cgraph: Avoid segfault when attempting to dump NULL clone_info cgraph_node::materialize_clone segfaulted when I tried compiling Tramp3D with -fdump-ipa-all because there was no clone_info - IPA-CP created a clone only for an aggregate constant, adding a note to its transformation summary but not creating any tree_map nor param_adjustements. Fixed with the following obvious extra checks which has passed bootstrap and testing on x86_64-linux. gcc/ChangeLog: 2020-11-12 Martin Jambor * cgraphclones.c (cgraph_node::materialize_clone): Check that clone info is not NULL before attempting to dump it. --- gcc/cgraphclones.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index 2e69689..2bf9baf 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -1107,7 +1107,7 @@ cgraph_node::materialize_clone () fprintf (symtab->dump_file, "cloning %s to %s\n", clone_of->dump_name (), dump_name ()); - if (info->tree_map) + if (info && info->tree_map) { fprintf (symtab->dump_file, " replace map:"); for (unsigned int i = 0; @@ -1123,7 +1123,7 @@ cgraph_node::materialize_clone () } fprintf (symtab->dump_file, "\n"); } - if (info->param_adjustments) + if (info && info->param_adjustments) info->param_adjustments->dump (symtab->dump_file); } clear_stmts_in_references (); -- cgit v1.1 From 6fcc3cac42998081dbbb1d3389bd42833ad9fdf4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Nov 2020 21:38:04 +0100 Subject: openmp: Implement allocate clause in omp lowering. For now, task/taskloop constructs aren't handled and C/C++ array reductions and reductions with task or inscan modifiers need further work. Instead of calling omp_alloc/omp_free (where the former doesn't have alignment argument and omp_aligned_alloc is 5.1 only feature), this calls GOMP_alloc/GOMP_free, so that the library can fail if it would fall back into NULL (exception is zero length allocations). 2020-11-12 Jakub Jelinek gcc/ * builtin-types.def (BT_FN_PTR_SIZE_SIZE_PTRMODE): New function type. * omp-builtins.def (BUILT_IN_GOACC_DECLARE): Move earlier. (BUILT_IN_GOMP_ALLOC, BUILT_IN_GOMP_FREE): New builtins. * gimplify.c (gimplify_scan_omp_clauses): Force allocator into a decl if it is not NULL, INTEGER_CST or decl. (gimplify_adjust_omp_clauses): Clear GOVD_EXPLICIT on explicit clauses which are being removed. Remove allocate clauses for variables not seen if they are private, firstprivate or linear too. Call omp_notice_variable on the allocator otherwise. (gimplify_omp_for): Handle iterator vars mentioned in allocate clauses similarly to non-is_gimple_reg iterators. * omp-low.c (struct omp_context): Add allocate_map field. (delete_omp_context): Delete it. (scan_sharing_clauses): Fill it from allocate clauses. Remove it if mentioned also in shared clause. (lower_private_allocate): New function. (lower_rec_input_clauses): Handle allocate clause for privatized variables, except for task/taskloop, C/C++ array reductions for now and task/inscan variables. (lower_send_shared_vars): Don't consider variables in allocate_map as shared. * omp-expand.c (expand_omp_for_generic, expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Use expand_omp_build_assign instead of gimple_build_assign + gsi_insert_after. * builtins.c (builtin_fnspec): Handle BUILTIN_GOMP_ALLOC and BUILTIN_GOMP_FREE. * tree-ssa-ccp.c (evaluate_stmt): Handle BUILTIN_GOMP_ALLOC. * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Handle BUILTIN_GOMP_ALLOC. (mark_all_reaching_defs_necessary_1): Handle BUILTIN_GOMP_ALLOC and BUILTIN_GOMP_FREE. (propagate_necessity): Likewise. gcc/fortran/ * f95-lang.c (ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST): Define. (gfc_init_builtin_functions): Add alloc_size and warn_unused_result attributes to __builtin_GOMP_alloc. * types.def (BT_PTRMODE): New primitive type. (BT_FN_VOID_PTR_PTRMODE, BT_FN_PTR_SIZE_SIZE_PTRMODE): New function types. libgomp/ * libgomp.map (GOMP_alloc, GOMP_free): Export at GOMP_5.0.1. * omp.h.in (omp_alloc): Add malloc and alloc_size attributes. * libgomp_g.h (GOMP_alloc, GOMP_free): Declare. * allocator.c (omp_aligned_alloc): New for now static function, add alignment argument and handle it. (omp_alloc): Reimplement using omp_aligned_alloc. (GOMP_alloc, GOMP_free): New functions. (omp_free): Add ialias. * testsuite/libgomp.c-c++-common/allocate-1.c: New test. * testsuite/libgomp.c++/allocate-1.C: New test. --- gcc/builtin-types.def | 2 + gcc/builtins.c | 2 + gcc/fortran/f95-lang.c | 11 +++- gcc/fortran/types.def | 5 ++ gcc/gimplify.c | 61 ++++++++++++++++++-- gcc/omp-builtins.def | 9 ++- gcc/omp-expand.c | 9 +-- gcc/omp-low.c | 148 ++++++++++++++++++++++++++++++++++++++++++++----- gcc/tree-ssa-ccp.c | 1 + gcc/tree-ssa-dce.c | 41 +++++++------- 10 files changed, 242 insertions(+), 47 deletions(-) (limited to 'gcc') diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index c46b1bc..4a82ee4 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -637,6 +637,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_SIZE_SIZE_PTR, BT_VOID, BT_SIZE, BT_SIZE, DEF_FUNCTION_TYPE_3 (BT_FN_UINT_UINT_PTR_PTR, BT_UINT, BT_UINT, BT_PTR, BT_PTR) DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_CONST_SIZE_BOOL, BT_PTR, BT_PTR, BT_CONST_SIZE, BT_BOOL) +DEF_FUNCTION_TYPE_3 (BT_FN_PTR_SIZE_SIZE_PTRMODE, + BT_PTR, BT_SIZE, BT_SIZE, BT_PTRMODE) DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR) diff --git a/gcc/builtins.c b/gcc/builtins.c index 4ec1766..42c52a1 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -13023,6 +13023,7 @@ builtin_fnspec (tree callee) case BUILT_IN_MALLOC: case BUILT_IN_ALIGNED_ALLOC: case BUILT_IN_CALLOC: + case BUILT_IN_GOMP_ALLOC: return "mC"; CASE_BUILT_IN_ALLOCA: return "mc"; @@ -13044,6 +13045,7 @@ builtin_fnspec (tree callee) across it. */ case BUILT_IN_STACK_RESTORE: case BUILT_IN_FREE: + case BUILT_IN_GOMP_FREE: return ".co "; case BUILT_IN_VA_END: return ".cO "; diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 526b721..1a05144 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -531,7 +531,7 @@ gfc_builtin_function (tree decl) return decl; } -/* So far we need just these 7 attribute types. */ +/* So far we need just these 8 attribute types. */ #define ATTR_NULL 0 #define ATTR_LEAF_LIST (ECF_LEAF) #define ATTR_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF) @@ -540,6 +540,8 @@ gfc_builtin_function (tree decl) #define ATTR_PURE_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF | ECF_PURE) #define ATTR_NOTHROW_LIST (ECF_NOTHROW) #define ATTR_CONST_NOTHROW_LIST (ECF_NOTHROW | ECF_CONST) +#define ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST \ + (ECF_NOTHROW) static void gfc_define_builtin (const char *name, tree type, enum built_in_function code, @@ -1236,6 +1238,13 @@ gfc_init_builtin_functions (void) #undef DEF_GOACC_BUILTIN #undef DEF_GOACC_BUILTIN_COMPILER #undef DEF_GOMP_BUILTIN + tree gomp_alloc = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC); + tree two = build_int_cst (integer_type_node, 2); + DECL_ATTRIBUTES (gomp_alloc) + = tree_cons (get_identifier ("warn_unused_result"), NULL_TREE, + tree_cons (get_identifier ("alloc_size"), + build_tree_list (NULL_TREE, two), + DECL_ATTRIBUTES (gomp_alloc))); } gfc_define_builtin ("__builtin_trap", builtin_types[BT_FN_VOID], diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def index 7b4925c..5736bba 100644 --- a/gcc/fortran/types.def +++ b/gcc/fortran/types.def @@ -70,6 +70,7 @@ DEF_PRIMITIVE_TYPE (BT_CONST_VOLATILE_PTR, build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_VOLATILE|TYPE_QUAL_CONST))) +DEF_PRIMITIVE_TYPE (BT_PTRMODE, (*lang_hooks.types.type_for_mode)(ptr_mode, 0)) DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG) DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG) DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR) @@ -117,6 +118,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE, BT_CONST_VOLATILE_PTR) DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL) DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT) +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTRMODE, + BT_VOID, BT_PTR, BT_PTRMODE) DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR) @@ -149,6 +152,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I16_INT, BT_VOID, BT_VOLATILE_PTR, BT_I16, DEF_FUNCTION_TYPE_3 (BT_FN_VOID_SIZE_SIZE_PTR, BT_VOID, BT_SIZE, BT_SIZE, BT_PTR) DEF_FUNCTION_TYPE_3 (BT_FN_UINT_UINT_PTR_PTR, BT_UINT, BT_UINT, BT_PTR, BT_PTR) +DEF_FUNCTION_TYPE_3 (BT_FN_PTR_SIZE_SIZE_PTRMODE, + BT_PTR, BT_SIZE, BT_SIZE, BT_PTRMODE) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d18c43e..b861e17 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -9904,10 +9904,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, remove = true; break; } + else if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) == NULL_TREE + || (TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) + == INTEGER_CST)) + ; else if (code == OMP_TASKLOOP - && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) - && (TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) - != INTEGER_CST)) + || !DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))) OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = get_initialized_tmp_var (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), pre_p, NULL, false); @@ -10475,6 +10477,8 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, && omp_shared_to_firstprivate_optimizable_decl_p (decl)) omp_mark_stores (gimplify_omp_ctxp->outer_context, decl); } + else + n->value &= ~GOVD_EXPLICIT; break; case OMP_CLAUSE_LASTPRIVATE: @@ -10774,6 +10778,41 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, && omp_shared_to_firstprivate_optimizable_decl_p (decl)) omp_mark_stores (gimplify_omp_ctxp->outer_context, decl); break; + + case OMP_CLAUSE_ALLOCATE: + decl = OMP_CLAUSE_DECL (c); + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (n != NULL && !(n->value & GOVD_SEEN)) + { + if ((n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LINEAR)) + != 0 + && (n->value & (GOVD_REDUCTION | GOVD_LASTPRIVATE)) == 0) + remove = true; + } + if (!remove + && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) + && TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) != INTEGER_CST + && ((ctx->region_type & (ORT_PARALLEL | ORT_TARGET)) != 0 + || (ctx->region_type & ORT_TASKLOOP) == ORT_TASK + || (ctx->region_type & ORT_HOST_TEAMS) == ORT_HOST_TEAMS)) + { + tree allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); + n = splay_tree_lookup (ctx->variables, (splay_tree_key) allocator); + if (n == NULL) + { + enum omp_clause_default_kind default_kind + = ctx->default_kind; + ctx->default_kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; + omp_notice_variable (ctx, OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), + true); + ctx->default_kind = default_kind; + } + else + omp_notice_variable (ctx, OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), + true); + } + break; + case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_IF: @@ -10823,7 +10862,6 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, case OMP_CLAUSE_FINALIZE: case OMP_CLAUSE_INCLUSIVE: case OMP_CLAUSE_EXCLUSIVE: - case OMP_CLAUSE_ALLOCATE: break; default: @@ -11623,6 +11661,15 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_TILE); if (c) tile = list_length (OMP_CLAUSE_TILE_LIST (c)); + c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ALLOCATE); + hash_set *allocate_uids = NULL; + if (c) + { + allocate_uids = new hash_set; + for (; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE) + allocate_uids->add (OMP_CLAUSE_DECL (c)); + } for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); @@ -11949,12 +11996,13 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) as an iteration counter. This is valid, since DECL cannot be modified in the body of the loop. Similarly for any iteration vars in simd with collapse > 1 where the iterator vars must be - lastprivate. */ + lastprivate. And similarly for vars mentioned in allocate clauses. */ if (orig_for_stmt != for_stmt) var = decl; else if (!is_gimple_reg (decl) || (ort == ORT_SIMD - && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)) + && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) + || (allocate_uids && allocate_uids->contains (decl))) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; /* Make sure omp_add_variable is not called on it prematurely. @@ -12181,6 +12229,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } BITMAP_FREE (has_decl_expr); + delete allocate_uids; if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP || (loop_p && orig_for_stmt == for_stmt)) diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index f461d60..f9b78ed 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -47,6 +47,8 @@ DEF_GOACC_BUILTIN (BUILT_IN_GOACC_UPDATE, "GOACC_update", DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait", BT_FN_VOID_INT_INT_VAR, ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare", + BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST) DEF_GOACC_BUILTIN_COMPILER (BUILT_IN_ACC_ON_DEVICE, "acc_on_device", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST) @@ -444,5 +446,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK_REDUCTION_REMAP, DEF_GOMP_BUILTIN (BUILT_IN_GOMP_WORKSHARE_TASK_REDUCTION_UNREGISTER, "GOMP_workshare_task_reduction_unregister", BT_FN_VOID_BOOL, ATTR_NOTHROW_LEAF_LIST) -DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare", - BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ALLOC, + "GOMP_alloc", BT_FN_PTR_SIZE_SIZE_PTRMODE, + ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_FREE, + "GOMP_free", BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST) diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 6583c88..ddca3d3 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -4255,8 +4255,7 @@ expand_omp_for_generic (struct omp_region *region, : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - assign_stmt = gimple_build_assign (dest, t); - gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + expand_omp_build_assign (&gsi, dest, t, true); } if (fd->collapse > 1) expand_omp_for_init_vars (fd, &gsi, counts, NULL, inner_stmt, startvar); @@ -5250,8 +5249,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, : POINTER_PLUS_EXPR, TREE_TYPE (t), t, a); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - assign_stmt = gimple_build_assign (dest, t); - gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + expand_omp_build_assign (&gsi, dest, t, true); } if (fd->collapse > 1) { @@ -5974,8 +5972,7 @@ expand_omp_for_static_chunk (struct omp_region *region, : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - assign_stmt = gimple_build_assign (dest, t); - gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + expand_omp_build_assign (&gsi, dest, t, true); } if (fd->collapse > 1) expand_omp_for_init_vars (fd, &gsi, counts, NULL, inner_stmt, startvar); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 83ca5fc..ed805e2 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -126,6 +126,10 @@ struct omp_context corresponding tracking loop iteration variables. */ hash_map *lastprivate_conditional_map; + /* And a hash map from the allocate variables to their corresponding + allocators. */ + hash_map *allocate_map; + /* A tree_list of the reduction clauses in this context. This is only used for checking the consistency of OpenACC reduction clauses in scan_omp_for and is not guaranteed to contain a valid @@ -1043,6 +1047,7 @@ delete_omp_context (splay_tree_value value) } delete ctx->lastprivate_conditional_map; + delete ctx->allocate_map; XDELETE (ctx); } @@ -1115,6 +1120,22 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) bool scan_array_reductions = false; for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE + && (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) == NULL_TREE + /* omp_default_mem_alloc is 1 */ + || !integer_onep (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)))) + { + if (is_task_ctx (ctx)) + continue; /* For now. */ + if (ctx->allocate_map == NULL) + ctx->allocate_map = new hash_map; + ctx->allocate_map->put (OMP_CLAUSE_DECL (c), + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) + ? OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) + : integer_zero_node); + } + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) { bool by_ref; @@ -1130,6 +1151,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_SHARED: decl = OMP_CLAUSE_DECL (c); + if (ctx->allocate_map && ctx->allocate_map->get (decl)) + ctx->allocate_map->remove (decl); /* Ignore shared directives in teams construct inside of target construct. */ if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS @@ -4358,6 +4381,68 @@ task_reduction_read (gimple_seq *ilist, tree tskred_temp, tree type, return v; } +/* Lower early initialization of privatized variable NEW_VAR + if it needs an allocator (has allocate clause). */ + +static bool +lower_private_allocate (tree var, tree new_var, tree &allocator, + tree &allocate_ptr, gimple_seq *ilist, + omp_context *ctx, bool is_ref, tree size) +{ + if (allocator) + return false; + gcc_assert (allocate_ptr == NULL_TREE); + if (ctx->allocate_map && DECL_P (new_var)) + if (tree *allocatorp = ctx->allocate_map->get (var)) + allocator = *allocatorp; + if (allocator == NULL_TREE) + return false; + if (!is_ref && omp_is_reference (var)) + return false; + + if (TREE_CODE (allocator) != INTEGER_CST) + allocator = build_outer_var_ref (allocator, ctx); + allocator = fold_convert (pointer_sized_int_node, allocator); + if (TREE_CODE (allocator) != INTEGER_CST) + { + tree var = create_tmp_var (TREE_TYPE (allocator)); + gimplify_assign (var, allocator, ilist); + allocator = var; + } + + tree ptr_type, align, sz; + if (is_ref) + { + ptr_type = build_pointer_type (TREE_TYPE (TREE_TYPE (new_var))); + align = build_int_cst (size_type_node, + TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type))); + sz = size; + } + else + { + ptr_type = build_pointer_type (TREE_TYPE (new_var)); + align = build_int_cst (size_type_node, DECL_ALIGN_UNIT (new_var)); + sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var)); + } + if (TREE_CODE (sz) != INTEGER_CST) + { + tree szvar = create_tmp_var (size_type_node); + gimplify_assign (szvar, sz, ilist); + sz = szvar; + } + allocate_ptr = create_tmp_var (ptr_type); + tree a = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC); + gimple *g = gimple_build_call (a, 3, align, sz, allocator); + gimple_call_set_lhs (g, allocate_ptr); + gimple_seq_add_stmt (ilist, g); + if (!is_ref) + { + SET_DECL_VALUE_EXPR (new_var, build_simple_mem_ref (allocate_ptr)); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + return true; +} + /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN, from the receiver (aka child) side and initializers for REFERENCE_TYPE private variables. Initialization statements go in ILIST, while calls @@ -4523,6 +4608,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, bool task_reduction_p = false; bool task_reduction_needs_orig_p = false; tree cond = NULL_TREE; + tree allocator, allocate_ptr; switch (c_kind) { @@ -4659,6 +4745,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (task_reduction_p != (pass >= 2)) continue; + allocator = NULL_TREE; + allocate_ptr = NULL_TREE; new_var = var = OMP_CLAUSE_DECL (c); if ((c_kind == OMP_CLAUSE_REDUCTION || c_kind == OMP_CLAUSE_IN_REDUCTION) @@ -5195,8 +5283,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx)) { - gcall *stmt; - tree tmp, atmp; + tree tmp; ptr = DECL_VALUE_EXPR (new_var); gcc_assert (TREE_CODE (ptr) == INDIRECT_REF); @@ -5204,16 +5291,25 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, gcc_assert (DECL_P (ptr)); x = TYPE_SIZE_UNIT (TREE_TYPE (new_var)); - /* void *tmp = __builtin_alloca */ - atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); - stmt = gimple_build_call (atmp, 2, x, - size_int (DECL_ALIGN (var))); - cfun->calls_alloca = 1; - tmp = create_tmp_var_raw (ptr_type_node); - gimple_add_tmp_var (tmp); - gimple_call_set_lhs (stmt, tmp); - - gimple_seq_add_stmt (ilist, stmt); + if (lower_private_allocate (var, new_var, allocator, + allocate_ptr, ilist, ctx, + false, x)) + tmp = allocate_ptr; + else + { + /* void *tmp = __builtin_alloca */ + tree atmp + = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); + gcall *stmt + = gimple_build_call (atmp, 2, x, + size_int (DECL_ALIGN (var))); + cfun->calls_alloca = 1; + tmp = create_tmp_var_raw (ptr_type_node); + gimple_add_tmp_var (tmp); + gimple_call_set_lhs (stmt, tmp); + + gimple_seq_add_stmt (ilist, stmt); + } x = fold_convert_loc (clause_loc, TREE_TYPE (ptr), tmp); gimplify_assign (ptr, x, ilist); @@ -5237,6 +5333,10 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, x = build_receiver_ref (var, false, ctx); x = build_fold_addr_expr_loc (clause_loc, x); } + else if (lower_private_allocate (var, new_var, allocator, + allocate_ptr, + ilist, ctx, true, x)) + x = allocate_ptr; else if (TREE_CONSTANT (x)) { /* For reduction in SIMD loop, defer adding the @@ -5349,6 +5449,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, tree nx; bool copy_ctor; copy_ctor = false; + lower_private_allocate (var, new_var, allocator, allocate_ptr, + ilist, ctx, false, NULL_TREE); nx = unshare_expr (new_var); if (is_simd && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE @@ -5494,6 +5596,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, x = lang_hooks.decls.omp_clause_dtor (c, new_var); if (x) gimplify_and_add (x, dlist); + if (allocator) + { + tree f = builtin_decl_explicit (BUILT_IN_GOMP_FREE); + gimple *g + = gimple_build_call (f, 2, allocate_ptr, allocator); + gimple_seq_add_stmt (dlist, g); + } break; case OMP_CLAUSE_LINEAR: @@ -5535,6 +5644,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, goto do_dtor; } do_firstprivate: + lower_private_allocate (var, new_var, allocator, allocate_ptr, + ilist, ctx, false, NULL_TREE); x = build_outer_var_ref (var, ctx); if (is_simd) { @@ -5722,6 +5833,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } else { + lower_private_allocate (var, new_var, allocator, + allocate_ptr, ilist, ctx, false, + NULL_TREE); x = build_outer_var_ref (var, ctx); if (omp_is_reference (var) @@ -6118,6 +6232,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } else { + lower_private_allocate (var, new_var, allocator, + allocate_ptr, ilist, ctx, + false, NULL_TREE); if (omp_is_reference (var) && is_simd) handle_simd_reference (clause_loc, new_vard, ilist); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION @@ -6132,6 +6249,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, ref = build_outer_var_ref (var, ctx); gimplify_assign (ref, x, dlist); } + if (allocator) + goto do_dtor; } } break; @@ -7488,7 +7607,10 @@ lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx) continue; nvar = maybe_lookup_decl (ovar, ctx); - if (!nvar || !DECL_HAS_VALUE_EXPR_P (nvar)) + if (!nvar + || !DECL_HAS_VALUE_EXPR_P (nvar) + || (ctx->allocate_map + && ctx->allocate_map->get (ovar))) continue; /* If CTX is a nested parallel directive. Find the immediately diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 23b2902..9a2ff62 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1972,6 +1972,7 @@ evaluate_stmt (gimple *stmt) break; case BUILT_IN_ALIGNED_ALLOC: + case BUILT_IN_GOMP_ALLOC: { tree align = get_constant_value (gimple_call_arg (stmt, 0)); if (align diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index a046612..9fb156c 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -239,6 +239,7 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) CASE_BUILT_IN_ALLOCA: case BUILT_IN_STRDUP: case BUILT_IN_STRNDUP: + case BUILT_IN_GOMP_ALLOC: return; default:; @@ -605,6 +606,8 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED, case BUILT_IN_CALLOC: CASE_BUILT_IN_ALLOCA: case BUILT_IN_FREE: + case BUILT_IN_GOMP_ALLOC: + case BUILT_IN_GOMP_FREE: return false; default:; @@ -879,7 +882,8 @@ propagate_necessity (bool aggressive) && gimple_call_from_new_or_delete (as_a (stmt)) && gimple_call_operator_delete_p (as_a (stmt))); if (is_delete_operator - || gimple_call_builtin_p (stmt, BUILT_IN_FREE)) + || gimple_call_builtin_p (stmt, BUILT_IN_FREE) + || gimple_call_builtin_p (stmt, BUILT_IN_GOMP_FREE)) { tree ptr = gimple_call_arg (stmt, 0); gcall *def_stmt; @@ -892,27 +896,26 @@ propagate_necessity (bool aggressive) && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC - || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC)) + || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC + || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_GOMP_ALLOC)) || (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee) && gimple_call_from_new_or_delete (def_stmt)))) { - if (is_delete_operator) - { - if (!valid_new_delete_pair_p (def_stmt, stmt)) - mark_operand_necessary (gimple_call_arg (stmt, 0)); - - /* Delete operators can have alignment and (or) size - as next arguments. When being a SSA_NAME, they - must be marked as necessary. */ - if (gimple_call_num_args (stmt) >= 2) - for (unsigned i = 1; i < gimple_call_num_args (stmt); - i++) - { - tree arg = gimple_call_arg (stmt, i); - if (TREE_CODE (arg) == SSA_NAME) - mark_operand_necessary (arg); - } - } + if (is_delete_operator + && !valid_new_delete_pair_p (def_stmt, stmt)) + mark_operand_necessary (gimple_call_arg (stmt, 0)); + + /* Delete operators can have alignment and (or) size + as next arguments. When being a SSA_NAME, they + must be marked as necessary. Similarly GOMP_free. */ + if (gimple_call_num_args (stmt) >= 2) + for (unsigned i = 1; i < gimple_call_num_args (stmt); + i++) + { + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (arg) == SSA_NAME) + mark_operand_necessary (arg); + } continue; } -- cgit v1.1 From 1d00f8c86324c40ab2ba7933366d380e32c0a94a Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 12 Nov 2020 21:13:51 +0000 Subject: c: C2x __has_c_attribute C2x adds the __has_c_attribute preprocessor operator, similar to C++ __has_cpp_attribute. GCC implements __has_cpp_attribute as exactly equivalent to __has_attribute. (The documentation says they differ regarding the values returned for standard attributes, but that's actually only a matter of the particular nonzero value returned not being specified in the documentation for __has_attribute; the implementation makes no distinction between the two.) I don't think having them exactly equivalent is actually correct, either for __has_cpp_attribute or for __has_c_attribute. Specifically, I think it is only correct for __has_cpp_attribute or __has_c_attribute to return nonzero if the given attribute is supported, with the particular pp-tokens passed to __has_cpp_attribute or __has_c_attribute, with [[]] syntax, not if it's only accepted in __attribute__ or with gnu:: added in [[]]. For example, they should return nonzero for gnu::packed, but zero for plain packed, because [[gnu::packed]] is accepted but [[packed]] is ignored as not a standard attribute. This patch implements that for __has_c_attribute, leaving any changes to __has_cpp_attribute for the C++ maintainers. A new BT_HAS_STD_ATTRIBUTE is added for __has_c_attribute (which I think, based on the above, would actually be correct to use for __has_cpp_attribute as well). The code in c_common_has_attribute that deals with scopes has its C++ conditional removed; instead, whether the language is C or C++ is used only to determine the numeric values returned for standard attributes (and which standard attributes are handled there at all). A new argument is passed to c_common_has_attribute to distinguish BT_HAS_STD_ATTRIBUTE from BT_HAS_ATTRIBUTE, and that argument is used to stop attributes with no scope specified from being accepted with __has_c_attribute unless they are one of the known standard attributes and so handled specially. Although the standard specify constants ending with 'L' as the values for the standard attributes, there is no correctness issue with the lack of code in GCC to add that 'L' to the expansion: __has_c_attribute and __has_cpp_attribute are expanded in #if after other macro expansion has occurred, with no semantics being specified if they occur outside #if, so there is no way for a conforming program to inspect the exact text of the expansion of those macros, only to use the resulting pp-number in a #if expression, where long and int have the same set of values. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/ 2020-11-12 Joseph Myers * doc/cpp.texi (__has_attribute): Document when scopes are allowed for C. (__has_c_attribute): New. gcc/c-family/ 2020-11-12 Joseph Myers * c-lex.c (c_common_has_attribute): Take argument std_syntax. Allow scope for C. Handle standard attributes for C. Do not accept unscoped attributes if std_syntax and not handled as standard attributes. * c-common.h (c_common_has_attribute): Update prototype. gcc/testsuite/ 2020-11-12 Joseph Myers * gcc.dg/c2x-has-c-attribute-1.c, gcc.dg/c2x-has-c-attribute-2.c, gcc.dg/c2x-has-c-attribute-3.c, gcc.dg/c2x-has-c-attribute-4.c: New tests. libcpp/ 2020-11-12 Joseph Myers * include/cpplib.h (struct cpp_callbacks): Add bool argument to has_attribute. (enum cpp_builtin_type): Add BT_HAS_STD_ATTRIBUTE. * init.c (builtin_array): Add __has_c_attribute. (cpp_init_special_builtins): Handle BT_HAS_STD_ATTRIBUTE. * macro.c (_cpp_builtin_macro_text): Handle BT_HAS_STD_ATTRIBUTE. Update call to has_attribute for BT_HAS_ATTRIBUTE. * traditional.c (fun_like_macro): Handle BT_HAS_STD_ATTRIBUTE. --- gcc/c-family/c-common.h | 2 +- gcc/c-family/c-lex.c | 67 ++++++++++++++++------------ gcc/doc/cpp.texi | 21 ++++++++- gcc/testsuite/gcc.dg/c2x-has-c-attribute-1.c | 28 ++++++++++++ gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c | 41 +++++++++++++++++ gcc/testsuite/gcc.dg/c2x-has-c-attribute-3.c | 25 +++++++++++ gcc/testsuite/gcc.dg/c2x-has-c-attribute-4.c | 18 ++++++++ 7 files changed, 171 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-has-c-attribute-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-has-c-attribute-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-has-c-attribute-4.c (limited to 'gcc') diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 94f4868..f470974 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1042,7 +1042,7 @@ extern bool c_cpp_diagnostic (cpp_reader *, enum cpp_diagnostic_level, enum cpp_warning_reason, rich_location *, const char *, va_list *) ATTRIBUTE_GCC_DIAG(5,0); -extern int c_common_has_attribute (cpp_reader *); +extern int c_common_has_attribute (cpp_reader *, bool); extern int c_common_has_builtin (cpp_reader *); extern bool parse_optimize_options (tree, bool); diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index e81e16d..6cd3df7 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -300,7 +300,7 @@ get_token_no_padding (cpp_reader *pfile) /* Callback for has_attribute. */ int -c_common_has_attribute (cpp_reader *pfile) +c_common_has_attribute (cpp_reader *pfile, bool std_syntax) { int result = 0; tree attr_name = NULL_TREE; @@ -319,35 +319,37 @@ c_common_has_attribute (cpp_reader *pfile) attr_name = get_identifier ((const char *) cpp_token_as_text (pfile, token)); attr_name = canonicalize_attr_name (attr_name); - if (c_dialect_cxx ()) + bool have_scope = false; + int idx = 0; + const cpp_token *nxt_token; + do + nxt_token = cpp_peek_token (pfile, idx++); + while (nxt_token->type == CPP_PADDING); + if (nxt_token->type == CPP_SCOPE) { - int idx = 0; - const cpp_token *nxt_token; - do - nxt_token = cpp_peek_token (pfile, idx++); - while (nxt_token->type == CPP_PADDING); - if (nxt_token->type == CPP_SCOPE) + have_scope = true; + get_token_no_padding (pfile); // Eat scope. + nxt_token = get_token_no_padding (pfile); + if (nxt_token->type == CPP_NAME) { - get_token_no_padding (pfile); // Eat scope. - nxt_token = get_token_no_padding (pfile); - if (nxt_token->type == CPP_NAME) - { - tree attr_ns = attr_name; - tree attr_id - = get_identifier ((const char *) - cpp_token_as_text (pfile, nxt_token)); - attr_name = build_tree_list (attr_ns, attr_id); - } - else - { - cpp_error (pfile, CPP_DL_ERROR, - "attribute identifier required after scope"); - attr_name = NULL_TREE; - } + tree attr_ns = attr_name; + tree attr_id + = get_identifier ((const char *) + cpp_token_as_text (pfile, nxt_token)); + attr_name = build_tree_list (attr_ns, attr_id); } else { - /* Some standard attributes need special handling. */ + cpp_error (pfile, CPP_DL_ERROR, + "attribute identifier required after scope"); + attr_name = NULL_TREE; + } + } + else + { + /* Some standard attributes need special handling. */ + if (c_dialect_cxx ()) + { if (is_attribute_p ("noreturn", attr_name)) result = 200809; else if (is_attribute_p ("deprecated", attr_name)) @@ -361,11 +363,20 @@ c_common_has_attribute (cpp_reader *pfile) result = 201803; else if (is_attribute_p ("nodiscard", attr_name)) result = 201907; - if (result) - attr_name = NULL_TREE; } + else + { + if (is_attribute_p ("deprecated", attr_name) + || is_attribute_p ("maybe_unused", attr_name) + || is_attribute_p ("fallthrough", attr_name)) + result = 201904; + else if (is_attribute_p ("nodiscard", attr_name)) + result = 202003; + } + if (result) + attr_name = NULL_TREE; } - if (attr_name) + if (attr_name && (have_scope || !std_syntax)) { init_attributes (); const struct attribute_spec *attr = lookup_attribute_spec (attr_name); diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index 33f876a..291e146 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -3159,6 +3159,7 @@ directive}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}. * Elif:: * @code{__has_attribute}:: * @code{__has_cpp_attribute}:: +* @code{__has_c_attribute}:: * @code{__has_builtin}:: * @code{__has_include}:: @end menu @@ -3432,8 +3433,9 @@ condition succeeds after the original @samp{#if} and all previous The special operator @code{__has_attribute (@var{operand})} may be used in @samp{#if} and @samp{#elif} expressions to test whether the attribute referenced by its @var{operand} is recognized by GCC. Using the operator -in other contexts is not valid. In C code, @var{operand} must be -a valid identifier. In C++ code, @var{operand} may be optionally +in other contexts is not valid. In C code, if compiling for strict +conformance to standards before C2x, @var{operand} must be +a valid identifier. Otherwise, @var{operand} may be optionally introduced by the @code{@var{attribute-scope}::} prefix. The @var{attribute-scope} prefix identifies the ``namespace'' within which the attribute is recognized. The scope of GCC attributes is @@ -3479,6 +3481,21 @@ information including the dates of the introduction of current standard attributes, see @w{@uref{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations/, SD-6: SG10 Feature Test Recommendations}}. +@node @code{__has_c_attribute} +@subsection @code{__has_c_attribute} +@cindex @code{__has_c_attribute} + +The special operator @code{__has_c_attribute (@var{operand})} may be +used in @samp{#if} and @samp{#elif} expressions in C code to test +whether the attribute referenced by its @var{operand} is recognized by +GCC in attributes using the @samp{[[]]} syntax. GNU attributes must +be specified with the scope @samp{gnu} or @samp{__gnu__} with +@code{__has_c_attribute}. When @var{operand} designates a supported +standard attribute it evaluates to an integer constant of the form +@code{YYYYMM} indicating the year and month when the attribute was +first introduced into the C standard, or when the syntax of operands +to the attribute was extended in the C standard. + @node @code{__has_builtin} @subsection @code{__has_builtin} @cindex @code{__has_builtin} diff --git a/gcc/testsuite/gcc.dg/c2x-has-c-attribute-1.c b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-1.c new file mode 100644 index 0000000..fe06abf --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-1.c @@ -0,0 +1,28 @@ +/* Test __has_c_attribute. Test basic properties. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#ifdef __has_c_attribute +/* OK. */ +#else +#error "__has_c_attribute not defined" +#endif + +#ifndef __has_c_attribute +#error "__has_c_attribute not defined" +#endif + +#if defined __has_c_attribute +/* OK. */ +#else +#error "__has_c_attribute not defined" +#endif + +#if __has_c_attribute(foo) +#error "foo attribute supported" +#endif + +#if 0 +#elif __has_c_attribute(foo) +#error "foo attribute supported" +#endif diff --git a/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c new file mode 100644 index 0000000..d6c4c6d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c @@ -0,0 +1,41 @@ +/* Test __has_c_attribute. Test supported attributes. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#if __has_c_attribute ( nodiscard ) != 202003L +#error "bad result for nodiscard" +#endif + +#if __has_c_attribute ( __nodiscard__ ) != 202003L +#error "bad result for __nodiscard__" +#endif + +#if __has_c_attribute(maybe_unused) != 201904L +#error "bad result for maybe_unused" +#endif + +#if __has_c_attribute(__maybe_unused__) != 201904L +#error "bad result for __maybe_unused__" +#endif + +#if __has_c_attribute (deprecated) != 201904L +#error "bad result for deprecated" +#endif + +#if __has_c_attribute (__deprecated__) != 201904L +#error "bad result for __deprecated__" +#endif + +#if __has_c_attribute (fallthrough) != 201904L +#error "bad result for fallthrough" +#endif + +#if __has_c_attribute (__fallthrough__) != 201904L +#error "bad result for __fallthrough__" +#endif + +/* Macros in the attribute name are expanded. */ +#define foo deprecated +#if __has_c_attribute (foo) != 201904L +#error "bad result for foo" +#endif diff --git a/gcc/testsuite/gcc.dg/c2x-has-c-attribute-3.c b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-3.c new file mode 100644 index 0000000..36842ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-3.c @@ -0,0 +1,25 @@ +/* Test __has_c_attribute. Test GNU attributes. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#if __has_c_attribute (gnu::packed) != 1 +#error "bad result for gnu::packed" +#endif + +#if __has_c_attribute (__gnu__::__packed__) != 1 +#error "bad result for __gnu__::__packed__" +#endif + +#if __has_c_attribute (gnu::__packed__) != 1 +#error "bad result for gnu::__packed__" +#endif + +#if __has_c_attribute (__gnu__::packed) != 1 +#error "bad result for __gnu__::packed" +#endif + +/* GNU attributes should not be reported as accepted without a scope + specified. */ +#if __has_c_attribute (packed) != 0 +#error "bad result for packed" +#endif diff --git a/gcc/testsuite/gcc.dg/c2x-has-c-attribute-4.c b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-4.c new file mode 100644 index 0000000..acd35d2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-4.c @@ -0,0 +1,18 @@ +/* Test __has_c_attribute. Test syntax errors. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#if __has_c_attribute /* { dg-error "missing '\\('" } */ +#endif + +#if __has_c_attribute 0 /* { dg-error "missing '\\('" } */ +#endif + +#if __has_c_attribute (0 /* { dg-error "requires an identifier" } */ +#endif + +#if __has_c_attribute (x /* { dg-error "missing '\\)'" } */ +#endif + +#if __has_c_attribute (x::0) /* { dg-error "required after scope" } */ +#endif -- cgit v1.1 From 97976c0757ad3173ac00d1e32e335f3f960b0b9f Mon Sep 17 00:00:00 2001 From: Nelson Chu Date: Tue, 10 Nov 2020 19:33:38 -0800 Subject: RISC-V: Enable ifunc if it was supported in the binutils for linux toolchain. gcc/ * configure: Regenerated. * configure.ac: If ifunc was supported in the binutils for linux toolchain, then set enable_gnu_indirect_function to yes. --- gcc/configure | 37 +++++++++++++++++++++++++++++++++++++ gcc/configure.ac | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'gcc') diff --git a/gcc/configure b/gcc/configure index 9d2fd0d..dbda441 100755 --- a/gcc/configure +++ b/gcc/configure @@ -23407,6 +23407,43 @@ else fi +case "${target}" in + riscv*-*-linux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker ifunc IRELATIVE support" >&5 +$as_echo_n "checking linker ifunc IRELATIVE support... " >&6; } + cat > conftest.s < /dev/null 2>&1 \ + && $gcc_cv_ld -o conftest conftest.o > /dev/null 2>&1 \ + && $gcc_cv_readelf --relocs --wide conftest \ + | grep R_RISCV_IRELATIVE > /dev/null 2>&1; then + enable_gnu_indirect_function=yes + fi + rm -f conftest conftest.o conftest.s + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gnu_indirect_function" >&5 +$as_echo "$enable_gnu_indirect_function" >&6; } + ;; +esac + gif=`if test x$enable_gnu_indirect_function = xyes; then echo 1; else echo 0; fi` cat >>confdefs.h <<_ACEOF diff --git a/gcc/configure.ac b/gcc/configure.ac index 73034bb..08f3034 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2807,6 +2807,41 @@ Valid choices are 'yes' and 'no'.]) ;; esac], [enable_gnu_indirect_function="$default_gnu_indirect_function"]) +case "${target}" in + riscv*-*-linux*) + AC_MSG_CHECKING(linker ifunc IRELATIVE support) + cat > conftest.s < /dev/null 2>&1 \ + && $gcc_cv_ld -o conftest conftest.o > /dev/null 2>&1 \ + && $gcc_cv_readelf --relocs --wide conftest \ + | grep R_RISCV_IRELATIVE > /dev/null 2>&1; then + enable_gnu_indirect_function=yes + fi + rm -f conftest conftest.o conftest.s + AC_MSG_RESULT($enable_gnu_indirect_function) + ;; +esac + gif=`if test x$enable_gnu_indirect_function = xyes; then echo 1; else echo 0; fi` AC_DEFINE_UNQUOTED(HAVE_GNU_INDIRECT_FUNCTION, $gif, [Define if your system supports gnu indirect functions.]) -- cgit v1.1 From 8948a5715b00fe36d20c03b6c4c4397b74cc6282 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 12 Nov 2020 17:26:01 -0500 Subject: libgccjit.h: fix typo in comment gcc/jit/ChangeLog: * libgccjit.h: Fix typo in comment. --- gcc/jit/libgccjit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 7134841..7fbaa9f 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1504,7 +1504,7 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt, #define LIBGCCJIT_HAVE_gcc_jit_version -/* Functions to retrive libgccjit version. +/* Functions to retrieve libgccjit version. Analogous to __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ in C code. These API entrypoints were added in LIBGCCJIT_ABI_13; you can test for their -- cgit v1.1 From fec573408310139e1ffc42741fbe46b4f2947592 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 12 Nov 2020 17:27:28 -0500 Subject: jit: fix string escaping This patch fixes a bug in recording::string::make_debug_string in which '\t' and '\n' were "escaped" by simply prepending a '\', thus emitting '\' then '\n', rather than '\' then 'n'. It also removes a hack that determined if a string is to be escaped by checking for a leading '"', by instead adding a flag. gcc/jit/ChangeLog: * jit-recording.c (recording::context::new_string): Add "escaped" param and use it when creating the new recording::string instance. (recording::string::string): Add "escaped" param and use it to initialize m_escaped. (recording::string::make_debug_string): Replace check that first char is double-quote with use of m_escaped. Fix escaping of '\t' and '\n'. Set "escaped" on the result. * jit-recording.h (recording::context::new_string): Add "escaped" param. (recording::string::string): Add "escaped" param. (recording::string::m_escaped): New field. gcc/testsuite/ChangeLog: * jit.dg/test-debug-strings.c (create_code): Add tests of string literal escaping. --- gcc/jit/jit-recording.c | 39 ++++++++++++++++++++++--------- gcc/jit/jit-recording.h | 9 +++++-- gcc/testsuite/jit.dg/test-debug-strings.c | 20 ++++++++++++++++ 3 files changed, 55 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 3cbeba0..3a84c1f 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -724,12 +724,12 @@ recording::context::disassociate_from_playback () This creates a fresh copy of the given 0-terminated buffer. */ recording::string * -recording::context::new_string (const char *text) +recording::context::new_string (const char *text, bool escaped) { if (!text) return NULL; - recording::string *result = new string (this, text); + recording::string *result = new string (this, text, escaped); record (result); return result; } @@ -1954,8 +1954,9 @@ recording::memento::write_to_dump (dump &d) /* Constructor for gcc::jit::recording::string::string, allocating a copy of the given text using new char[]. */ -recording::string::string (context *ctxt, const char *text) - : memento (ctxt) +recording::string::string (context *ctxt, const char *text, bool escaped) +: memento (ctxt), + m_escaped (escaped) { m_len = strlen (text); m_buffer = new char[m_len + 1]; @@ -2005,9 +2006,9 @@ recording::string::from_printf (context *ctxt, const char *fmt, ...) recording::string * recording::string::make_debug_string () { - /* Hack to avoid infinite recursion into strings when logging all - mementos: don't re-escape strings: */ - if (m_buffer[0] == '"') + /* Avoid infinite recursion into strings when logging all mementos: + don't re-escape strings: */ + if (m_escaped) return this; /* Wrap in quotes and do escaping etc */ @@ -2024,15 +2025,31 @@ recording::string::make_debug_string () for (size_t i = 0; i < m_len ; i++) { char ch = m_buffer[i]; - if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"') - APPEND('\\'); - APPEND(ch); + switch (ch) + { + default: + APPEND(ch); + break; + case '\t': + APPEND('\\'); + APPEND('t'); + break; + case '\n': + APPEND('\\'); + APPEND('n'); + break; + case '\\': + case '"': + APPEND('\\'); + APPEND(ch); + break; + } } APPEND('"'); /* closing quote */ #undef APPEND tmp[len] = '\0'; /* nil termintator */ - string *result = m_ctxt->new_string (tmp); + string *result = m_ctxt->new_string (tmp, true); delete[] tmp; return result; diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 30e37af..9a43a7b 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -74,7 +74,7 @@ public: void disassociate_from_playback (); string * - new_string (const char *text); + new_string (const char *text, bool escaped = false); location * new_location (const char *filename, @@ -414,7 +414,7 @@ private: class string : public memento { public: - string (context *ctxt, const char *text); + string (context *ctxt, const char *text, bool escaped); ~string (); const char *c_str () { return m_buffer; } @@ -431,6 +431,11 @@ private: private: size_t m_len; char *m_buffer; + + /* Flag to track if this string is the result of string::make_debug_string, + to avoid infinite recursion when logging all mementos: don't re-escape + such strings. */ + bool m_escaped; }; class location : public memento diff --git a/gcc/testsuite/jit.dg/test-debug-strings.c b/gcc/testsuite/jit.dg/test-debug-strings.c index e515a17..03ef337 100644 --- a/gcc/testsuite/jit.dg/test-debug-strings.c +++ b/gcc/testsuite/jit.dg/test-debug-strings.c @@ -178,6 +178,26 @@ create_code (gcc_jit_context *ctxt, void *user_data) "((struct node *)ptr->next)->next"); } + /* Check string literal escaping. */ + { + CHECK_RVALUE_DEBUG_STRING + (gcc_jit_context_new_string_literal (ctxt, ""), + "\"\""); + CHECK_RVALUE_DEBUG_STRING + (gcc_jit_context_new_string_literal (ctxt, "foo"), + "\"foo\""); + CHECK_RVALUE_DEBUG_STRING + (gcc_jit_context_new_string_literal (ctxt, "\""), + "\"\\\"\""); + CHECK_RVALUE_DEBUG_STRING + (gcc_jit_context_new_string_literal (ctxt, "line 1\nline 2\n"), + "\"line 1\\nline 2\\n\""); + CHECK_RVALUE_DEBUG_STRING + (gcc_jit_context_new_string_literal (ctxt, "foo\tbar"), + "\"foo\\tbar\""); + } + +#undef CHECK_RVALUE_DEBUG_STRING #undef CHECK_LVALUE_DEBUG_STRING } -- cgit v1.1 From 421d0d0f54294a7bf2872b3b2ac521ce0fa9869e Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 12 Nov 2020 17:28:17 -0500 Subject: jit: add support for inline asm [PR87291] This patch adds various entrypoints to libgccjit for directly embedding asm statements into a compile, analogous to inline asm in the C frontend: gcc_jit_block_add_extended_asm gcc_jit_block_end_with_extended_asm_goto gcc_jit_extended_asm_as_object gcc_jit_extended_asm_set_volatile_flag gcc_jit_extended_asm_set_inline_flag gcc_jit_extended_asm_add_output_operand gcc_jit_extended_asm_add_input_operand gcc_jit_extended_asm_add_clobber gcc_jit_context_add_top_level_asm gcc/jit/ChangeLog: PR jit/87291 * docs/cp/topics/asm.rst: New file. * docs/cp/topics/index.rst (Topic Reference): Add it. * docs/topics/asm.rst: New file. * docs/topics/compatibility.rst (LIBGCCJIT_ABI_15): New. * docs/topics/functions.rst (Statements): Add link to extended asm. * docs/topics/index.rst (Topic Reference): Add asm.rst. * docs/topics/objects.rst: Add gcc_jit_extended_asm to ASCII art. * docs/_build/texinfo/Makefile: Regenerate. * docs/_build/texinfo/libgccjit.texi: Regenerate. * jit-common.h (gcc::jit::recording::extended_asm): New forward decl. (gcc::jit::recording::top_level_asm): Likewise. * jit-playback.c: Include "stmt.h". (build_string): New. (gcc::jit::playback::context::new_string_literal): Disambiguate build_string call. (gcc::jit::playback::context::add_top_level_asm): New. (build_operand_chain): New. (build_clobbers): New. (build_goto_operands): New. (gcc::jit::playback::block::add_extended_asm): New. * jit-playback.h (gcc::jit::playback::context::add_top_level_asm): New decl. (struct gcc::jit::playback::asm_operand): New struct. (gcc::jit::playback::block::add_extended_asm): New decl. * jit-recording.c (gcc::jit::recording::context::dump_to_file): Dump top-level asms. (gcc::jit::recording::context::add_top_level_asm): New. (gcc::jit::recording::block::add_extended_asm): New. (gcc::jit::recording::block::end_with_extended_asm_goto): New. (gcc::jit::recording::asm_operand::asm_operand): New. (gcc::jit::recording::asm_operand::print): New. (gcc::jit::recording::asm_operand::make_debug_string): New. (gcc::jit::recording::output_asm_operand::write_reproducer): New. (gcc::jit::recording::output_asm_operand::print): New. (gcc::jit::recording::input_asm_operand::write_reproducer): New. (gcc::jit::recording::input_asm_operand::print): New. (gcc::jit::recording::extended_asm::add_output_operand): New. (gcc::jit::recording::extended_asm::add_input_operand): New. (gcc::jit::recording::extended_asm::add_clobber): New. (gcc::jit::recording::extended_asm::replay_into): New. (gcc::jit::recording::extended_asm::make_debug_string): New. (gcc::jit::recording::extended_asm::write_flags): New. (gcc::jit::recording::extended_asm::write_clobbers): New. (gcc::jit::recording::extended_asm_simple::write_reproducer): New. (gcc::jit::recording::extended_asm::maybe_populate_playback_blocks): New. (gcc::jit::recording::extended_asm_goto::extended_asm_goto): New. (gcc::jit::recording::extended_asm_goto::replay_into): New. (gcc::jit::recording::extended_asm_goto::write_reproducer): New. (gcc::jit::recording::extended_asm_goto::get_successor_blocks): New. (gcc::jit::recording::extended_asm_goto::maybe_print_gotos): New. (gcc::jit::recording::extended_asm_goto::maybe_populate_playback_blocks): New. (gcc::jit::recording::top_level_asm::top_level_asm): New. (gcc::jit::recording::top_level_asm::replay_into): New. (gcc::jit::recording::top_level_asm::make_debug_string): New. (gcc::jit::recording::top_level_asm::write_to_dump): New. (gcc::jit::recording::top_level_asm::write_reproducer): New. * jit-recording.h (gcc::jit::recording::context::add_top_level_asm): New decl. (gcc::jit::recording::context::m_top_level_asms): New field. (gcc::jit::recording::block::add_extended_asm): New decl. (gcc::jit::recording::block::end_with_extended_asm_goto): New decl. (gcc::jit::recording::asm_operand): New class. (gcc::jit::recording::output_asm_operand): New class. (gcc::jit::recording::input_asm_operand): New class. (gcc::jit::recording::extended_asm): New class. (gcc::jit::recording::extended_asm_simple): New class. (gcc::jit::recording::extended_asm_goto): New class. (gcc::jit::recording::top_level_asm): New class. * libgccjit++.h (gccjit::extended_asm): New forward decl. (gccjit::context::add_top_level_asm): New. (gccjit::block::add_extended_asm): New. (gccjit::block::end_with_extended_asm_goto): New. (gccjit::extended_asm): New class. (gccjit::extended_asm::extended_asm): New ctors. (gccjit::extended_asm::set_volatile_flag): New. (gccjit::extended_asm::set_inline_flag): New. (gccjit::extended_asm::add_output_operand): New. (gccjit::extended_asm::add_input_operand): New. (gccjit::extended_asm::add_clobber): New. (gccjit::extended_asm::get_inner_extended_asm): New. * libgccjit.c (struct gcc_jit_extended_asm): New. (jit_error): Make "loc" param take a gcc::jit::recording::location * rather than a gcc_jit_location *. (gcc_jit_block_add_extended_asm): New entrypoint. (gcc_jit_block_end_with_extended_asm_goto): New entrypoint. (gcc_jit_extended_asm_as_object): New entrypoint. (gcc_jit_extended_asm_set_volatile_flag): New entrypoint. (gcc_jit_extended_asm_set_inline_flag): New entrypoint. (gcc_jit_extended_asm_add_output_operand): New entrypoint. (gcc_jit_extended_asm_add_clobber): New entrypoint. (gcc_jit_context_add_top_level_asm): New entrypoint. * libgccjit.h: Add gcc_jit_extended_asm to ASCII art. (gcc_jit_extended_asm): New typedef. (LIBGCCJIT_HAVE_ASM_STATEMENTS): New define. (gcc_jit_block_add_extended_asm): New entrypoint. (gcc_jit_block_end_with_extended_asm_goto): New entrypoint. (gcc_jit_extended_asm_as_object): New entrypoint. (gcc_jit_extended_asm_set_volatile_flag): New entrypoint. (gcc_jit_extended_asm_set_inline_flag): New entrypoint. (gcc_jit_extended_asm_add_output_operand): New entrypoint. (gcc_jit_extended_asm_add_input_operand): New entrypoint. (gcc_jit_extended_asm_add_clobber): New entrypoint. (gcc_jit_context_add_top_level_asm): New entrypoint. * libgccjit.map (LIBGCCJIT_ABI_15): New. gcc/testsuite/ChangeLog: PR jit/87291 * jit.dg/jit.exp: Load target-supports-dg.exp. Set dg-do-what-default. (jit-dg-test): Set dg-do-what and call dg-get-options, skipping the test if it's not supported on the given target. * jit.dg/test-asm.c: New test. * jit.dg/test-asm.cc: New test. --- gcc/jit/docs/_build/texinfo/Makefile | 11 +- gcc/jit/docs/_build/texinfo/libgccjit.texi | 1837 ++++++++++++++++++++-------- gcc/jit/docs/cp/topics/asm.rst | 308 +++++ gcc/jit/docs/cp/topics/index.rst | 1 + gcc/jit/docs/topics/asm.rst | 311 +++++ gcc/jit/docs/topics/compatibility.rst | 17 + gcc/jit/docs/topics/functions.rst | 3 + gcc/jit/docs/topics/index.rst | 1 + gcc/jit/docs/topics/objects.rst | 1 + gcc/jit/jit-common.h | 2 + gcc/jit/jit-playback.c | 125 +- gcc/jit/jit-playback.h | 27 + gcc/jit/jit-recording.c | 514 ++++++++ gcc/jit/jit-recording.h | 215 ++++ gcc/jit/libgccjit++.h | 170 +++ gcc/jit/libgccjit.c | 188 ++- gcc/jit/libgccjit.h | 103 ++ gcc/jit/libgccjit.map | 13 + gcc/testsuite/jit.dg/jit.exp | 31 + gcc/testsuite/jit.dg/test-asm.c | 492 ++++++++ gcc/testsuite/jit.dg/test-asm.cc | 453 +++++++ 21 files changed, 4318 insertions(+), 505 deletions(-) create mode 100644 gcc/jit/docs/cp/topics/asm.rst create mode 100644 gcc/jit/docs/topics/asm.rst create mode 100644 gcc/testsuite/jit.dg/test-asm.c create mode 100644 gcc/testsuite/jit.dg/test-asm.cc (limited to 'gcc') diff --git a/gcc/jit/docs/_build/texinfo/Makefile b/gcc/jit/docs/_build/texinfo/Makefile index 81c60f5..e3b732c 100644 --- a/gcc/jit/docs/_build/texinfo/Makefile +++ b/gcc/jit/docs/_build/texinfo/Makefile @@ -18,13 +18,20 @@ pdf: $(addsuffix .pdf,$(ALLDOCS)) install-info: info for f in *.info; do \ - cp -t $(infodir) "$$f" && \ - $(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \ + mkdir -p $(infodir) && \ + cp "$$f" $(infodir) && \ + $(INSTALL_INFO) --info-dir=$(infodir) "$$f" && \ + \ + FIGURE_DIR="`basename \"$$f\" .info`-figures" && \ + if [ -e "$$FIGURE_DIR" ]; then \ + cp -r "$$FIGURE_DIR" $(infodir) ; \ + fi; \ done uninstall-info: info for f in *.info; do \ rm -f "$(infodir)/$$f" ; \ + rm -rf "$(infodir)/`basename '$$f' .info`-figures" && \ $(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \ done diff --git a/gcc/jit/docs/_build/texinfo/libgccjit.texi b/gcc/jit/docs/_build/texinfo/libgccjit.texi index 57aca7a..7b957b7 100644 --- a/gcc/jit/docs/_build/texinfo/libgccjit.texi +++ b/gcc/jit/docs/_build/texinfo/libgccjit.texi @@ -3,7 +3,7 @@ @setfilename libgccjit.info @documentencoding UTF-8 @ifinfo -@*Generated by Sphinx 1.6.7.@* +@*Generated by Sphinx 2.2.2.@* @end ifinfo @settitle libgccjit Documentation @defindex ge @@ -21,7 +21,7 @@ @copying @quotation -libgccjit 11.0.0 (experimental 20200914), Sep 14, 2020 +libgccjit 11.0.0 (experimental 20201112), Nov 12, 2020 David Malcolm @@ -173,6 +173,7 @@ Topic Reference * Compiling a context:: * ABI and API compatibility:: * Performance:: +* Using Assembly Language with libgccjit:: Compilation contexts @@ -256,11 +257,17 @@ ABI symbol tags * LIBGCCJIT_ABI_12:: * LIBGCCJIT_ABI_13:: * LIBGCCJIT_ABI_14:: +* LIBGCCJIT_ABI_15:: Performance * The timing API:: +Using Assembly Language with libgccjit + +* Adding assembler instructions within a function:: +* Adding top-level assembler statements:: + C++ bindings for libgccjit * Tutorial: Tutorial<2>. @@ -312,6 +319,7 @@ Topic Reference * Creating and using functions: Creating and using functions<2>. * Source Locations: Source Locations<2>. * Compiling a context: Compiling a context<2>. +* Using Assembly Language with libgccjit++:: Compilation contexts @@ -372,6 +380,11 @@ Compiling a context * In-memory compilation: In-memory compilation<2>. * Ahead-of-time compilation: Ahead-of-time compilation<2>. +Using Assembly Language with libgccjit++ + +* Adding assembler instructions within a function: Adding assembler instructions within a function<2>. +* Adding top-level assembler statements: Adding top-level assembler statements<2>. + Internals * Working on the JIT library:: @@ -390,7 +403,7 @@ Running the test suite @end menu @node Tutorial,Topic Reference,Top,Top -@anchor{intro/index libgccjit}@anchor{1}@anchor{intro/index doc}@anchor{2}@anchor{intro/index tutorial}@anchor{3} +@anchor{intro/index doc}@anchor{1}@anchor{intro/index libgccjit}@anchor{2}@anchor{intro/index tutorial}@anchor{3} @chapter Tutorial @@ -1122,7 +1135,7 @@ result: 25 @c . @node Tutorial part 3 Loops and variables,Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial part 2 Creating a trivial machine code function,Tutorial -@anchor{intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{21}@anchor{intro/tutorial03 doc}@anchor{22} +@anchor{intro/tutorial03 doc}@anchor{21}@anchor{intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{22} @section Tutorial part 3: Loops and variables @@ -1171,7 +1184,7 @@ Here’s what the final control flow graph will look like: @float Figure -@image{sum-of-squares1,,,image of a control flow graph,png} +@image{libgccjit-figures/sum-of-squares1,,,image of a control flow graph,png} @end float @@ -1520,7 +1533,7 @@ install it with @cite{yum install python-xdot}): @float Figure -@image{sum-of-squares1,,,image of a control flow graph,png} +@image{libgccjit-figures/sum-of-squares1,,,image of a control flow graph,png} @end float @@ -1740,7 +1753,7 @@ loop_test returned: 285 @c . @node Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial part 5 Implementing an Ahead-of-Time compiler,Tutorial part 3 Loops and variables,Tutorial -@anchor{intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{35}@anchor{intro/tutorial04 doc}@anchor{36} +@anchor{intro/tutorial04 doc}@anchor{35}@anchor{intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{36} @section Tutorial part 4: Adding JIT-compilation to a toy interpreter @@ -2716,7 +2729,7 @@ errors in our compiler. @float Figure -@image{factorial1,,,image of a control flow graph,png} +@image{libgccjit-figures/factorial1,,,image of a control flow graph,png} @end float @@ -4435,11 +4448,12 @@ and to a dynamic library. See the documentation of * Compiling a context:: * ABI and API compatibility:: * Performance:: +* Using Assembly Language with libgccjit:: @end menu @node Compilation contexts,Objects,,Topic Reference -@anchor{topics/contexts compilation-contexts}@anchor{51}@anchor{topics/contexts doc}@anchor{52} +@anchor{topics/contexts doc}@anchor{51}@anchor{topics/contexts compilation-contexts}@anchor{52} @section Compilation contexts @@ -5130,7 +5144,7 @@ its presence using @c . @node Objects,Types,Compilation contexts,Topic Reference -@anchor{topics/objects objects}@anchor{76}@anchor{topics/objects doc}@anchor{77} +@anchor{topics/objects doc}@anchor{76}@anchor{topics/objects objects}@anchor{77} @section Objects @@ -5175,6 +5189,7 @@ looks like this: +- gcc_jit_lvalue +- gcc_jit_param +- gcc_jit_case + +- gcc_jit_extended_asm @end example There are casting methods for upcasting from subclasses to parent classes. @@ -5875,7 +5890,7 @@ Function pointer types can be created using @c . @node Expressions,Creating and using functions,Types,Topic Reference -@anchor{topics/expressions expressions}@anchor{96}@anchor{topics/expressions doc}@anchor{97} +@anchor{topics/expressions doc}@anchor{96}@anchor{topics/expressions expressions}@anchor{97} @section Expressions @@ -7520,6 +7535,9 @@ create_code (gcc_jit_context *ctxt, void *user_data) @end quotation @end deffn +See also @ref{f1,,gcc_jit_extended_asm} for entrypoints for adding inline +assembler statements to a function. + @c Copyright (C) 2017-2020 Free Software Foundation, Inc. @c Originally contributed by David Malcolm @c @@ -7538,7 +7556,7 @@ create_code (gcc_jit_context *ctxt, void *user_data) @c . @node Function pointers<2>,Source Locations,Creating and using functions,Topic Reference -@anchor{topics/function-pointers doc}@anchor{f1}@anchor{topics/function-pointers function-pointers}@anchor{f2} +@anchor{topics/function-pointers doc}@anchor{f2}@anchor{topics/function-pointers function-pointers}@anchor{f3} @section Function pointers @@ -7557,7 +7575,7 @@ via @ref{c0,,gcc_jit_function_get_address()}. Get the address of a function as an rvalue, of function pointer type. -This entrypoint was added in @ref{f3,,LIBGCCJIT_ABI_9}; you can test +This entrypoint was added in @ref{f4,,LIBGCCJIT_ABI_9}; you can test for its presence using @example @@ -7619,7 +7637,7 @@ Each of @cite{param_types} must be non-@cite{void}; @cite{return_type} may be @c @c . @node Source Locations,Compiling a context,Function pointers<2>,Topic Reference -@anchor{topics/locations source-locations}@anchor{f4}@anchor{topics/locations doc}@anchor{f5} +@anchor{topics/locations doc}@anchor{f5}@anchor{topics/locations source-locations}@anchor{f6} @section Source Locations @@ -7667,7 +7685,7 @@ on-stack buffer. @end menu @node Faking it,,,Source Locations -@anchor{topics/locations faking-it}@anchor{f6} +@anchor{topics/locations faking-it}@anchor{f7} @subsection Faking it @@ -7703,7 +7721,7 @@ file, giving you @emph{something} you can step through in the debugger. @c . @node Compiling a context,ABI and API compatibility,Source Locations,Topic Reference -@anchor{topics/compilation compiling-a-context}@anchor{f7}@anchor{topics/compilation doc}@anchor{f8} +@anchor{topics/compilation doc}@anchor{f8}@anchor{topics/compilation compiling-a-context}@anchor{f9} @section Compiling a context @@ -7722,7 +7740,7 @@ prevent any future compilation of that context. @end menu @node In-memory compilation,Ahead-of-time compilation,,Compiling a context -@anchor{topics/compilation in-memory-compilation}@anchor{f9} +@anchor{topics/compilation in-memory-compilation}@anchor{fa} @subsection In-memory compilation @@ -7842,7 +7860,7 @@ by calling @ref{17,,gcc_jit_result_get_code()} or @end deffn @node Ahead-of-time compilation,,In-memory compilation,Compiling a context -@anchor{topics/compilation ahead-of-time-compilation}@anchor{fa} +@anchor{topics/compilation ahead-of-time-compilation}@anchor{fb} @subsection Ahead-of-time compilation @@ -7871,7 +7889,7 @@ suffix of the output file when determining what to do. @end cartouche @geindex gcc_jit_output_kind (C type) -@anchor{topics/compilation c gcc_jit_output_kind}@anchor{fb} +@anchor{topics/compilation c gcc_jit_output_kind}@anchor{fc} @deffn {C Type} enum gcc_jit_output_kind @end deffn @@ -7889,7 +7907,7 @@ Typical suffix @item -@ref{fc,,GCC_JIT_OUTPUT_KIND_ASSEMBLER} +@ref{fd,,GCC_JIT_OUTPUT_KIND_ASSEMBLER} @tab @@ -7897,7 +7915,7 @@ Typical suffix @item -@ref{fd,,GCC_JIT_OUTPUT_KIND_OBJECT_FILE} +@ref{fe,,GCC_JIT_OUTPUT_KIND_OBJECT_FILE} @tab @@ -7905,7 +7923,7 @@ Typical suffix @item -@ref{fe,,GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY} +@ref{ff,,GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY} @tab @@ -7913,7 +7931,7 @@ Typical suffix @item -@ref{ff,,GCC_JIT_OUTPUT_KIND_EXECUTABLE} +@ref{100,,GCC_JIT_OUTPUT_KIND_EXECUTABLE} @tab @@ -7923,21 +7941,21 @@ None, or .exe @geindex GCC_JIT_OUTPUT_KIND_ASSEMBLER (C macro) -@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_ASSEMBLER}@anchor{fc} +@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_ASSEMBLER}@anchor{fd} @deffn {C Macro} GCC_JIT_OUTPUT_KIND_ASSEMBLER Compile the context to an assembler file. @end deffn @geindex GCC_JIT_OUTPUT_KIND_OBJECT_FILE (C macro) -@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_OBJECT_FILE}@anchor{fd} +@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_OBJECT_FILE}@anchor{fe} @deffn {C Macro} GCC_JIT_OUTPUT_KIND_OBJECT_FILE Compile the context to an object file. @end deffn @geindex GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY (C macro) -@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}@anchor{fe} +@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}@anchor{ff} @deffn {C Macro} GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY Compile the context to a dynamic library. @@ -7947,7 +7965,7 @@ against. @end deffn @geindex GCC_JIT_OUTPUT_KIND_EXECUTABLE (C macro) -@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_EXECUTABLE}@anchor{ff} +@anchor{topics/compilation c GCC_JIT_OUTPUT_KIND_EXECUTABLE}@anchor{100} @deffn {C Macro} GCC_JIT_OUTPUT_KIND_EXECUTABLE Compile the context to an executable. @@ -7974,7 +7992,7 @@ against. @c . @node ABI and API compatibility,Performance,Compiling a context,Topic Reference -@anchor{topics/compatibility abi-and-api-compatibility}@anchor{100}@anchor{topics/compatibility doc}@anchor{101} +@anchor{topics/compatibility doc}@anchor{101}@anchor{topics/compatibility abi-and-api-compatibility}@anchor{102} @section ABI and API compatibility @@ -8030,21 +8048,21 @@ Version definitions: @end menu @node Programmatically checking version,ABI symbol tags,,ABI and API compatibility -@anchor{topics/compatibility programmatically-checking-version}@anchor{102} +@anchor{topics/compatibility programmatically-checking-version}@anchor{103} @subsection Programmatically checking version Client code can programmatically check libgccjit version using: @geindex gcc_jit_version_major (C function) -@anchor{topics/compatibility c gcc_jit_version_major}@anchor{103} +@anchor{topics/compatibility c gcc_jit_version_major}@anchor{104} @deffn {C Function} int gcc_jit_version_major (void) Return libgccjit major version. This is analogous to __GNUC__ in C code. @end deffn @geindex gcc_jit_version_minor (C function) -@anchor{topics/compatibility c gcc_jit_version_minor}@anchor{104} +@anchor{topics/compatibility c gcc_jit_version_minor}@anchor{105} @deffn {C Function} int gcc_jit_version_minor (void) Return libgccjit minor version. This is analogous to @@ -8052,7 +8070,7 @@ __GNUC_MINOR__ in C code. @end deffn @geindex gcc_jit_version_patchlevel (C function) -@anchor{topics/compatibility c gcc_jit_version_patchlevel}@anchor{105} +@anchor{topics/compatibility c gcc_jit_version_patchlevel}@anchor{106} @deffn {C Function} int gcc_jit_version_patchlevel (void) Return libgccjit patchlevel version. This is analogous to @@ -8067,7 +8085,7 @@ These entry points has been added with @code{LIBGCCJIT_ABI_13} @end cartouche @node ABI symbol tags,,Programmatically checking version,ABI and API compatibility -@anchor{topics/compatibility abi-symbol-tags}@anchor{106} +@anchor{topics/compatibility abi-symbol-tags}@anchor{107} @subsection ABI symbol tags @@ -8091,11 +8109,12 @@ Newer releases use the following tags. * LIBGCCJIT_ABI_12:: * LIBGCCJIT_ABI_13:: * LIBGCCJIT_ABI_14:: +* LIBGCCJIT_ABI_15:: @end menu @node LIBGCCJIT_ABI_0,LIBGCCJIT_ABI_1,,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-0}@anchor{107}@anchor{topics/compatibility id1}@anchor{108} +@anchor{topics/compatibility id1}@anchor{108}@anchor{topics/compatibility libgccjit-abi-0}@anchor{109} @subsubsection @code{LIBGCCJIT_ABI_0} @@ -8107,7 +8126,7 @@ continue to work, with this being handled transparently by the linker (see this post@footnote{https://gcc.gnu.org/ml/gcc-patches/2015-06/msg02126.html}) @node LIBGCCJIT_ABI_1,LIBGCCJIT_ABI_2,LIBGCCJIT_ABI_0,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-1}@anchor{73}@anchor{topics/compatibility id2}@anchor{109} +@anchor{topics/compatibility id2}@anchor{10a}@anchor{topics/compatibility libgccjit-abi-1}@anchor{73} @subsubsection @code{LIBGCCJIT_ABI_1} @@ -8115,7 +8134,7 @@ continue to work, with this being handled transparently by the linker @ref{72,,gcc_jit_context_add_command_line_option()} @node LIBGCCJIT_ABI_2,LIBGCCJIT_ABI_3,LIBGCCJIT_ABI_1,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-2}@anchor{6c}@anchor{topics/compatibility id3}@anchor{10a} +@anchor{topics/compatibility id3}@anchor{10b}@anchor{topics/compatibility libgccjit-abi-2}@anchor{6c} @subsubsection @code{LIBGCCJIT_ABI_2} @@ -8123,7 +8142,7 @@ continue to work, with this being handled transparently by the linker @ref{6b,,gcc_jit_context_set_bool_allow_unreachable_blocks()} @node LIBGCCJIT_ABI_3,LIBGCCJIT_ABI_4,LIBGCCJIT_ABI_2,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-3}@anchor{ef}@anchor{topics/compatibility id4}@anchor{10b} +@anchor{topics/compatibility id4}@anchor{10c}@anchor{topics/compatibility libgccjit-abi-3}@anchor{ef} @subsubsection @code{LIBGCCJIT_ABI_3} @@ -8147,7 +8166,7 @@ entrypoints: @end quotation @node LIBGCCJIT_ABI_4,LIBGCCJIT_ABI_5,LIBGCCJIT_ABI_3,ABI symbol tags -@anchor{topics/compatibility id5}@anchor{10c}@anchor{topics/compatibility libgccjit-abi-4}@anchor{10d} +@anchor{topics/compatibility id5}@anchor{10d}@anchor{topics/compatibility libgccjit-abi-4}@anchor{10e} @subsubsection @code{LIBGCCJIT_ABI_4} @@ -8160,30 +8179,30 @@ entrypoints: @itemize * @item -@ref{10e,,gcc_jit_context_get_timer()} +@ref{10f,,gcc_jit_context_get_timer()} @item -@ref{10f,,gcc_jit_context_set_timer()} +@ref{110,,gcc_jit_context_set_timer()} @item -@ref{110,,gcc_jit_timer_new()} +@ref{111,,gcc_jit_timer_new()} @item -@ref{111,,gcc_jit_timer_release()} +@ref{112,,gcc_jit_timer_release()} @item -@ref{112,,gcc_jit_timer_push()} +@ref{113,,gcc_jit_timer_push()} @item -@ref{113,,gcc_jit_timer_pop()} +@ref{114,,gcc_jit_timer_pop()} @item -@ref{114,,gcc_jit_timer_print()} +@ref{115,,gcc_jit_timer_print()} @end itemize @end quotation @node LIBGCCJIT_ABI_5,LIBGCCJIT_ABI_6,LIBGCCJIT_ABI_4,ABI symbol tags -@anchor{topics/compatibility id6}@anchor{115}@anchor{topics/compatibility libgccjit-abi-5}@anchor{6e} +@anchor{topics/compatibility id6}@anchor{116}@anchor{topics/compatibility libgccjit-abi-5}@anchor{6e} @subsubsection @code{LIBGCCJIT_ABI_5} @@ -8191,7 +8210,7 @@ entrypoints: @ref{6d,,gcc_jit_context_set_bool_use_external_driver()} @node LIBGCCJIT_ABI_6,LIBGCCJIT_ABI_7,LIBGCCJIT_ABI_5,ABI symbol tags -@anchor{topics/compatibility id7}@anchor{116}@anchor{topics/compatibility libgccjit-abi-6}@anchor{be} +@anchor{topics/compatibility id7}@anchor{117}@anchor{topics/compatibility libgccjit-abi-6}@anchor{be} @subsubsection @code{LIBGCCJIT_ABI_6} @@ -8199,7 +8218,7 @@ entrypoints: @ref{bd,,gcc_jit_rvalue_set_bool_require_tail_call()} @node LIBGCCJIT_ABI_7,LIBGCCJIT_ABI_8,LIBGCCJIT_ABI_6,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-7}@anchor{83}@anchor{topics/compatibility id8}@anchor{117} +@anchor{topics/compatibility id8}@anchor{118}@anchor{topics/compatibility libgccjit-abi-7}@anchor{83} @subsubsection @code{LIBGCCJIT_ABI_7} @@ -8207,7 +8226,7 @@ entrypoints: @ref{82,,gcc_jit_type_get_aligned()} @node LIBGCCJIT_ABI_8,LIBGCCJIT_ABI_9,LIBGCCJIT_ABI_7,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-8}@anchor{86}@anchor{topics/compatibility id9}@anchor{118} +@anchor{topics/compatibility id9}@anchor{119}@anchor{topics/compatibility libgccjit-abi-8}@anchor{86} @subsubsection @code{LIBGCCJIT_ABI_8} @@ -8215,7 +8234,7 @@ entrypoints: @ref{85,,gcc_jit_type_get_vector()} @node LIBGCCJIT_ABI_9,LIBGCCJIT_ABI_10,LIBGCCJIT_ABI_8,ABI symbol tags -@anchor{topics/compatibility id10}@anchor{119}@anchor{topics/compatibility libgccjit-abi-9}@anchor{f3} +@anchor{topics/compatibility id10}@anchor{11a}@anchor{topics/compatibility libgccjit-abi-9}@anchor{f4} @subsubsection @code{LIBGCCJIT_ABI_9} @@ -8223,7 +8242,7 @@ entrypoints: @ref{c0,,gcc_jit_function_get_address()} @node LIBGCCJIT_ABI_10,LIBGCCJIT_ABI_11,LIBGCCJIT_ABI_9,ABI symbol tags -@anchor{topics/compatibility id11}@anchor{11a}@anchor{topics/compatibility libgccjit-abi-10}@anchor{a0} +@anchor{topics/compatibility id11}@anchor{11b}@anchor{topics/compatibility libgccjit-abi-10}@anchor{a0} @subsubsection @code{LIBGCCJIT_ABI_10} @@ -8231,7 +8250,7 @@ entrypoints: @ref{87,,gcc_jit_context_new_rvalue_from_vector()} @node LIBGCCJIT_ABI_11,LIBGCCJIT_ABI_12,LIBGCCJIT_ABI_10,ABI symbol tags -@anchor{topics/compatibility id12}@anchor{11b}@anchor{topics/compatibility libgccjit-abi-11}@anchor{75} +@anchor{topics/compatibility id12}@anchor{11c}@anchor{topics/compatibility libgccjit-abi-11}@anchor{75} @subsubsection @code{LIBGCCJIT_ABI_11} @@ -8239,7 +8258,7 @@ entrypoints: @ref{74,,gcc_jit_context_add_driver_option()} @node LIBGCCJIT_ABI_12,LIBGCCJIT_ABI_13,LIBGCCJIT_ABI_11,ABI symbol tags -@anchor{topics/compatibility id13}@anchor{11c}@anchor{topics/compatibility libgccjit-abi-12}@anchor{8d} +@anchor{topics/compatibility id13}@anchor{11d}@anchor{topics/compatibility libgccjit-abi-12}@anchor{8d} @subsubsection @code{LIBGCCJIT_ABI_12} @@ -8247,7 +8266,7 @@ entrypoints: @ref{8c,,gcc_jit_context_new_bitfield()} @node LIBGCCJIT_ABI_13,LIBGCCJIT_ABI_14,LIBGCCJIT_ABI_12,ABI symbol tags -@anchor{topics/compatibility id14}@anchor{11d}@anchor{topics/compatibility libgccjit-abi-13}@anchor{11e} +@anchor{topics/compatibility id14}@anchor{11e}@anchor{topics/compatibility libgccjit-abi-13}@anchor{11f} @subsubsection @code{LIBGCCJIT_ABI_13} @@ -8260,24 +8279,66 @@ entrypoints: @itemize * @item -@ref{103,,gcc_jit_version_major()} +@ref{104,,gcc_jit_version_major()} @item -@ref{104,,gcc_jit_version_minor()} +@ref{105,,gcc_jit_version_minor()} @item -@ref{105,,gcc_jit_version_patchlevel()} +@ref{106,,gcc_jit_version_patchlevel()} @end itemize @end quotation -@node LIBGCCJIT_ABI_14,,LIBGCCJIT_ABI_13,ABI symbol tags -@anchor{topics/compatibility libgccjit-abi-14}@anchor{cf}@anchor{topics/compatibility id15}@anchor{11f} +@node LIBGCCJIT_ABI_14,LIBGCCJIT_ABI_15,LIBGCCJIT_ABI_13,ABI symbol tags +@anchor{topics/compatibility id15}@anchor{120}@anchor{topics/compatibility libgccjit-abi-14}@anchor{cf} @subsubsection @code{LIBGCCJIT_ABI_14} @code{LIBGCCJIT_ABI_14} covers the addition of @ref{ce,,gcc_jit_global_set_initializer()} +@node LIBGCCJIT_ABI_15,,LIBGCCJIT_ABI_14,ABI symbol tags +@anchor{topics/compatibility id16}@anchor{121}@anchor{topics/compatibility libgccjit-abi-15}@anchor{122} +@subsubsection @code{LIBGCCJIT_ABI_15} + + +@code{LIBGCCJIT_ABI_15} covers the addition of API entrypoints for directly +embedding assembler instructions: + +@quotation + + +@itemize * + +@item +@ref{123,,gcc_jit_block_add_extended_asm()} + +@item +@ref{124,,gcc_jit_block_end_with_extended_asm_goto()} + +@item +@ref{125,,gcc_jit_extended_asm_as_object()} + +@item +@ref{126,,gcc_jit_extended_asm_set_volatile_flag()} + +@item +@ref{127,,gcc_jit_extended_asm_set_inline_flag()} + +@item +@ref{128,,gcc_jit_extended_asm_add_output_operand()} + +@item +@ref{129,,gcc_jit_extended_asm_add_input_operand()} + +@item +@ref{12a,,gcc_jit_extended_asm_add_clobber()} + +@item +@ref{12b,,gcc_jit_context_add_top_level_asm()} +@end itemize +@end quotation + @c Copyright (C) 2015-2020 Free Software Foundation, Inc. @c Originally contributed by David Malcolm @c @@ -8295,8 +8356,8 @@ entrypoints: @c along with this program. If not, see @c . -@node Performance,,ABI and API compatibility,Topic Reference -@anchor{topics/performance performance}@anchor{120}@anchor{topics/performance doc}@anchor{121} +@node Performance,Using Assembly Language with libgccjit,ABI and API compatibility,Topic Reference +@anchor{topics/performance doc}@anchor{12c}@anchor{topics/performance performance}@anchor{12d} @section Performance @@ -8306,14 +8367,14 @@ entrypoints: @end menu @node The timing API,,,Performance -@anchor{topics/performance the-timing-api}@anchor{122} +@anchor{topics/performance the-timing-api}@anchor{12e} @subsection The timing API As of GCC 6, libgccjit exposes a timing API, for printing reports on how long was spent in different parts of code. -You can create a @ref{123,,gcc_jit_timer} instance, which will +You can create a @ref{12f,,gcc_jit_timer} instance, which will measure time spent since its creation. The timer maintains a stack of “timer items”: as control flow moves through your code, you can push and pop named items relating to your code onto the stack, and the timer @@ -8411,7 +8472,7 @@ Client items: The exact format is intended to be human-readable, and is subject to change. @geindex LIBGCCJIT_HAVE_TIMING_API (C macro) -@anchor{topics/performance c LIBGCCJIT_HAVE_TIMING_API}@anchor{124} +@anchor{topics/performance c LIBGCCJIT_HAVE_TIMING_API}@anchor{130} @deffn {C Macro} LIBGCCJIT_HAVE_TIMING_API The timer API was added to libgccjit in GCC 6. @@ -8428,21 +8489,21 @@ gcc_jit_context_set_timer (ctxt, t); @end deffn @geindex gcc_jit_timer (C type) -@anchor{topics/performance c gcc_jit_timer}@anchor{123} +@anchor{topics/performance c gcc_jit_timer}@anchor{12f} @deffn {C Type} gcc_jit_timer @end deffn @geindex gcc_jit_timer_new (C function) -@anchor{topics/performance c gcc_jit_timer_new}@anchor{110} +@anchor{topics/performance c gcc_jit_timer_new}@anchor{111} @deffn {C Function} gcc_jit_timer * gcc_jit_timer_new (void) -Create a @ref{123,,gcc_jit_timer} instance, and start timing: +Create a @ref{12f,,gcc_jit_timer} instance, and start timing: @example gcc_jit_timer *t = gcc_jit_timer_new (); @end example -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8451,10 +8512,10 @@ for its presence using @end deffn @geindex gcc_jit_timer_release (C function) -@anchor{topics/performance c gcc_jit_timer_release}@anchor{111} +@anchor{topics/performance c gcc_jit_timer_release}@anchor{112} @deffn {C Function} void gcc_jit_timer_release (gcc_jit_timer@w{ }*timer) -Release a @ref{123,,gcc_jit_timer} instance: +Release a @ref{12f,,gcc_jit_timer} instance: @example gcc_jit_timer_release (t); @@ -8462,7 +8523,7 @@ gcc_jit_timer_release (t); This should be called exactly once on a timer. -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8471,10 +8532,10 @@ for its presence using @end deffn @geindex gcc_jit_context_set_timer (C function) -@anchor{topics/performance c gcc_jit_context_set_timer}@anchor{10f} +@anchor{topics/performance c gcc_jit_context_set_timer}@anchor{110} @deffn {C Function} void gcc_jit_context_set_timer (gcc_jit_context@w{ }*ctxt, gcc_jit_timer@w{ }*timer) -Associate a @ref{123,,gcc_jit_timer} instance with a context: +Associate a @ref{12f,,gcc_jit_timer} instance with a context: @example gcc_jit_context_set_timer (ctxt, t); @@ -8487,7 +8548,7 @@ Timers have no locking, so if you have a multithreaded program, you must provide your own locks if more than one thread could be working with the same timer via timer-associated contexts. -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8496,12 +8557,12 @@ for its presence using @end deffn @geindex gcc_jit_context_get_timer (C function) -@anchor{topics/performance c gcc_jit_context_get_timer}@anchor{10e} +@anchor{topics/performance c gcc_jit_context_get_timer}@anchor{10f} @deffn {C Function} gcc_jit_timer *gcc_jit_context_get_timer (gcc_jit_context@w{ }*ctxt) Get the timer associated with a context (if any). -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8510,7 +8571,7 @@ for its presence using @end deffn @geindex gcc_jit_timer_push (C function) -@anchor{topics/performance c gcc_jit_timer_push}@anchor{112} +@anchor{topics/performance c gcc_jit_timer_push}@anchor{113} @deffn {C Function} void gcc_jit_timer_push (gcc_jit_timer@w{ }*timer, const char@w{ }*item_name) Push the given item onto the timer’s stack: @@ -8521,7 +8582,7 @@ run_the_code (ctxt, result); gcc_jit_timer_pop (t, "running code"); @end example -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8530,7 +8591,7 @@ for its presence using @end deffn @geindex gcc_jit_timer_pop (C function) -@anchor{topics/performance c gcc_jit_timer_pop}@anchor{113} +@anchor{topics/performance c gcc_jit_timer_pop}@anchor{114} @deffn {C Function} void gcc_jit_timer_pop (gcc_jit_timer@w{ }*timer, const char@w{ }*item_name) Pop the top item from the timer’s stack. @@ -8538,7 +8599,7 @@ Pop the top item from the timer’s stack. If “item_name” is provided, it must match that of the top item. Alternatively, @code{NULL} can be passed in, to suppress checking. -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8547,13 +8608,13 @@ for its presence using @end deffn @geindex gcc_jit_timer_print (C function) -@anchor{topics/performance c gcc_jit_timer_print}@anchor{114} +@anchor{topics/performance c gcc_jit_timer_print}@anchor{115} @deffn {C Function} void gcc_jit_timer_print (gcc_jit_timer@w{ }*timer, FILE@w{ }*f_out) Print timing information to the given stream about activity since the timer was started. -This API entrypoint was added in @ref{10d,,LIBGCCJIT_ABI_4}; you can test +This API entrypoint was added in @ref{10e,,LIBGCCJIT_ABI_4}; you can test for its presence using @example @@ -8561,6 +8622,403 @@ for its presence using @end example @end deffn +@c Copyright (C) 2020 Free Software Foundation, Inc. +@c Originally contributed by David Malcolm +@c +@c This is free software: you can redistribute it and/or modify it +@c under the terms of the GNU General Public License as published by +@c the Free Software Foundation, either version 3 of the License, or +@c (at your option) any later version. +@c +@c This program is distributed in the hope that it will be useful, but +@c WITHOUT ANY WARRANTY; without even the implied warranty of +@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +@c General Public License for more details. +@c +@c You should have received a copy of the GNU General Public License +@c along with this program. If not, see +@c . + +@node Using Assembly Language with libgccjit,,Performance,Topic Reference +@anchor{topics/asm doc}@anchor{131}@anchor{topics/asm using-assembly-language-with-libgccjit}@anchor{132} +@section Using Assembly Language with libgccjit + + +libgccjit has some support for directly embedding assembler instructions. +This is based on GCC’s support for inline @code{asm} in C code, and the +following assumes a familiarity with that functionality. See +How to Use Inline Assembly Language in C Code@footnote{https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html} +in GCC’s documentation, the “Extended Asm” section in particular. + +These entrypoints were added in @ref{122,,LIBGCCJIT_ABI_15}; you can test +for their presence using + +@quotation + +@example +#ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS +@end example +@end quotation + +@menu +* Adding assembler instructions within a function:: +* Adding top-level assembler statements:: + +@end menu + +@node Adding assembler instructions within a function,Adding top-level assembler statements,,Using Assembly Language with libgccjit +@anchor{topics/asm adding-assembler-instructions-within-a-function}@anchor{133} +@subsection Adding assembler instructions within a function + + +@geindex gcc_jit_extended_asm (C type) +@anchor{topics/asm c gcc_jit_extended_asm}@anchor{f1} +@deffn {C Type} gcc_jit_extended_asm + +A @cite{gcc_jit_extended_asm} represents an extended @code{asm} statement: a +series of low-level instructions inside a function that convert inputs +to outputs. + +To avoid having an API entrypoint with a very large number of +parameters, an extended @code{asm} statement is made in stages: +an initial call to create the @ref{f1,,gcc_jit_extended_asm}, +followed by calls to add operands and set other properties of the +statement. + +There are two API entrypoints for creating a @ref{f1,,gcc_jit_extended_asm}: + + +@itemize * + +@item +@ref{123,,gcc_jit_block_add_extended_asm()} for an @code{asm} statement with +no control flow, and + +@item +@ref{124,,gcc_jit_block_end_with_extended_asm_goto()} for an @code{asm goto}. +@end itemize + +For example, to create the equivalent of: + +@example + asm ("mov %1, %0\n\t" + "add $1, %0" + : "=r" (dst) + : "r" (src)); +@end example + +the following API calls could be used: + +@example + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_add_extended_asm (block, NULL, + "mov %1, %0\n\t" + "add $1, %0"); + gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_lvalue_as_rvalue (src)); +@end example + +@cartouche +@quotation Warning +When considering the numbering of operands within an +extended @code{asm} statement (e.g. the @code{%0} and @code{%1} +above), the equivalent to the C syntax is followed i.e. all +output operands, then all input operands, regardless of +what order the calls to +@ref{128,,gcc_jit_extended_asm_add_output_operand()} and +@ref{129,,gcc_jit_extended_asm_add_input_operand()} were made in. +@end quotation +@end cartouche + +As in the C syntax, operands can be given symbolic names to avoid having +to number them. For example, to create the equivalent of: + +@example + asm ("bsfl %[aMask], %[aIndex]" + : [aIndex] "=r" (Index) + : [aMask] "r" (Mask) + : "cc"); +@end example + +the following API calls could be used: + +@example + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_add_extended_asm (block, NULL, + "bsfl %[aMask], %[aIndex]"); + gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index); + gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", + gcc_jit_param_as_rvalue (mask)); + gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); +@end example +@end deffn + +@geindex gcc_jit_block_add_extended_asm (C function) +@anchor{topics/asm c gcc_jit_block_add_extended_asm}@anchor{123} +@deffn {C Function} gcc_jit_extended_asm * gcc_jit_block_add_extended_asm (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*asm_template) + +Create a @ref{f1,,gcc_jit_extended_asm} for an extended @code{asm} statement +with no control flow (i.e. without the @code{goto} qualifier). + +The parameter @code{asm_template} corresponds to the @cite{AssemblerTemplate} +within C’s extended @code{asm} syntax. It must be non-NULL. The call takes +a copy of the underlying string, so it is valid to pass in a pointer to +an on-stack buffer. +@end deffn + +@geindex gcc_jit_block_end_with_extended_asm_goto (C function) +@anchor{topics/asm c gcc_jit_block_end_with_extended_asm_goto}@anchor{124} +@deffn {C Function} gcc_jit_extended_asm * gcc_jit_block_end_with_extended_asm_goto (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*asm_template, int@w{ }num_goto_blocks, gcc_jit_block@w{ }**goto_blocks, gcc_jit_block@w{ }*fallthrough_block) + +Create a @ref{f1,,gcc_jit_extended_asm} for an extended @code{asm} statement +that may perform jumps, and use it to terminate the given block. +This is equivalent to the @code{goto} qualifier in C’s extended @code{asm} +syntax. + +For example, to create the equivalent of: + +@example + asm goto ("btl %1, %0\n\t" + "jc %l[carry]" + : // No outputs + : "r" (p1), "r" (p2) + : "cc" + : carry); +@end example + +the following API calls could be used: + +@example + const char *asm_template = + (use_name + ? /* Label referred to by name: "%l[carry]". */ + ("btl %1, %0\n\t" + "jc %l[carry]") + : /* Label referred to numerically: "%l2". */ + ("btl %1, %0\n\t" + "jc %l2")); + + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_end_with_extended_asm_goto (b_start, NULL, + asm_template, + 1, &b_carry, + b_fallthru); + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_param_as_rvalue (p1)); + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_param_as_rvalue (p2)); + gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); +@end example + +here referencing a @ref{28,,gcc_jit_block} named “carry”. + +@code{num_goto_blocks} must be >= 0. + +@code{goto_blocks} must be non-NULL. This corresponds to the @code{GotoLabels} +parameter within C’s extended @code{asm} syntax. The block names can be +referenced within the assembler template. + +@code{fallthrough_block} can be NULL. If non-NULL, it specifies the block +to fall through to after the statement. + +@cartouche +@quotation Note +This is needed since each @ref{28,,gcc_jit_block} must have a +single exit point, as a basic block: you can’t jump from the +middle of a block. A “goto” is implicitly added after the +asm to handle the fallthrough case, which is equivalent to what +would have happened in the C case. +@end quotation +@end cartouche +@end deffn + +@geindex gcc_jit_extended_asm_set_volatile_flag (C function) +@anchor{topics/asm c gcc_jit_extended_asm_set_volatile_flag}@anchor{126} +@deffn {C Function} void gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm@w{ }*ext_asm, int@w{ }flag) + +Set whether the @ref{f1,,gcc_jit_extended_asm} has side-effects, equivalent to the +volatile@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile} +qualifier in C’s extended asm syntax. + +For example, to create the equivalent of: + +@example +asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (msr) + : + : "rdx"); +@end example + +the following API calls could be used: + +@example + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_add_extended_asm + (block, NULL, + "rdtsc\n\t" /* Returns the time in EDX:EAX. */ + "shl $32, %%rdx\n\t" /* Shift the upper bits left. */ + "or %%rdx, %0"); /* 'Or' in the lower bits. */ + gcc_jit_extended_asm_set_volatile_flag (ext_asm, 1); + gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=a", msr); + gcc_jit_extended_asm_add_clobber (ext_asm, "rdx"); +@end example + +where the @ref{f1,,gcc_jit_extended_asm} is flagged as volatile. +@end deffn + +@geindex gcc_jit_extended_asm_set_inline_flag (C function) +@anchor{topics/asm c gcc_jit_extended_asm_set_inline_flag}@anchor{127} +@deffn {C Function} void gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm@w{ }*ext_asm, int@w{ }flag) + +Set the equivalent of the +inline@footnote{https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html#Size-of-an-asm} +qualifier in C’s extended @code{asm} syntax. +@end deffn + +@geindex gcc_jit_extended_asm_add_output_operand (C function) +@anchor{topics/asm c gcc_jit_extended_asm_add_output_operand}@anchor{128} +@deffn {C Function} void gcc_jit_extended_asm_add_output_operand (gcc_jit_extended_asm@w{ }*ext_asm, const char@w{ }*asm_symbolic_name, const char@w{ }*constraint, gcc_jit_lvalue@w{ }*dest) + +Add an output operand to the extended @code{asm} statement. See the +Output Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands} +section of the documentation of the C syntax. + +@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component of C’s +extended @code{asm} syntax. It can be NULL. If non-NULL it specifies the +symbolic name for the operand. + +@code{constraint} corresponds to the @code{constraint} component of C’s extended +@code{asm} syntax. It must be non-NULL. + +@code{dest} corresponds to the @code{cvariablename} component of C’s extended +@code{asm} syntax. It must be non-NULL. + +@example +// Example with a NULL symbolic name, the equivalent of: +// : "=r" (dst) +gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); + +// Example with a symbolic name ("aIndex"), the equivalent of: +// : [aIndex] "=r" (index) +gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index); +@end example + +This function can’t be called on an @code{asm goto} as such instructions can’t +have outputs; see the +Goto Labels@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels} +section of GCC’s “Extended Asm” documentation. +@end deffn + +@geindex gcc_jit_extended_asm_add_input_operand (C function) +@anchor{topics/asm c gcc_jit_extended_asm_add_input_operand}@anchor{129} +@deffn {C Function} void gcc_jit_extended_asm_add_input_operand (gcc_jit_extended_asm@w{ }*ext_asm, const char@w{ }*asm_symbolic_name, const char@w{ }*constraint, gcc_jit_rvalue@w{ }*src) + +Add an input operand to the extended @code{asm} statement. See the +Input Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands} +section of the documentation of the C syntax. + +@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component of C’s +extended @code{asm} syntax. It can be NULL. If non-NULL it specifies the +symbolic name for the operand. + +@code{constraint} corresponds to the @code{constraint} component of C’s extended +@code{asm} syntax. It must be non-NULL. + +@code{src} corresponds to the @code{cexpression} component of C’s extended +@code{asm} syntax. It must be non-NULL. + +@example +// Example with a NULL symbolic name, the equivalent of: +// : "r" (src) +gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_lvalue_as_rvalue (src)); + +// Example with a symbolic name ("aMask"), the equivalent of: +// : [aMask] "r" (Mask) +gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", + gcc_jit_lvalue_as_rvalue (mask)); +@end example +@end deffn + +@geindex gcc_jit_extended_asm_add_clobber (C function) +@anchor{topics/asm c gcc_jit_extended_asm_add_clobber}@anchor{12a} +@deffn {C Function} void gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm@w{ }*ext_asm, const char@w{ }*victim) + +Add @cite{victim} to the list of registers clobbered by the extended @code{asm} +statement. It must be non-NULL. See the +Clobbers and Scratch Registers@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers#} +section of the documentation of the C syntax. + +Statements with multiple clobbers will require multiple calls, one per +clobber. + +For example: + +@example +gcc_jit_extended_asm_add_clobber (ext_asm, "r0"); +gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); +gcc_jit_extended_asm_add_clobber (ext_asm, "memory"); +@end example +@end deffn + +A @ref{f1,,gcc_jit_extended_asm} is a @ref{e,,gcc_jit_object} “owned” by +the block’s context. The following upcast is available: + +@geindex gcc_jit_extended_asm_as_object (C function) +@anchor{topics/asm c gcc_jit_extended_asm_as_object}@anchor{125} +@deffn {C Function} gcc_jit_object * gcc_jit_extended_asm_as_object (gcc_jit_extended_asm@w{ }*ext_asm) + +Upcast from extended @code{asm} to object. +@end deffn + +@node Adding top-level assembler statements,,Adding assembler instructions within a function,Using Assembly Language with libgccjit +@anchor{topics/asm adding-top-level-assembler-statements}@anchor{134} +@subsection Adding top-level assembler statements + + +In addition to creating extended @code{asm} instructions within a function, +there is support for creating “top-level” assembler statements, outside +of any function. + +@geindex gcc_jit_context_add_top_level_asm (C function) +@anchor{topics/asm c gcc_jit_context_add_top_level_asm}@anchor{12b} +@deffn {C Function} void gcc_jit_context_add_top_level_asm (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*asm_stmts) + +Create a set of top-level asm statements, analogous to those created +by GCC’s “basic” @code{asm} syntax in C at file scope. + +For example, to create the equivalent of: + +@example + asm ("\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @@function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t.popsection\n"); +@end example + +the following API calls could be used: + +@example + gcc_jit_context_add_top_level_asm (ctxt, NULL, + "\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @@function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t# some asm here\n" + "\t.popsection\n"); +@end example +@end deffn + @c Copyright (C) 2014-2020 Free Software Foundation, Inc. @c Originally contributed by David Malcolm @c @@ -8579,7 +9037,7 @@ for its presence using @c . @node C++ bindings for libgccjit,Internals,Topic Reference,Top -@anchor{cp/index c-bindings-for-libgccjit}@anchor{125}@anchor{cp/index doc}@anchor{126} +@anchor{cp/index doc}@anchor{135}@anchor{cp/index c-bindings-for-libgccjit}@anchor{136} @chapter C++ bindings for libgccjit @@ -8623,7 +9081,7 @@ Contents: @end menu @node Tutorial<2>,Topic Reference<2>,,C++ bindings for libgccjit -@anchor{cp/intro/index doc}@anchor{127}@anchor{cp/intro/index tutorial}@anchor{128} +@anchor{cp/intro/index doc}@anchor{137}@anchor{cp/intro/index tutorial}@anchor{138} @section Tutorial @@ -8653,7 +9111,7 @@ Contents: @end menu @node Tutorial part 1 “Hello world”<2>,Tutorial part 2 Creating a trivial machine code function<2>,,Tutorial<2> -@anchor{cp/intro/tutorial01 doc}@anchor{129}@anchor{cp/intro/tutorial01 tutorial-part-1-hello-world}@anchor{12a} +@anchor{cp/intro/tutorial01 doc}@anchor{139}@anchor{cp/intro/tutorial01 tutorial-part-1-hello-world}@anchor{13a} @subsection Tutorial part 1: “Hello world” @@ -8816,7 +9274,7 @@ hello world @c . @node Tutorial part 2 Creating a trivial machine code function<2>,Tutorial part 3 Loops and variables<2>,Tutorial part 1 “Hello world”<2>,Tutorial<2> -@anchor{cp/intro/tutorial02 doc}@anchor{12b}@anchor{cp/intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{12c} +@anchor{cp/intro/tutorial02 doc}@anchor{13b}@anchor{cp/intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{13c} @subsection Tutorial part 2: Creating a trivial machine code function @@ -8838,10 +9296,10 @@ First we need to include the relevant header: @end example All state associated with compilation is associated with a -@ref{12d,,gccjit;;context}, which is a thin C++ wrapper around the C API’s +@ref{13d,,gccjit;;context}, which is a thin C++ wrapper around the C API’s @ref{8,,gcc_jit_context *}. -Create one using @ref{12e,,gccjit;;context;;acquire()}: +Create one using @ref{13e,,gccjit;;context;;acquire()}: @example gccjit::context ctxt; @@ -8851,19 +9309,19 @@ ctxt = gccjit::context::acquire (); The JIT library has a system of types. It is statically-typed: every expression is of a specific type, fixed at compile-time. In our example, all of the expressions are of the C @cite{int} type, so let’s obtain this from -the context, as a @ref{12f,,gccjit;;type}, using -@ref{130,,gccjit;;context;;get_type()}: +the context, as a @ref{13f,,gccjit;;type}, using +@ref{140,,gccjit;;context;;get_type()}: @example gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT); @end example -@ref{12f,,gccjit;;type} is an example of a “contextual” object: every -entity in the API is associated with a @ref{12d,,gccjit;;context}. +@ref{13f,,gccjit;;type} is an example of a “contextual” object: every +entity in the API is associated with a @ref{13d,,gccjit;;context}. Memory management is easy: all such “contextual” objects are automatically cleaned up for you when the context is released, using -@ref{131,,gccjit;;context;;release()}: +@ref{141,,gccjit;;context;;release()}: @example ctxt.release (); @@ -8890,9 +9348,9 @@ The C++ class hierarchy within the @code{gccjit} namespace looks like this: +- param @end example -One thing you can do with a @ref{132,,gccjit;;object} is +One thing you can do with a @ref{142,,gccjit;;object} is to ask it for a human-readable description as a @code{std::string}, using -@ref{133,,gccjit;;object;;get_debug_string()}: +@ref{143,,gccjit;;object;;get_debug_string()}: @example printf ("obj: %s\n", obj.get_debug_string ().c_str ()); @@ -8908,7 +9366,7 @@ This is invaluable when debugging. Let’s create the function. To do so, we first need to construct its single parameter, specifying its type and giving it a name, -using @ref{134,,gccjit;;context;;new_param()}: +using @ref{144,,gccjit;;context;;new_param()}: @example gccjit::param param_i = ctxt.new_param (int_type, "i"); @@ -8949,7 +9407,7 @@ gccjit::block block = func.new_block (); Our basic block is relatively simple: it immediately terminates by returning the value of an expression. -We can build the expression using @ref{135,,gccjit;;context;;new_binary_op()}: +We can build the expression using @ref{145,,gccjit;;context;;new_binary_op()}: @example gccjit::rvalue expr = @@ -8958,9 +9416,9 @@ gccjit::rvalue expr = param_i, param_i); @end example -A @ref{136,,gccjit;;rvalue} is another example of a -@ref{132,,gccjit;;object} subclass. As before, we can print it with -@ref{133,,gccjit;;object;;get_debug_string()}. +A @ref{146,,gccjit;;rvalue} is another example of a +@ref{142,,gccjit;;object} subclass. As before, we can print it with +@ref{143,,gccjit;;object;;get_debug_string()}. @example printf ("expr: %s\n", expr.get_debug_string ().c_str ()); @@ -8972,7 +9430,7 @@ giving this output: expr: i * i @end example -Note that @ref{136,,gccjit;;rvalue} provides numerous overloaded operators +Note that @ref{146,,gccjit;;rvalue} provides numerous overloaded operators which can be used to dramatically reduce the amount of typing needed. We can build the above binary operation more directly with this one-liner: @@ -8989,7 +9447,7 @@ block.end_with_return (expr); @end example OK, we’ve populated the context. We can now compile it using -@ref{137,,gccjit;;context;;compile()}: +@ref{147,,gccjit;;context;;compile()}: @example gcc_jit_result *result; @@ -9031,12 +9489,12 @@ result: 25 @end menu @node Options<3>,Full example<3>,,Tutorial part 2 Creating a trivial machine code function<2> -@anchor{cp/intro/tutorial02 options}@anchor{138} +@anchor{cp/intro/tutorial02 options}@anchor{148} @subsubsection Options To get more information on what’s going on, you can set debugging flags -on the context using @ref{139,,gccjit;;context;;set_bool_option()}. +on the context using @ref{149,,gccjit;;context;;set_bool_option()}. @c (I'm deliberately not mentioning @c :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think @@ -9100,7 +9558,7 @@ square: By default, no optimizations are performed, the equivalent of GCC’s @cite{-O0} option. We can turn things up to e.g. @cite{-O3} by calling -@ref{13a,,gccjit;;context;;set_int_option()} with +@ref{14a,,gccjit;;context;;set_int_option()} with @ref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}: @example @@ -9130,7 +9588,7 @@ square: Naturally this has only a small effect on such a trivial function. @node Full example<3>,,Options<3>,Tutorial part 2 Creating a trivial machine code function<2> -@anchor{cp/intro/tutorial02 full-example}@anchor{13b} +@anchor{cp/intro/tutorial02 full-example}@anchor{14b} @subsubsection Full example @@ -9268,7 +9726,7 @@ result: 25 @c . @node Tutorial part 3 Loops and variables<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>,Tutorial part 2 Creating a trivial machine code function<2>,Tutorial<2> -@anchor{cp/intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{13c}@anchor{cp/intro/tutorial03 doc}@anchor{13d} +@anchor{cp/intro/tutorial03 doc}@anchor{14c}@anchor{cp/intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{14d} @subsection Tutorial part 3: Loops and variables @@ -9317,14 +9775,14 @@ Here’s what the final control flow graph will look like: @float Figure -@image{sum-of-squares,,,image of a control flow graph,png} +@image{libgccjit-figures/sum-of-squares,,,image of a control flow graph,png} @end float @end quotation As before, we include the libgccjit++ header and make a -@ref{12d,,gccjit;;context}. +@ref{13d,,gccjit;;context}. @example #include @@ -9378,18 +9836,18 @@ gccjit::function func = @end menu @node Expressions lvalues and rvalues<2>,Control flow<2>,,Tutorial part 3 Loops and variables<2> -@anchor{cp/intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{13e} +@anchor{cp/intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{14e} @subsubsection Expressions: lvalues and rvalues -The base class of expression is the @ref{136,,gccjit;;rvalue}, +The base class of expression is the @ref{146,,gccjit;;rvalue}, representing an expression that can be on the @emph{right}-hand side of an assignment: a value that can be computed somehow, and assigned @emph{to} a storage area (such as a variable). It has a specific -@ref{12f,,gccjit;;type}. +@ref{13f,,gccjit;;type}. -Anothe important class is @ref{13f,,gccjit;;lvalue}. -A @ref{13f,,gccjit;;lvalue}. is something that can of the @emph{left}-hand +Anothe important class is @ref{14f,,gccjit;;lvalue}. +A @ref{14f,,gccjit;;lvalue}. is something that can of the @emph{left}-hand side of an assignment: a storage area (such as a variable). In other words, every assignment can be thought of as: @@ -9398,8 +9856,8 @@ In other words, every assignment can be thought of as: LVALUE = RVALUE; @end example -Note that @ref{13f,,gccjit;;lvalue} is a subclass of -@ref{136,,gccjit;;rvalue}, where in an assignment of the form: +Note that @ref{14f,,gccjit;;lvalue} is a subclass of +@ref{146,,gccjit;;rvalue}, where in an assignment of the form: @example LVALUE_A = LVALUE_B; @@ -9429,7 +9887,7 @@ gccjit::rvalue expr = gccjit::rvalue expr = param_i * param_i; @end example -which is a @ref{136,,gccjit;;rvalue}, and +which is a @ref{146,,gccjit;;rvalue}, and @end quotation @@ -9437,15 +9895,15 @@ which is a @ref{136,,gccjit;;rvalue}, and @item the various function parameters: @cite{param_i} and @cite{param_n}, instances of -@ref{140,,gccjit;;param}, which is a subclass of @ref{13f,,gccjit;;lvalue} -(and, in turn, of @ref{136,,gccjit;;rvalue}): +@ref{150,,gccjit;;param}, which is a subclass of @ref{14f,,gccjit;;lvalue} +(and, in turn, of @ref{146,,gccjit;;rvalue}): we can both read from and write to function parameters within the body of a function. @end enumerate Our new example has a new kind of expression: we have two local variables. We create them by calling -@ref{141,,gccjit;;function;;new_local()}, supplying a type and a name: +@ref{151,,gccjit;;function;;new_local()}, supplying a type and a name: @example /* Build locals: */ @@ -9453,7 +9911,7 @@ gccjit::lvalue i = func.new_local (the_type, "i"); gccjit::lvalue sum = func.new_local (the_type, "sum"); @end example -These are instances of @ref{13f,,gccjit;;lvalue} - they can be read from +These are instances of @ref{14f,,gccjit;;lvalue} - they can be read from and written to. Note that there is no precanned way to create @emph{and} initialize a variable @@ -9467,7 +9925,7 @@ Instead, having added the local to the function, we have to separately add an assignment of @cite{0} to @cite{local_i} at the beginning of the function. @node Control flow<2>,Visualizing the control flow graph<2>,Expressions lvalues and rvalues<2>,Tutorial part 3 Loops and variables<2> -@anchor{cp/intro/tutorial03 control-flow}@anchor{142} +@anchor{cp/intro/tutorial03 control-flow}@anchor{152} @subsubsection Control flow @@ -9490,8 +9948,8 @@ the body of the loop after the loop terminates (@cite{return sum}) @end enumerate -so we create these as @ref{143,,gccjit;;block} instances within the -@ref{144,,gccjit;;function}: +so we create these as @ref{153,,gccjit;;block} instances within the +@ref{154,,gccjit;;function}: @example gccjit::block b_initial = func.new_block ("initial"); @@ -9504,8 +9962,8 @@ We now populate each block with statements. The entry block @cite{b_initial} consists of initializations followed by a jump to the conditional. We assign @cite{0} to @cite{i} and to @cite{sum}, using -@ref{145,,gccjit;;block;;add_assignment()} to add -an assignment statement, and using @ref{146,,gccjit;;context;;zero()} to get +@ref{155,,gccjit;;block;;add_assignment()} to add +an assignment statement, and using @ref{156,,gccjit;;context;;zero()} to get the constant value @cite{0} for the relevant type for the right-hand side of the assignment: @@ -9526,9 +9984,9 @@ b_initial.end_with_jump (b_loop_cond); The conditional block is equivalent to the line @cite{while (i < n)} from our C example. It contains a single statement: a conditional, which jumps to one of two destination blocks depending on a boolean -@ref{136,,gccjit;;rvalue}, in this case the comparison of @cite{i} and @cite{n}. +@ref{146,,gccjit;;rvalue}, in this case the comparison of @cite{i} and @cite{n}. -We could build the comparison using @ref{147,,gccjit;;context;;new_comparison()}: +We could build the comparison using @ref{157,,gccjit;;context;;new_comparison()}: @example gccjit::rvalue guard = @@ -9537,7 +9995,7 @@ gccjit::rvalue guard = @end example and can then use this to add @cite{b_loop_cond}’s sole statement, via -@ref{148,,gccjit;;block;;end_with_conditional()}: +@ref{158,,gccjit;;block;;end_with_conditional()}: @example b_loop_cond.end_with_conditional (guard, @@ -9545,7 +10003,7 @@ b_loop_cond.end_with_conditional (guard, b_loop_body); // on_false @end example -However @ref{136,,gccjit;;rvalue} has overloaded operators for this, so we +However @ref{146,,gccjit;;rvalue} has overloaded operators for this, so we express the conditional as @example @@ -9565,7 +10023,7 @@ Next, we populate the body of the loop. The C statement @cite{sum += i * i;} is an assignment operation, where an lvalue is modified “in-place”. We use -@ref{149,,gccjit;;block;;add_assignment_op()} to handle these operations: +@ref{159,,gccjit;;block;;add_assignment_op()} to handle these operations: @example /* sum += i * i */ @@ -9589,7 +10047,7 @@ b_loop_body.add_assignment_op (i, @cartouche @quotation Note For numeric constants other than 0 or 1, we could use -@ref{14a,,gccjit;;context;;new_rvalue()}, which has overloads +@ref{15a,,gccjit;;context;;new_rvalue()}, which has overloads for both @code{int} and @code{double}. @end quotation @end cartouche @@ -9655,12 +10113,12 @@ result: 285 @end example @node Visualizing the control flow graph<2>,Full example<4>,Control flow<2>,Tutorial part 3 Loops and variables<2> -@anchor{cp/intro/tutorial03 visualizing-the-control-flow-graph}@anchor{14b} +@anchor{cp/intro/tutorial03 visualizing-the-control-flow-graph}@anchor{15b} @subsubsection Visualizing the control flow graph You can see the control flow graph of a function using -@ref{14c,,gccjit;;function;;dump_to_dot()}: +@ref{15c,,gccjit;;function;;dump_to_dot()}: @example func.dump_to_dot ("/tmp/sum-of-squares.dot"); @@ -9683,14 +10141,14 @@ install it with @cite{yum install python-xdot}): @float Figure -@image{sum-of-squares,,,image of a control flow graph,png} +@image{libgccjit-figures/sum-of-squares,,,image of a control flow graph,png} @end float @end quotation @node Full example<4>,,Visualizing the control flow graph<2>,Tutorial part 3 Loops and variables<2> -@anchor{cp/intro/tutorial03 full-example}@anchor{14d} +@anchor{cp/intro/tutorial03 full-example}@anchor{15d} @subsubsection Full example @@ -9868,7 +10326,7 @@ loop_test returned: 285 @c . @node Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>,,Tutorial part 3 Loops and variables<2>,Tutorial<2> -@anchor{cp/intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{14e}@anchor{cp/intro/tutorial04 doc}@anchor{14f} +@anchor{cp/intro/tutorial04 doc}@anchor{15e}@anchor{cp/intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{15f} @subsection Tutorial part 4: Adding JIT-compilation to a toy interpreter @@ -9890,7 +10348,7 @@ to it. @end menu @node Our toy interpreter<2>,Compiling to machine code<2>,,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 our-toy-interpreter}@anchor{150} +@anchor{cp/intro/tutorial04 our-toy-interpreter}@anchor{160} @subsubsection Our toy interpreter @@ -10292,7 +10750,7 @@ toyvm_function::interpret (int arg, FILE *trace) @end quotation @node Compiling to machine code<2>,Setting things up<2>,Our toy interpreter<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 compiling-to-machine-code}@anchor{151} +@anchor{cp/intro/tutorial04 compiling-to-machine-code}@anchor{161} @subsubsection Compiling to machine code @@ -10362,7 +10820,7 @@ This means our compiler has the following state: @end quotation @node Setting things up<2>,Populating the function<2>,Compiling to machine code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 setting-things-up}@anchor{152} +@anchor{cp/intro/tutorial04 setting-things-up}@anchor{162} @subsubsection Setting things up @@ -10452,7 +10910,7 @@ compilation_state::add_pop (gccjit::block block, @end quotation We will support single-stepping through the generated code in the -debugger, so we need to create @ref{153,,gccjit;;location} instances, one +debugger, so we need to create @ref{163,,gccjit;;location} instances, one per operation in the source code. These will reference the lines of e.g. @code{factorial.toy}. @@ -10512,7 +10970,7 @@ We create the locals within the function. @end quotation @node Populating the function<2>,Verifying the control flow graph<2>,Setting things up<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 populating-the-function}@anchor{154} +@anchor{cp/intro/tutorial04 populating-the-function}@anchor{164} @subsubsection Populating the function @@ -10625,7 +11083,7 @@ stack into @code{y} instead erroneously assigned it to @code{x}, leaving @code{y uninitialized. To track this kind of thing down, we can use -@ref{155,,gccjit;;block;;add_comment()} to add descriptive comments +@ref{165,,gccjit;;block;;add_comment()} to add descriptive comments to the internal representation. This is invaluable when looking through the generated IR for, say @code{factorial}: @@ -10765,14 +11223,14 @@ to the next block. This is analogous to simply incrementing the program counter. @node Verifying the control flow graph<2>,Compiling the context<2>,Populating the function<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 verifying-the-control-flow-graph}@anchor{156} +@anchor{cp/intro/tutorial04 verifying-the-control-flow-graph}@anchor{166} @subsubsection Verifying the control flow graph Having finished looping over the blocks, the context is complete. As before, we can verify that the control flow and statements are sane by -using @ref{14c,,gccjit;;function;;dump_to_dot()}: +using @ref{15c,,gccjit;;function;;dump_to_dot()}: @example fn.dump_to_dot ("/tmp/factorial.dot"); @@ -10787,14 +11245,14 @@ errors in our compiler. @float Figure -@image{factorial,,,image of a control flow graph,png} +@image{libgccjit-figures/factorial,,,image of a control flow graph,png} @end float @end quotation @node Compiling the context<2>,Single-stepping through the generated code<2>,Verifying the control flow graph<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 compiling-the-context}@anchor{157} +@anchor{cp/intro/tutorial04 compiling-the-context}@anchor{167} @subsubsection Compiling the context @@ -10845,7 +11303,7 @@ private: @end quotation @node Single-stepping through the generated code<2>,Examining the generated code<2>,Compiling the context<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 single-stepping-through-the-generated-code}@anchor{158} +@anchor{cp/intro/tutorial04 single-stepping-through-the-generated-code}@anchor{168} @subsubsection Single-stepping through the generated code @@ -10859,14 +11317,14 @@ It’s possible to debug the generated code. To do this we need to both: @item Set up source code locations for our statements, so that we can meaningfully step through the code. We did this above by -calling @ref{159,,gccjit;;context;;new_location()} and using the +calling @ref{169,,gccjit;;context;;new_location()} and using the results. @item Enable the generation of debugging information, by setting @ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the -@ref{12d,,gccjit;;context} via -@ref{139,,gccjit;;context;;set_bool_option()}: +@ref{13d,,gccjit;;context} via +@ref{149,,gccjit;;context;;set_bool_option()}: @example ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1); @@ -10930,14 +11388,14 @@ optimization level in a regular compiler. @end cartouche @node Examining the generated code<2>,Putting it all together<2>,Single-stepping through the generated code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 examining-the-generated-code}@anchor{15a} +@anchor{cp/intro/tutorial04 examining-the-generated-code}@anchor{16a} @subsubsection Examining the generated code How good is the optimized code? We can turn up optimizations, by calling -@ref{13a,,gccjit;;context;;set_int_option()} with +@ref{14a,,gccjit;;context;;set_int_option()} with @ref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}: @example @@ -11105,7 +11563,7 @@ Note that the stack pushing and popping have been eliminated, as has the recursive call (in favor of an iteration). @node Putting it all together<2>,Behind the curtain How does our code get optimized?<2>,Examining the generated code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 putting-it-all-together}@anchor{15b} +@anchor{cp/intro/tutorial04 putting-it-all-together}@anchor{16b} @subsubsection Putting it all together @@ -11136,7 +11594,7 @@ compiler result: 55 @end example @node Behind the curtain How does our code get optimized?<2>,,Putting it all together<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2> -@anchor{cp/intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{15c} +@anchor{cp/intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{16c} @subsubsection Behind the curtain: How does our code get optimized? @@ -11314,7 +11772,7 @@ instr9: @} @end example -Note in the above how all the @ref{143,,gccjit;;block} instances we +Note in the above how all the @ref{153,,gccjit;;block} instances we created have been consolidated into just 3 blocks in GCC’s internal representation: @code{initial}, @code{instr4} and @code{instr9}. @@ -11325,7 +11783,7 @@ representation: @code{initial}, @code{instr4} and @code{instr9}. @end menu @node Optimizing away stack manipulation<2>,Elimination of tail recursion<2>,,Behind the curtain How does our code get optimized?<2> -@anchor{cp/intro/tutorial04 optimizing-away-stack-manipulation}@anchor{15d} +@anchor{cp/intro/tutorial04 optimizing-away-stack-manipulation}@anchor{16d} @subsubsection Optimizing away stack manipulation @@ -11589,7 +12047,7 @@ instr9: @end example @node Elimination of tail recursion<2>,,Optimizing away stack manipulation<2>,Behind the curtain How does our code get optimized?<2> -@anchor{cp/intro/tutorial04 elimination-of-tail-recursion}@anchor{15e} +@anchor{cp/intro/tutorial04 elimination-of-tail-recursion}@anchor{16e} @subsubsection Elimination of tail recursion @@ -11672,7 +12130,7 @@ instr9: @c . @node Topic Reference<2>,,Tutorial<2>,C++ bindings for libgccjit -@anchor{cp/topics/index doc}@anchor{15f}@anchor{cp/topics/index topic-reference}@anchor{160} +@anchor{cp/topics/index doc}@anchor{16f}@anchor{cp/topics/index topic-reference}@anchor{170} @section Topic Reference @@ -11701,26 +12159,27 @@ instr9: * Creating and using functions: Creating and using functions<2>. * Source Locations: Source Locations<2>. * Compiling a context: Compiling a context<2>. +* Using Assembly Language with libgccjit++:: @end menu @node Compilation contexts<2>,Objects<2>,,Topic Reference<2> -@anchor{cp/topics/contexts compilation-contexts}@anchor{161}@anchor{cp/topics/contexts doc}@anchor{162} +@anchor{cp/topics/contexts doc}@anchor{171}@anchor{cp/topics/contexts compilation-contexts}@anchor{172} @subsection Compilation contexts @geindex gccjit;;context (C++ class) -@anchor{cp/topics/contexts _CPPv2N6gccjit7contextE}@anchor{12d}@anchor{cp/topics/contexts gccjit context}@anchor{163} +@anchor{cp/topics/contexts _CPPv4N6gccjit7contextE}@anchor{13d}@anchor{cp/topics/contexts _CPPv3N6gccjit7contextE}@anchor{173}@anchor{cp/topics/contexts _CPPv2N6gccjit7contextE}@anchor{174}@anchor{cp/topics/contexts gccjit context}@anchor{175} @deffn {C++ Class} gccjit::context @end deffn -The top-level of the C++ API is the @ref{12d,,gccjit;;context} type. +The top-level of the C++ API is the @ref{13d,,gccjit;;context} type. -A @ref{12d,,gccjit;;context} instance encapsulates the state of a +A @ref{13d,,gccjit;;context} instance encapsulates the state of a compilation. You can set up options on it, and add types, functions and code. -Invoking @ref{137,,gccjit;;context;;compile()} on it gives you a +Invoking @ref{147,,gccjit;;context;;compile()} on it gives you a @ref{16,,gcc_jit_result *}. It is a thin wrapper around the C API’s @ref{8,,gcc_jit_context *}. @@ -11735,7 +12194,7 @@ It is a thin wrapper around the C API’s @ref{8,,gcc_jit_context *}. @end menu @node Lifetime-management<2>,Thread-safety<2>,,Compilation contexts<2> -@anchor{cp/topics/contexts lifetime-management}@anchor{164} +@anchor{cp/topics/contexts lifetime-management}@anchor{176} @subsubsection Lifetime-management @@ -11744,17 +12203,17 @@ have their lifetime bounded by the context they are created within, and cleanup of such objects is done for you when the context is released. @geindex gccjit;;context;;acquire (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context7acquireEv}@anchor{12e}@anchor{cp/topics/contexts gccjit context acquire}@anchor{165} -@deffn {C++ Function} gccjit::@ref{12d,,context} gccjit::context::acquire () +@anchor{cp/topics/contexts _CPPv4N6gccjit7context7acquireEv}@anchor{13e}@anchor{cp/topics/contexts _CPPv3N6gccjit7context7acquireEv}@anchor{177}@anchor{cp/topics/contexts _CPPv2N6gccjit7context7acquireEv}@anchor{178}@anchor{cp/topics/contexts gccjit context acquire}@anchor{179} +@deffn {C++ Function} gccjit::@ref{13d,,context} gccjit::@ref{13d,,context}::acquire () -This function acquires a new @ref{12d,,gccjit;;context} instance, +This function acquires a new @ref{13d,,gccjit;;context} instance, which is independent of any others that may be present within this process. @end deffn @geindex gccjit;;context;;release (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context7releaseEv}@anchor{131}@anchor{cp/topics/contexts gccjit context release}@anchor{166} -@deffn {C++ Function} void gccjit::context::release () +@anchor{cp/topics/contexts _CPPv4N6gccjit7context7releaseEv}@anchor{141}@anchor{cp/topics/contexts _CPPv3N6gccjit7context7releaseEv}@anchor{17a}@anchor{cp/topics/contexts _CPPv2N6gccjit7context7releaseEv}@anchor{17b}@anchor{cp/topics/contexts gccjit context release}@anchor{17c} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::release () This function releases all resources associated with the given context. Both the context itself and all of its @code{gccjit::object *} @@ -11770,8 +12229,8 @@ ctxt.release (); @end deffn @geindex gccjit;;context;;new_child_context (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context17new_child_contextEv}@anchor{167}@anchor{cp/topics/contexts gccjit context new_child_context}@anchor{168} -@deffn {C++ Function} gccjit::@ref{12d,,context} gccjit::context::new_child_context () +@anchor{cp/topics/contexts _CPPv4N6gccjit7context17new_child_contextEv}@anchor{17d}@anchor{cp/topics/contexts _CPPv3N6gccjit7context17new_child_contextEv}@anchor{17e}@anchor{cp/topics/contexts _CPPv2N6gccjit7context17new_child_contextEv}@anchor{17f}@anchor{cp/topics/contexts gccjit context new_child_context}@anchor{180} +@deffn {C++ Function} gccjit::@ref{13d,,context} gccjit::@ref{13d,,context}::new_child_context () Given an existing JIT context, create a child context. @@ -11802,16 +12261,16 @@ there will likely be a performance hit for such nesting. @end deffn @node Thread-safety<2>,Error-handling<3>,Lifetime-management<2>,Compilation contexts<2> -@anchor{cp/topics/contexts thread-safety}@anchor{169} +@anchor{cp/topics/contexts thread-safety}@anchor{181} @subsubsection Thread-safety -Instances of @ref{12d,,gccjit;;context} created via -@ref{12e,,gccjit;;context;;acquire()} are independent from each other: +Instances of @ref{13d,,gccjit;;context} created via +@ref{13e,,gccjit;;context;;acquire()} are independent from each other: only one thread may use a given context at once, but multiple threads could each have their own contexts without needing locks. -Contexts created via @ref{167,,gccjit;;context;;new_child_context()} are +Contexts created via @ref{17d,,gccjit;;context;;new_child_context()} are related to their parent context. They can be partitioned by their ultimate ancestor into independent “family trees”. Only one thread within a process may use a given “family tree” of such contexts at once, @@ -11819,7 +12278,7 @@ and if you’re using multiple threads you should provide your own locking around entire such context partitions. @node Error-handling<3>,Debugging<2>,Thread-safety<2>,Compilation contexts<2> -@anchor{cp/topics/contexts error-handling}@anchor{16a} +@anchor{cp/topics/contexts error-handling}@anchor{182} @subsubsection Error-handling @@ -11832,11 +12291,11 @@ NULL. You don’t have to check everywhere for NULL results, since the API gracefully handles a NULL being passed in for any argument. Errors are printed on stderr and can be queried using -@ref{16b,,gccjit;;context;;get_first_error()}. +@ref{183,,gccjit;;context;;get_first_error()}. @geindex gccjit;;context;;get_first_error (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{16b}@anchor{cp/topics/contexts gccjit context get_first_error__gccjit contextP}@anchor{16c} -@deffn {C++ Function} const char *gccjit::context::get_first_error (gccjit::context *ctxt) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{183}@anchor{cp/topics/contexts _CPPv3N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{184}@anchor{cp/topics/contexts _CPPv2N6gccjit7context15get_first_errorEPN6gccjit7contextE}@anchor{185}@anchor{cp/topics/contexts gccjit context get_first_error__gccjit contextP}@anchor{186} +@deffn {C++ Function} const char *gccjit::@ref{13d,,context}::get_first_error (gccjit::context *ctxt) Returns the first error message that occurred on the context. @@ -11847,18 +12306,18 @@ If no errors occurred, this will be NULL. @end deffn @node Debugging<2>,Options<4>,Error-handling<3>,Compilation contexts<2> -@anchor{cp/topics/contexts debugging}@anchor{16d} +@anchor{cp/topics/contexts debugging}@anchor{187} @subsubsection Debugging @geindex gccjit;;context;;dump_to_file (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{16e}@anchor{cp/topics/contexts gccjit context dump_to_file__ssCR i}@anchor{16f} -@deffn {C++ Function} void gccjit::context::dump_to_file (const std::string &path, int update_locations) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{188}@anchor{cp/topics/contexts _CPPv3N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{189}@anchor{cp/topics/contexts _CPPv2N6gccjit7context12dump_to_fileERKNSt6stringEi}@anchor{18a}@anchor{cp/topics/contexts gccjit context dump_to_file__ssCR i}@anchor{18b} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::dump_to_file (const std::string &path, int update_locations) To help with debugging: dump a C-like representation to the given path, describing what’s been set up on the context. -If “update_locations” is true, then also set up @ref{153,,gccjit;;location} +If “update_locations” is true, then also set up @ref{163,,gccjit;;location} information throughout the context, pointing at the dump file as if it were a source file. This may be of use in conjunction with @code{GCCJIT::BOOL_OPTION_DEBUGINFO} to allow stepping through the @@ -11866,8 +12325,8 @@ code in a debugger. @end deffn @geindex gccjit;;context;;dump_reproducer_to_file (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{170}@anchor{cp/topics/contexts gccjit context dump_reproducer_to_file__gcc_jit_contextP cCP}@anchor{171} -@deffn {C++ Function} void gccjit::context::dump_reproducer_to_file (gcc_jit_context *ctxt, const char *path) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{18c}@anchor{cp/topics/contexts _CPPv3N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{18d}@anchor{cp/topics/contexts _CPPv2N6gccjit7context23dump_reproducer_to_fileEP15gcc_jit_contextPKc}@anchor{18e}@anchor{cp/topics/contexts gccjit context dump_reproducer_to_file__gcc_jit_contextP cCP}@anchor{18f} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::dump_reproducer_to_file (gcc_jit_context *ctxt, const char *path) This is a thin wrapper around the C API @ref{5d,,gcc_jit_context_dump_reproducer_to_file()}, and hence works the @@ -11878,7 +12337,7 @@ for seeing what the C++ bindings are doing at the C level. @end deffn @node Options<4>,,Debugging<2>,Compilation contexts<2> -@anchor{cp/topics/contexts options}@anchor{172} +@anchor{cp/topics/contexts options}@anchor{190} @subsubsection Options @@ -11891,13 +12350,13 @@ for seeing what the C++ bindings are doing at the C level. @end menu @node String Options<2>,Boolean options<2>,,Options<4> -@anchor{cp/topics/contexts string-options}@anchor{173} +@anchor{cp/topics/contexts string-options}@anchor{191} @subsubsection String Options @geindex gccjit;;context;;set_str_option (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{174}@anchor{cp/topics/contexts gccjit context set_str_option__gcc_jit_str_option cCP}@anchor{175} -@deffn {C++ Function} void gccjit::context::set_str_option (enum gcc_jit_str_option, const char *value) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{192}@anchor{cp/topics/contexts _CPPv3N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{193}@anchor{cp/topics/contexts _CPPv2N6gccjit7context14set_str_optionE18gcc_jit_str_optionPKc}@anchor{194}@anchor{cp/topics/contexts gccjit context set_str_option__gcc_jit_str_option cCP}@anchor{195} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::set_str_option (enum gcc_jit_str_option, const char *value) Set a string option of the context. @@ -11907,13 +12366,13 @@ meaning. @end deffn @node Boolean options<2>,Integer options<2>,String Options<2>,Options<4> -@anchor{cp/topics/contexts boolean-options}@anchor{176} +@anchor{cp/topics/contexts boolean-options}@anchor{196} @subsubsection Boolean options @geindex gccjit;;context;;set_bool_option (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{139}@anchor{cp/topics/contexts gccjit context set_bool_option__gcc_jit_bool_option i}@anchor{177} -@deffn {C++ Function} void gccjit::context::set_bool_option (enum gcc_jit_bool_option, int value) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{149}@anchor{cp/topics/contexts _CPPv3N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{197}@anchor{cp/topics/contexts _CPPv2N6gccjit7context15set_bool_optionE19gcc_jit_bool_optioni}@anchor{198}@anchor{cp/topics/contexts gccjit context set_bool_option__gcc_jit_bool_option i}@anchor{199} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::set_bool_option (enum gcc_jit_bool_option, int value) Set a boolean option of the context. @@ -11923,8 +12382,8 @@ meaning. @end deffn @geindex gccjit;;context;;set_bool_allow_unreachable_blocks (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{178}@anchor{cp/topics/contexts gccjit context set_bool_allow_unreachable_blocks__i}@anchor{179} -@deffn {C++ Function} void gccjit::context::set_bool_allow_unreachable_blocks (int bool_value) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{19a}@anchor{cp/topics/contexts _CPPv3N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{19b}@anchor{cp/topics/contexts _CPPv2N6gccjit7context33set_bool_allow_unreachable_blocksEi}@anchor{19c}@anchor{cp/topics/contexts gccjit context set_bool_allow_unreachable_blocks__i}@anchor{19d} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::set_bool_allow_unreachable_blocks (int bool_value) By default, libgccjit will issue an error about unreachable blocks within a function. @@ -11942,8 +12401,8 @@ its presence using @end deffn @geindex gccjit;;context;;set_bool_use_external_driver (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context28set_bool_use_external_driverEi}@anchor{17a}@anchor{cp/topics/contexts gccjit context set_bool_use_external_driver__i}@anchor{17b} -@deffn {C++ Function} void gccjit::context::set_bool_use_external_driver (int bool_value) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context28set_bool_use_external_driverEi}@anchor{19e}@anchor{cp/topics/contexts _CPPv3N6gccjit7context28set_bool_use_external_driverEi}@anchor{19f}@anchor{cp/topics/contexts _CPPv2N6gccjit7context28set_bool_use_external_driverEi}@anchor{1a0}@anchor{cp/topics/contexts gccjit context set_bool_use_external_driver__i}@anchor{1a1} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::set_bool_use_external_driver (int bool_value) libgccjit internally generates assembler, and uses “driver” code for converting it to other formats (e.g. shared libraries). @@ -11964,13 +12423,13 @@ its presence using @end deffn @node Integer options<2>,Additional command-line options<2>,Boolean options<2>,Options<4> -@anchor{cp/topics/contexts integer-options}@anchor{17c} +@anchor{cp/topics/contexts integer-options}@anchor{1a2} @subsubsection Integer options @geindex gccjit;;context;;set_int_option (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{13a}@anchor{cp/topics/contexts gccjit context set_int_option__gcc_jit_int_option i}@anchor{17d} -@deffn {C++ Function} void gccjit::context::set_int_option (enum gcc_jit_int_option, int value) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{14a}@anchor{cp/topics/contexts _CPPv3N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{1a3}@anchor{cp/topics/contexts _CPPv2N6gccjit7context14set_int_optionE18gcc_jit_int_optioni}@anchor{1a4}@anchor{cp/topics/contexts gccjit context set_int_option__gcc_jit_int_option i}@anchor{1a5} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::set_int_option (enum gcc_jit_int_option, int value) Set an integer option of the context. @@ -11980,13 +12439,13 @@ meaning. @end deffn @node Additional command-line options<2>,,Integer options<2>,Options<4> -@anchor{cp/topics/contexts additional-command-line-options}@anchor{17e} +@anchor{cp/topics/contexts additional-command-line-options}@anchor{1a6} @subsubsection Additional command-line options @geindex gccjit;;context;;add_command_line_option (C++ function) -@anchor{cp/topics/contexts _CPPv2N6gccjit7context23add_command_line_optionEPKc}@anchor{17f}@anchor{cp/topics/contexts gccjit context add_command_line_option__cCP}@anchor{180} -@deffn {C++ Function} void gccjit::context::add_command_line_option (const char *optname) +@anchor{cp/topics/contexts _CPPv4N6gccjit7context23add_command_line_optionEPKc}@anchor{1a7}@anchor{cp/topics/contexts _CPPv3N6gccjit7context23add_command_line_optionEPKc}@anchor{1a8}@anchor{cp/topics/contexts _CPPv2N6gccjit7context23add_command_line_optionEPKc}@anchor{1a9}@anchor{cp/topics/contexts gccjit context add_command_line_option__cCP}@anchor{1aa} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::add_command_line_option (const char *optname) Add an arbitrary gcc command-line option to the context for use when compiling. @@ -12020,18 +12479,18 @@ its presence using @c . @node Objects<2>,Types<2>,Compilation contexts<2>,Topic Reference<2> -@anchor{cp/topics/objects objects}@anchor{181}@anchor{cp/topics/objects doc}@anchor{182} +@anchor{cp/topics/objects doc}@anchor{1ab}@anchor{cp/topics/objects objects}@anchor{1ac} @subsection Objects @geindex gccjit;;object (C++ class) -@anchor{cp/topics/objects _CPPv2N6gccjit6objectE}@anchor{132}@anchor{cp/topics/objects gccjit object}@anchor{183} +@anchor{cp/topics/objects _CPPv4N6gccjit6objectE}@anchor{142}@anchor{cp/topics/objects _CPPv3N6gccjit6objectE}@anchor{1ad}@anchor{cp/topics/objects _CPPv2N6gccjit6objectE}@anchor{1ae}@anchor{cp/topics/objects gccjit object}@anchor{1af} @deffn {C++ Class} gccjit::object @end deffn Almost every entity in the API (with the exception of -@ref{12d,,gccjit;;context} and @ref{16,,gcc_jit_result *}) is a -“contextual” object, a @ref{132,,gccjit;;object}. +@ref{13d,,gccjit;;context} and @ref{16,,gcc_jit_result *}) is a +“contextual” object, a @ref{142,,gccjit;;object}. A JIT object: @@ -12041,7 +12500,7 @@ A JIT object: @itemize * @item -is associated with a @ref{12d,,gccjit;;context}. +is associated with a @ref{13d,,gccjit;;context}. @item is automatically cleaned up for you when its context is released so @@ -12066,18 +12525,18 @@ The C++ class hierarchy within the @code{gccjit} namespace looks like this: +- case_ @end example -The @ref{132,,gccjit;;object} base class has the following operations: +The @ref{142,,gccjit;;object} base class has the following operations: @geindex gccjit;;object;;get_context (C++ function) -@anchor{cp/topics/objects _CPPv2NK6gccjit6object11get_contextEv}@anchor{184}@anchor{cp/topics/objects gccjit object get_contextC}@anchor{185} -@deffn {C++ Function} gccjit::@ref{12d,,context} gccjit::object::get_context () const +@anchor{cp/topics/objects _CPPv4NK6gccjit6object11get_contextEv}@anchor{1b0}@anchor{cp/topics/objects _CPPv3NK6gccjit6object11get_contextEv}@anchor{1b1}@anchor{cp/topics/objects _CPPv2NK6gccjit6object11get_contextEv}@anchor{1b2}@anchor{cp/topics/objects gccjit object get_contextC}@anchor{1b3} +@deffn {C++ Function} gccjit::@ref{13d,,context} gccjit::@ref{142,,object}::get_context () const Which context is the obj within? @end deffn @geindex gccjit;;object;;get_debug_string (C++ function) -@anchor{cp/topics/objects _CPPv2NK6gccjit6object16get_debug_stringEv}@anchor{133}@anchor{cp/topics/objects gccjit object get_debug_stringC}@anchor{186} -@deffn {C++ Function} std::string gccjit::object::get_debug_string () const +@anchor{cp/topics/objects _CPPv4NK6gccjit6object16get_debug_stringEv}@anchor{143}@anchor{cp/topics/objects _CPPv3NK6gccjit6object16get_debug_stringEv}@anchor{1b4}@anchor{cp/topics/objects _CPPv2NK6gccjit6object16get_debug_stringEv}@anchor{1b5}@anchor{cp/topics/objects gccjit object get_debug_stringC}@anchor{1b6} +@deffn {C++ Function} std::string gccjit::@ref{142,,object}::get_debug_string () const Generate a human-readable description for the given object. @@ -12112,16 +12571,16 @@ obj: 4.0 * (float)i @c . @node Types<2>,Expressions<2>,Objects<2>,Topic Reference<2> -@anchor{cp/topics/types doc}@anchor{187}@anchor{cp/topics/types types}@anchor{188} +@anchor{cp/topics/types doc}@anchor{1b7}@anchor{cp/topics/types types}@anchor{1b8} @subsection Types @geindex gccjit;;type (C++ class) -@anchor{cp/topics/types _CPPv2N6gccjit4typeE}@anchor{12f}@anchor{cp/topics/types gccjit type}@anchor{189} +@anchor{cp/topics/types _CPPv4N6gccjit4typeE}@anchor{13f}@anchor{cp/topics/types _CPPv3N6gccjit4typeE}@anchor{1b9}@anchor{cp/topics/types _CPPv2N6gccjit4typeE}@anchor{1ba}@anchor{cp/topics/types gccjit type}@anchor{1bb} @deffn {C++ Class} gccjit::type gccjit::type represents a type within the library. It is a subclass -of @ref{132,,gccjit;;object}. +of @ref{142,,gccjit;;object}. @end deffn Types can be created in several ways: @@ -12131,7 +12590,7 @@ Types can be created in several ways: @item fundamental types can be accessed using -@ref{130,,gccjit;;context;;get_type()}: +@ref{140,,gccjit;;context;;get_type()}: @example gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT); @@ -12147,7 +12606,7 @@ See @ref{b,,gcc_jit_context_get_type()} for the available types. @item derived types can be accessed by using functions such as -@ref{18a,,gccjit;;type;;get_pointer()} and @ref{18b,,gccjit;;type;;get_const()}: +@ref{1bc,,gccjit;;type;;get_pointer()} and @ref{1bd,,gccjit;;type;;get_const()}: @example gccjit::type const_int_star = int_type.get_const ().get_pointer (); @@ -12167,28 +12626,28 @@ by creating structures (see below). @end menu @node Standard types<2>,Pointers const and volatile<2>,,Types<2> -@anchor{cp/topics/types standard-types}@anchor{18c} +@anchor{cp/topics/types standard-types}@anchor{1be} @subsubsection Standard types @geindex gccjit;;context;;get_type (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit7context8get_typeE13gcc_jit_types}@anchor{130}@anchor{cp/topics/types gccjit context get_type__gcc_jit_types}@anchor{18d} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::context::get_type (enum gcc_jit_types) +@anchor{cp/topics/types _CPPv4N6gccjit7context8get_typeE13gcc_jit_types}@anchor{140}@anchor{cp/topics/types _CPPv3N6gccjit7context8get_typeE13gcc_jit_types}@anchor{1bf}@anchor{cp/topics/types _CPPv2N6gccjit7context8get_typeE13gcc_jit_types}@anchor{1c0}@anchor{cp/topics/types gccjit context get_type__gcc_jit_types}@anchor{1c1} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13d,,context}::get_type (enum gcc_jit_types) Access a specific type. This is a thin wrapper around @ref{b,,gcc_jit_context_get_type()}; the parameter has the same meaning. @end deffn @geindex gccjit;;context;;get_int_type (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit7context12get_int_typeE6size_ti}@anchor{18e}@anchor{cp/topics/types gccjit context get_int_type__s i}@anchor{18f} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::context::get_int_type (size_t num_bytes, int is_signed) +@anchor{cp/topics/types _CPPv4N6gccjit7context12get_int_typeE6size_ti}@anchor{1c2}@anchor{cp/topics/types _CPPv3N6gccjit7context12get_int_typeE6size_ti}@anchor{1c3}@anchor{cp/topics/types _CPPv2N6gccjit7context12get_int_typeE6size_ti}@anchor{1c4}@anchor{cp/topics/types gccjit context get_int_type__s i}@anchor{1c5} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13d,,context}::get_int_type (size_t num_bytes, int is_signed) Access the integer type of the given size. @end deffn @geindex gccjit;;context;;get_int_type (C++ function) -@anchor{cp/topics/types _CPPv2IEN6gccjit7context12get_int_typeI1TEEv}@anchor{190} -@deffn {C++ Function} template<>gccjit::@ref{12f,,type} gccjit::context::get_int_type () +@anchor{cp/topics/types _CPPv4IEN6gccjit7context12get_int_typeI1TEEN6gccjit4typeEv}@anchor{1c6}@anchor{cp/topics/types _CPPv3IEN6gccjit7context12get_int_typeI1TEEv}@anchor{1c7}@anchor{cp/topics/types _CPPv2IEN6gccjit7context12get_int_typeI1TEEv}@anchor{1c8} +@deffn {C++ Function} template<>gccjit::@ref{13f,,type} gccjit::@ref{13d,,context}::get_int_type () Access the given integer type. For example, you could map the @code{unsigned short} type into a gccjit::type via: @@ -12199,34 +12658,34 @@ gccjit::type t = ctxt.get_int_type (); @end deffn @node Pointers const and volatile<2>,Vector types<2>,Standard types<2>,Types<2> -@anchor{cp/topics/types pointers-const-and-volatile}@anchor{191} +@anchor{cp/topics/types pointers-const-and-volatile}@anchor{1c9} @subsubsection Pointers, @cite{const}, and @cite{volatile} @geindex gccjit;;type;;get_pointer (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit4type11get_pointerEv}@anchor{18a}@anchor{cp/topics/types gccjit type get_pointer}@anchor{192} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::type::get_pointer () +@anchor{cp/topics/types _CPPv4N6gccjit4type11get_pointerEv}@anchor{1bc}@anchor{cp/topics/types _CPPv3N6gccjit4type11get_pointerEv}@anchor{1ca}@anchor{cp/topics/types _CPPv2N6gccjit4type11get_pointerEv}@anchor{1cb}@anchor{cp/topics/types gccjit type get_pointer}@anchor{1cc} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13f,,type}::get_pointer () Given type “T”, get type “T*”. @end deffn @geindex gccjit;;type;;get_const (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit4type9get_constEv}@anchor{18b}@anchor{cp/topics/types gccjit type get_const}@anchor{193} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::type::get_const () +@anchor{cp/topics/types _CPPv4N6gccjit4type9get_constEv}@anchor{1bd}@anchor{cp/topics/types _CPPv3N6gccjit4type9get_constEv}@anchor{1cd}@anchor{cp/topics/types _CPPv2N6gccjit4type9get_constEv}@anchor{1ce}@anchor{cp/topics/types gccjit type get_const}@anchor{1cf} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13f,,type}::get_const () Given type “T”, get type “const T”. @end deffn @geindex gccjit;;type;;get_volatile (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit4type12get_volatileEv}@anchor{194}@anchor{cp/topics/types gccjit type get_volatile}@anchor{195} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::type::get_volatile () +@anchor{cp/topics/types _CPPv4N6gccjit4type12get_volatileEv}@anchor{1d0}@anchor{cp/topics/types _CPPv3N6gccjit4type12get_volatileEv}@anchor{1d1}@anchor{cp/topics/types _CPPv2N6gccjit4type12get_volatileEv}@anchor{1d2}@anchor{cp/topics/types gccjit type get_volatile}@anchor{1d3} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13f,,type}::get_volatile () Given type “T”, get type “volatile T”. @end deffn @geindex gccjit;;type;;get_aligned (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit4type11get_alignedE6size_t}@anchor{196}@anchor{cp/topics/types gccjit type get_aligned__s}@anchor{197} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::type::get_aligned (size_t alignment_in_bytes) +@anchor{cp/topics/types _CPPv4N6gccjit4type11get_alignedE6size_t}@anchor{1d4}@anchor{cp/topics/types _CPPv3N6gccjit4type11get_alignedE6size_t}@anchor{1d5}@anchor{cp/topics/types _CPPv2N6gccjit4type11get_alignedE6size_t}@anchor{1d6}@anchor{cp/topics/types gccjit type get_aligned__s}@anchor{1d7} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13f,,type}::get_aligned (size_t alignment_in_bytes) Given type “T”, get type: @@ -12238,21 +12697,21 @@ The alignment must be a power of two. @end deffn @geindex gccjit;;context;;new_array_type (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{198}@anchor{cp/topics/types gccjit context new_array_type__gccjit type i gccjit location}@anchor{199} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::context::new_array_type (gccjit::type element_type, int num_elements, gccjit::location loc) +@anchor{cp/topics/types _CPPv4N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{1d8}@anchor{cp/topics/types _CPPv3N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{1d9}@anchor{cp/topics/types _CPPv2N6gccjit7context14new_array_typeEN6gccjit4typeEiN6gccjit8locationE}@anchor{1da}@anchor{cp/topics/types gccjit context new_array_type__gccjit type i gccjit location}@anchor{1db} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13d,,context}::new_array_type (gccjit::type element_type, int num_elements, gccjit::location loc) Given type “T”, get type “T[N]” (for a constant N). Param “loc” is optional. @end deffn @node Vector types<2>,Structures and unions<2>,Pointers const and volatile<2>,Types<2> -@anchor{cp/topics/types vector-types}@anchor{19a} +@anchor{cp/topics/types vector-types}@anchor{1dc} @subsubsection Vector types @geindex gccjit;;type;;get_vector (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit4type10get_vectorE6size_t}@anchor{19b}@anchor{cp/topics/types gccjit type get_vector__s}@anchor{19c} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::type::get_vector (size_t num_units) +@anchor{cp/topics/types _CPPv4N6gccjit4type10get_vectorE6size_t}@anchor{1dd}@anchor{cp/topics/types _CPPv3N6gccjit4type10get_vectorE6size_t}@anchor{1de}@anchor{cp/topics/types _CPPv2N6gccjit4type10get_vectorE6size_t}@anchor{1df}@anchor{cp/topics/types gccjit type get_vector__s}@anchor{1e0} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{13f,,type}::get_vector (size_t num_units) Given type “T”, get type: @@ -12264,31 +12723,31 @@ T must be integral or floating point; num_units must be a power of two. @end deffn @node Structures and unions<2>,,Vector types<2>,Types<2> -@anchor{cp/topics/types structures-and-unions}@anchor{19d} +@anchor{cp/topics/types structures-and-unions}@anchor{1e1} @subsubsection Structures and unions @geindex gccjit;;struct_ (C++ class) -@anchor{cp/topics/types _CPPv2N6gccjit7struct_E}@anchor{19e}@anchor{cp/topics/types gccjit struct_}@anchor{19f} +@anchor{cp/topics/types _CPPv4N6gccjit7struct_E}@anchor{1e2}@anchor{cp/topics/types _CPPv3N6gccjit7struct_E}@anchor{1e3}@anchor{cp/topics/types _CPPv2N6gccjit7struct_E}@anchor{1e4}@anchor{cp/topics/types gccjit struct_}@anchor{1e5} @deffn {C++ Class} gccjit::struct_ @end deffn A compound type analagous to a C @cite{struct}. -@ref{19e,,gccjit;;struct_} is a subclass of @ref{12f,,gccjit;;type} (and thus -of @ref{132,,gccjit;;object} in turn). +@ref{1e2,,gccjit;;struct_} is a subclass of @ref{13f,,gccjit;;type} (and thus +of @ref{142,,gccjit;;object} in turn). @geindex gccjit;;field (C++ class) -@anchor{cp/topics/types _CPPv2N6gccjit5fieldE}@anchor{1a0}@anchor{cp/topics/types gccjit field}@anchor{1a1} +@anchor{cp/topics/types _CPPv4N6gccjit5fieldE}@anchor{1e6}@anchor{cp/topics/types _CPPv3N6gccjit5fieldE}@anchor{1e7}@anchor{cp/topics/types _CPPv2N6gccjit5fieldE}@anchor{1e8}@anchor{cp/topics/types gccjit field}@anchor{1e9} @deffn {C++ Class} gccjit::field @end deffn -A field within a @ref{19e,,gccjit;;struct_}. +A field within a @ref{1e2,,gccjit;;struct_}. -@ref{1a0,,gccjit;;field} is a subclass of @ref{132,,gccjit;;object}. +@ref{1e6,,gccjit;;field} is a subclass of @ref{142,,gccjit;;object}. -You can model C @cite{struct} types by creating @ref{19e,,gccjit;;struct_} and -@ref{1a0,,gccjit;;field} instances, in either order: +You can model C @cite{struct} types by creating @ref{1e2,,gccjit;;struct_} and +@ref{1e6,,gccjit;;field} instances, in either order: @itemize * @@ -12336,15 +12795,15 @@ node.set_fields (fields); @c FIXME: the above API doesn't seem to exist yet @geindex gccjit;;context;;new_field (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{1a2}@anchor{cp/topics/types gccjit context new_field__gccjit type cCP gccjit location}@anchor{1a3} -@deffn {C++ Function} gccjit::@ref{1a0,,field} gccjit::context::new_field (gccjit::type type, const char *name, gccjit::location loc) +@anchor{cp/topics/types _CPPv4N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{1ea}@anchor{cp/topics/types _CPPv3N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{1eb}@anchor{cp/topics/types _CPPv2N6gccjit7context9new_fieldEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{1ec}@anchor{cp/topics/types gccjit context new_field__gccjit type cCP gccjit location}@anchor{1ed} +@deffn {C++ Function} gccjit::@ref{1e6,,field} gccjit::@ref{13d,,context}::new_field (gccjit::type type, const char *name, gccjit::location loc) Construct a new field, with the given type and name. @end deffn @geindex gccjit;;context;;new_struct_type (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{1a4}@anchor{cp/topics/types gccjit context new_struct_type__ssCR std vector field R gccjit location}@anchor{1a5} -@deffn {C++ Function} gccjit::@ref{19e,,struct_} gccjit::context::new_struct_type (const std::string &name, std::vector &fields, gccjit::location loc) +@anchor{cp/topics/types _CPPv4N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{1ee}@anchor{cp/topics/types _CPPv3N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{1ef}@anchor{cp/topics/types _CPPv2N6gccjit7context15new_struct_typeERKNSt6stringERNSt6vectorI5fieldEEN6gccjit8locationE}@anchor{1f0}@anchor{cp/topics/types gccjit context new_struct_type__ssCR std vector field R gccjit location}@anchor{1f1} +@deffn {C++ Function} gccjit::@ref{1e2,,struct_} gccjit::@ref{13d,,context}::new_struct_type (const std::string &name, std::vector &fields, gccjit::location loc) @quotation @@ -12353,8 +12812,8 @@ Construct a new struct type, with the given name and fields. @end deffn @geindex gccjit;;context;;new_opaque_struct (C++ function) -@anchor{cp/topics/types _CPPv2N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{1a6}@anchor{cp/topics/types gccjit context new_opaque_struct__ssCR gccjit location}@anchor{1a7} -@deffn {C++ Function} gccjit::@ref{19e,,struct_} gccjit::context::new_opaque_struct (const std::string &name, gccjit::location loc) +@anchor{cp/topics/types _CPPv4N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{1f2}@anchor{cp/topics/types _CPPv3N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{1f3}@anchor{cp/topics/types _CPPv2N6gccjit7context17new_opaque_structERKNSt6stringEN6gccjit8locationE}@anchor{1f4}@anchor{cp/topics/types gccjit context new_opaque_struct__ssCR gccjit location}@anchor{1f5} +@deffn {C++ Function} gccjit::@ref{1e2,,struct_} gccjit::@ref{13d,,context}::new_opaque_struct (const std::string &name, gccjit::location loc) Construct a new struct type, with the given name, but without specifying the fields. The fields can be omitted (in which case the @@ -12380,7 +12839,7 @@ size of the struct is not known), or later specified using @c . @node Expressions<2>,Creating and using functions<2>,Types<2>,Topic Reference<2> -@anchor{cp/topics/expressions expressions}@anchor{1a8}@anchor{cp/topics/expressions doc}@anchor{1a9} +@anchor{cp/topics/expressions doc}@anchor{1f6}@anchor{cp/topics/expressions expressions}@anchor{1f7} @subsection Expressions @@ -12392,17 +12851,17 @@ size of the struct is not known), or later specified using @end menu @node Rvalues<2>,Lvalues<2>,,Expressions<2> -@anchor{cp/topics/expressions rvalues}@anchor{1aa} +@anchor{cp/topics/expressions rvalues}@anchor{1f8} @subsubsection Rvalues @geindex gccjit;;rvalue (C++ class) -@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalueE}@anchor{136}@anchor{cp/topics/expressions gccjit rvalue}@anchor{1ab} +@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalueE}@anchor{146}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalueE}@anchor{1f9}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalueE}@anchor{1fa}@anchor{cp/topics/expressions gccjit rvalue}@anchor{1fb} @deffn {C++ Class} gccjit::rvalue @end deffn -A @ref{136,,gccjit;;rvalue} is an expression that can be computed. It is a -subclass of @ref{132,,gccjit;;object}, and is a thin wrapper around +A @ref{146,,gccjit;;rvalue} is an expression that can be computed. It is a +subclass of @ref{142,,gccjit;;object}, and is a thin wrapper around @ref{13,,gcc_jit_rvalue *} from the C API. It can be simple, e.g.: @@ -12448,8 +12907,8 @@ Every rvalue has an associated type, and the API will check to ensure that types match up correctly (otherwise the context will emit an error). @geindex gccjit;;rvalue;;get_type (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue8get_typeEv}@anchor{1ac}@anchor{cp/topics/expressions gccjit rvalue get_type}@anchor{1ad} -@deffn {C++ Function} gccjit::@ref{12f,,type} gccjit::rvalue::get_type () +@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue8get_typeEv}@anchor{1fc}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue8get_typeEv}@anchor{1fd}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue8get_typeEv}@anchor{1fe}@anchor{cp/topics/expressions gccjit rvalue get_type}@anchor{1ff} +@deffn {C++ Function} gccjit::@ref{13f,,type} gccjit::@ref{146,,rvalue}::get_type () Get the type of this rvalue. @end deffn @@ -12467,29 +12926,29 @@ Get the type of this rvalue. @end menu @node Simple expressions<2>,Vector expressions<2>,,Rvalues<2> -@anchor{cp/topics/expressions simple-expressions}@anchor{1ae} +@anchor{cp/topics/expressions simple-expressions}@anchor{200} @subsubsection Simple expressions @geindex gccjit;;context;;new_rvalue (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{14a}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type iC}@anchor{1af} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_rvalue (gccjit::type numeric_type, int value) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{15a}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{201}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEi}@anchor{202}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type iC}@anchor{203} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_rvalue (gccjit::type numeric_type, int value) const Given a numeric type (integer or floating point), build an rvalue for the given constant @code{int} value. @end deffn @geindex gccjit;;context;;new_rvalue (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{1b0}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type lC}@anchor{1b1} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_rvalue (gccjit::type numeric_type, long value) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{204}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{205}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEl}@anchor{206}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type lC}@anchor{207} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_rvalue (gccjit::type numeric_type, long value) const Given a numeric type (integer or floating point), build an rvalue for the given constant @code{long} value. @end deffn @geindex gccjit;;context;;zero (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{146}@anchor{cp/topics/expressions gccjit context zero__gccjit typeC}@anchor{1b2} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::zero (gccjit::type numeric_type) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{156}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{208}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context4zeroEN6gccjit4typeE}@anchor{209}@anchor{cp/topics/expressions gccjit context zero__gccjit typeC}@anchor{20a} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::zero (gccjit::type numeric_type) const Given a numeric type (integer or floating point), get the rvalue for zero. Essentially this is just a shortcut for: @@ -12500,8 +12959,8 @@ ctxt.new_rvalue (numeric_type, 0) @end deffn @geindex gccjit;;context;;one (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context3oneEN6gccjit4typeE}@anchor{1b3}@anchor{cp/topics/expressions gccjit context one__gccjit typeC}@anchor{1b4} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::one (gccjit::type numeric_type) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context3oneEN6gccjit4typeE}@anchor{20b}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context3oneEN6gccjit4typeE}@anchor{20c}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context3oneEN6gccjit4typeE}@anchor{20d}@anchor{cp/topics/expressions gccjit context one__gccjit typeC}@anchor{20e} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::one (gccjit::type numeric_type) const Given a numeric type (integer or floating point), get the rvalue for one. Essentially this is just a shortcut for: @@ -12512,36 +12971,36 @@ ctxt.new_rvalue (numeric_type, 1) @end deffn @geindex gccjit;;context;;new_rvalue (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{1b5}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type doubleC}@anchor{1b6} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_rvalue (gccjit::type numeric_type, double value) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{20f}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{210}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEd}@anchor{211}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type doubleC}@anchor{212} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_rvalue (gccjit::type numeric_type, double value) const Given a numeric type (integer or floating point), build an rvalue for the given constant @code{double} value. @end deffn @geindex gccjit;;context;;new_rvalue (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{1b7}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type voidPC}@anchor{1b8} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_rvalue (gccjit::type pointer_type, void *value) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{213}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{214}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeEPv}@anchor{215}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type voidPC}@anchor{216} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_rvalue (gccjit::type pointer_type, void *value) const Given a pointer type, build an rvalue for the given address. @end deffn @geindex gccjit;;context;;new_rvalue (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{1b9}@anchor{cp/topics/expressions gccjit context new_rvalue__ssCRC}@anchor{1ba} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_rvalue (const std::string &value) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{217}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{218}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueERKNSt6stringE}@anchor{219}@anchor{cp/topics/expressions gccjit context new_rvalue__ssCRC}@anchor{21a} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_rvalue (const std::string &value) const Generate an rvalue of type @code{GCC_JIT_TYPE_CONST_CHAR_PTR} for the given string. This is akin to a string literal. @end deffn @node Vector expressions<2>,Unary Operations<2>,Simple expressions<2>,Rvalues<2> -@anchor{cp/topics/expressions vector-expressions}@anchor{1bb} +@anchor{cp/topics/expressions vector-expressions}@anchor{21b} @subsubsection Vector expressions @geindex gccjit;;context;;new_rvalue (C++ function) -@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{1bc}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type std vector gccjit rvalue C}@anchor{1bd} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_rvalue (gccjit::type vector_type, std::vector elements) const +@anchor{cp/topics/expressions _CPPv4NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{21c}@anchor{cp/topics/expressions _CPPv3NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{21d}@anchor{cp/topics/expressions _CPPv2NK6gccjit7context10new_rvalueEN6gccjit4typeENSt6vectorIN6gccjit6rvalueEEE}@anchor{21e}@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type std vector gccjit rvalue C}@anchor{21f} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_rvalue (gccjit::type vector_type, std::vector elements) const Given a vector type, and a vector of scalar rvalue elements, generate a vector rvalue. @@ -12550,13 +13009,13 @@ The number of elements needs to match that of the vector type. @end deffn @node Unary Operations<2>,Binary Operations<2>,Vector expressions<2>,Rvalues<2> -@anchor{cp/topics/expressions unary-operations}@anchor{1be} +@anchor{cp/topics/expressions unary-operations}@anchor{220} @subsubsection Unary Operations @geindex gccjit;;context;;new_unary_op (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1bf}@anchor{cp/topics/expressions gccjit context new_unary_op__gcc_jit_unary_op gccjit type gccjit rvalue gccjit location}@anchor{1c0} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_unary_op (enum gcc_jit_unary_op, gccjit::type result_type, gccjit::rvalue rvalue, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{221}@anchor{cp/topics/expressions _CPPv3N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{222}@anchor{cp/topics/expressions _CPPv2N6gccjit7context12new_unary_opE16gcc_jit_unary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{223}@anchor{cp/topics/expressions gccjit context new_unary_op__gcc_jit_unary_op gccjit type gccjit rvalue gccjit location}@anchor{224} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_unary_op (enum gcc_jit_unary_op, gccjit::type result_type, gccjit::rvalue rvalue, gccjit::location loc) Build a unary operation out of an input rvalue. @@ -12571,8 +13030,8 @@ There are shorter ways to spell the various specific kinds of unary operation: @geindex gccjit;;context;;new_minus (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1c1}@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit location}@anchor{1c2} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{225}@anchor{cp/topics/expressions _CPPv3N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{226}@anchor{cp/topics/expressions _CPPv2N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{227}@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit location}@anchor{228} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc) Negate an arithmetic value; for example: @@ -12588,8 +13047,8 @@ builds the equivalent of this C expression: @end deffn @geindex new_bitwise_negate (C++ function) -@anchor{cp/topics/expressions _CPPv218new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1c3}@anchor{cp/topics/expressions new_bitwise_negate__gccjit type gccjit rvalue gccjit location}@anchor{1c4} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} new_bitwise_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv418new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{229}@anchor{cp/topics/expressions _CPPv318new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{22a}@anchor{cp/topics/expressions _CPPv218new_bitwise_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{22b}@anchor{cp/topics/expressions new_bitwise_negate__gccjit type gccjit rvalue gccjit location}@anchor{22c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} new_bitwise_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc) Bitwise negation of an integer value (one’s complement); for example: @@ -12605,8 +13064,8 @@ builds the equivalent of this C expression: @end deffn @geindex new_logical_negate (C++ function) -@anchor{cp/topics/expressions _CPPv218new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1c5}@anchor{cp/topics/expressions new_logical_negate__gccjit type gccjit rvalue gccjit location}@anchor{1c6} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} new_logical_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv418new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{22d}@anchor{cp/topics/expressions _CPPv318new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{22e}@anchor{cp/topics/expressions _CPPv218new_logical_negateN6gccjit4typeEN6gccjit6rvalueEN6gccjit8locationE}@anchor{22f}@anchor{cp/topics/expressions new_logical_negate__gccjit type gccjit rvalue gccjit location}@anchor{230} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} new_logical_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc) Logical negation of an arithmetic or pointer value; for example: @@ -12624,8 +13083,8 @@ builds the equivalent of this C expression: The most concise way to spell them is with overloaded operators: @geindex operator- (C++ function) -@anchor{cp/topics/expressions _CPPv2miN6gccjit6rvalueE}@anchor{1c7}@anchor{cp/topics/expressions sub-operator__gccjit rvalue}@anchor{1c8} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator@w{-} (gccjit::rvalue a) +@anchor{cp/topics/expressions _CPPv4miN6gccjit6rvalueE}@anchor{231}@anchor{cp/topics/expressions _CPPv3miN6gccjit6rvalueE}@anchor{232}@anchor{cp/topics/expressions _CPPv2miN6gccjit6rvalueE}@anchor{233}@anchor{cp/topics/expressions sub-operator__gccjit rvalue}@anchor{234} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator@w{-} (gccjit::rvalue a) @example gccjit::rvalue negpi = -pi; @@ -12633,8 +13092,8 @@ gccjit::rvalue negpi = -pi; @end deffn @geindex operator~ (C++ function) -@anchor{cp/topics/expressions _CPPv2coN6gccjit6rvalueE}@anchor{1c9}@anchor{cp/topics/expressions inv-operator__gccjit rvalue}@anchor{1ca} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator~ (gccjit::rvalue a) +@anchor{cp/topics/expressions _CPPv4coN6gccjit6rvalueE}@anchor{235}@anchor{cp/topics/expressions _CPPv3coN6gccjit6rvalueE}@anchor{236}@anchor{cp/topics/expressions _CPPv2coN6gccjit6rvalueE}@anchor{237}@anchor{cp/topics/expressions inv-operator__gccjit rvalue}@anchor{238} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator~ (gccjit::rvalue a) @example gccjit::rvalue mask = ~a; @@ -12642,8 +13101,8 @@ gccjit::rvalue mask = ~a; @end deffn @geindex operator! (C++ function) -@anchor{cp/topics/expressions _CPPv2ntN6gccjit6rvalueE}@anchor{1cb}@anchor{cp/topics/expressions not-operator__gccjit rvalue}@anchor{1cc} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator! (gccjit::rvalue a) +@anchor{cp/topics/expressions _CPPv4ntN6gccjit6rvalueE}@anchor{239}@anchor{cp/topics/expressions _CPPv3ntN6gccjit6rvalueE}@anchor{23a}@anchor{cp/topics/expressions _CPPv2ntN6gccjit6rvalueE}@anchor{23b}@anchor{cp/topics/expressions not-operator__gccjit rvalue}@anchor{23c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator! (gccjit::rvalue a) @example gccjit::rvalue guard = !cond; @@ -12651,13 +13110,13 @@ gccjit::rvalue guard = !cond; @end deffn @node Binary Operations<2>,Comparisons<2>,Unary Operations<2>,Rvalues<2> -@anchor{cp/topics/expressions binary-operations}@anchor{1cd} +@anchor{cp/topics/expressions binary-operations}@anchor{23d} @subsubsection Binary Operations @geindex gccjit;;context;;new_binary_op (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{135}@anchor{cp/topics/expressions gccjit context new_binary_op__gcc_jit_binary_op gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1ce} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_binary_op (enum gcc_jit_binary_op, gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{145}@anchor{cp/topics/expressions _CPPv3N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{23e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context13new_binary_opE17gcc_jit_binary_opN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{23f}@anchor{cp/topics/expressions gccjit context new_binary_op__gcc_jit_binary_op gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{240} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_binary_op (enum gcc_jit_binary_op, gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) Build a binary operation out of two constituent rvalues. @@ -12672,60 +13131,60 @@ There are shorter ways to spell the various specific kinds of binary operation: @geindex gccjit;;context;;new_plus (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1cf}@anchor{cp/topics/expressions gccjit context new_plus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1d0} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_plus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{241}@anchor{cp/topics/expressions _CPPv3N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{242}@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_plusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{243}@anchor{cp/topics/expressions gccjit context new_plus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{244} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_plus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_minus (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1d1}@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1d2} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{245}@anchor{cp/topics/expressions _CPPv3N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{246}@anchor{cp/topics/expressions _CPPv2N6gccjit7context9new_minusEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{247}@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{248} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_mult (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1d3}@anchor{cp/topics/expressions gccjit context new_mult__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1d4} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_mult (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{249}@anchor{cp/topics/expressions _CPPv3N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{24a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_multEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{24b}@anchor{cp/topics/expressions gccjit context new_mult__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{24c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_mult (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_divide (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1d5}@anchor{cp/topics/expressions gccjit context new_divide__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1d6} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_divide (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{24d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{24e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_divideEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{24f}@anchor{cp/topics/expressions gccjit context new_divide__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{250} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_divide (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_modulo (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1d7}@anchor{cp/topics/expressions gccjit context new_modulo__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1d8} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_modulo (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{251}@anchor{cp/topics/expressions _CPPv3N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{252}@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_moduloEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{253}@anchor{cp/topics/expressions gccjit context new_modulo__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{254} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_modulo (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_bitwise_and (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1d9}@anchor{cp/topics/expressions gccjit context new_bitwise_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1da} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_bitwise_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{255}@anchor{cp/topics/expressions _CPPv3N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{256}@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_bitwise_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{257}@anchor{cp/topics/expressions gccjit context new_bitwise_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{258} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_bitwise_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_bitwise_xor (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1db}@anchor{cp/topics/expressions gccjit context new_bitwise_xor__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1dc} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_bitwise_xor (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{259}@anchor{cp/topics/expressions _CPPv3N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_bitwise_xorEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25b}@anchor{cp/topics/expressions gccjit context new_bitwise_xor__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{25c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_bitwise_xor (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_bitwise_or (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1dd}@anchor{cp/topics/expressions gccjit context new_bitwise_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1de} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_bitwise_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_bitwise_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{25f}@anchor{cp/topics/expressions gccjit context new_bitwise_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{260} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_bitwise_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_logical_and (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1df}@anchor{cp/topics/expressions gccjit context new_logical_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1e0} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_logical_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{261}@anchor{cp/topics/expressions _CPPv3N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{262}@anchor{cp/topics/expressions _CPPv2N6gccjit7context15new_logical_andEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{263}@anchor{cp/topics/expressions gccjit context new_logical_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{264} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_logical_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_logical_or (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1e1}@anchor{cp/topics/expressions gccjit context new_logical_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{1e2} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_logical_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{265}@anchor{cp/topics/expressions _CPPv3N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{266}@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_logical_orEN6gccjit4typeEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{267}@anchor{cp/topics/expressions gccjit context new_logical_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{268} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_logical_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn The most concise way to spell them is with overloaded operators: @geindex operator+ (C++ function) -@anchor{cp/topics/expressions _CPPv2plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1e3}@anchor{cp/topics/expressions add-operator__gccjit rvalue gccjit rvalue}@anchor{1e4} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator+ (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{269}@anchor{cp/topics/expressions _CPPv3plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{26a}@anchor{cp/topics/expressions _CPPv2plN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{26b}@anchor{cp/topics/expressions add-operator__gccjit rvalue gccjit rvalue}@anchor{26c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator+ (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue sum = a + b; @@ -12733,8 +13192,8 @@ gccjit::rvalue sum = a + b; @end deffn @geindex operator- (C++ function) -@anchor{cp/topics/expressions _CPPv2miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1e5}@anchor{cp/topics/expressions sub-operator__gccjit rvalue gccjit rvalue}@anchor{1e6} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator@w{-} (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{26d}@anchor{cp/topics/expressions _CPPv3miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{26e}@anchor{cp/topics/expressions _CPPv2miN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{26f}@anchor{cp/topics/expressions sub-operator__gccjit rvalue gccjit rvalue}@anchor{270} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator@w{-} (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue diff = a - b; @@ -12742,8 +13201,8 @@ gccjit::rvalue diff = a - b; @end deffn @geindex operator* (C++ function) -@anchor{cp/topics/expressions _CPPv2mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1e7}@anchor{cp/topics/expressions mul-operator__gccjit rvalue gccjit rvalue}@anchor{1e8} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator* (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{271}@anchor{cp/topics/expressions _CPPv3mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{272}@anchor{cp/topics/expressions _CPPv2mlN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{273}@anchor{cp/topics/expressions mul-operator__gccjit rvalue gccjit rvalue}@anchor{274} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator* (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue prod = a * b; @@ -12751,8 +13210,8 @@ gccjit::rvalue prod = a * b; @end deffn @geindex operator/ (C++ function) -@anchor{cp/topics/expressions _CPPv2dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1e9}@anchor{cp/topics/expressions div-operator__gccjit rvalue gccjit rvalue}@anchor{1ea} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator/ (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{275}@anchor{cp/topics/expressions _CPPv3dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{276}@anchor{cp/topics/expressions _CPPv2dvN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{277}@anchor{cp/topics/expressions div-operator__gccjit rvalue gccjit rvalue}@anchor{278} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator/ (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue result = a / b; @@ -12760,8 +13219,8 @@ gccjit::rvalue result = a / b; @end deffn @geindex operator% (C++ function) -@anchor{cp/topics/expressions _CPPv2rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1eb}@anchor{cp/topics/expressions mod-operator__gccjit rvalue gccjit rvalue}@anchor{1ec} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator% (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{279}@anchor{cp/topics/expressions _CPPv3rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{27a}@anchor{cp/topics/expressions _CPPv2rmN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{27b}@anchor{cp/topics/expressions mod-operator__gccjit rvalue gccjit rvalue}@anchor{27c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator% (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue mod = a % b; @@ -12769,8 +13228,8 @@ gccjit::rvalue mod = a % b; @end deffn @geindex operator& (C++ function) -@anchor{cp/topics/expressions _CPPv2anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1ed}@anchor{cp/topics/expressions and-operator__gccjit rvalue gccjit rvalue}@anchor{1ee} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator& (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{27d}@anchor{cp/topics/expressions _CPPv3anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{27e}@anchor{cp/topics/expressions _CPPv2anN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{27f}@anchor{cp/topics/expressions and-operator__gccjit rvalue gccjit rvalue}@anchor{280} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator& (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue x = a & b; @@ -12778,8 +13237,8 @@ gccjit::rvalue x = a & b; @end deffn @geindex operator^ (C++ function) -@anchor{cp/topics/expressions _CPPv2eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1ef}@anchor{cp/topics/expressions xor-operator__gccjit rvalue gccjit rvalue}@anchor{1f0} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator^ (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{281}@anchor{cp/topics/expressions _CPPv3eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{282}@anchor{cp/topics/expressions _CPPv2eoN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{283}@anchor{cp/topics/expressions xor-operator__gccjit rvalue gccjit rvalue}@anchor{284} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator^ (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue x = a ^ b; @@ -12787,8 +13246,8 @@ gccjit::rvalue x = a ^ b; @end deffn @geindex operator| (C++ function) -@anchor{cp/topics/expressions _CPPv2orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1f1}@anchor{cp/topics/expressions or-operator__gccjit rvalue gccjit rvalue}@anchor{1f2} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator| (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{285}@anchor{cp/topics/expressions _CPPv3orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{286}@anchor{cp/topics/expressions _CPPv2orN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{287}@anchor{cp/topics/expressions or-operator__gccjit rvalue gccjit rvalue}@anchor{288} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator| (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue x = a | b; @@ -12796,8 +13255,8 @@ gccjit::rvalue x = a | b; @end deffn @geindex operator&& (C++ function) -@anchor{cp/topics/expressions _CPPv2aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1f3}@anchor{cp/topics/expressions sand-operator__gccjit rvalue gccjit rvalue}@anchor{1f4} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator&& (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{289}@anchor{cp/topics/expressions _CPPv3aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{28a}@anchor{cp/topics/expressions _CPPv2aaN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{28b}@anchor{cp/topics/expressions sand-operator__gccjit rvalue gccjit rvalue}@anchor{28c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator&& (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = a && b; @@ -12805,8 +13264,8 @@ gccjit::rvalue cond = a && b; @end deffn @geindex operator|| (C++ function) -@anchor{cp/topics/expressions _CPPv2ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{1f5}@anchor{cp/topics/expressions sor-operator__gccjit rvalue gccjit rvalue}@anchor{1f6} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator|| (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{28d}@anchor{cp/topics/expressions _CPPv3ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{28e}@anchor{cp/topics/expressions _CPPv2ooN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{28f}@anchor{cp/topics/expressions sor-operator__gccjit rvalue gccjit rvalue}@anchor{290} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator|| (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = a || b; @@ -12824,13 +13283,13 @@ gccjit::rvalue discriminant = (b * b) - (four * a * c); @end quotation @node Comparisons<2>,Function calls<2>,Binary Operations<2>,Rvalues<2> -@anchor{cp/topics/expressions comparisons}@anchor{1f7} +@anchor{cp/topics/expressions comparisons}@anchor{291} @subsubsection Comparisons @geindex gccjit;;context;;new_comparison (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{147}@anchor{cp/topics/expressions gccjit context new_comparison__gcc_jit_comparison gccjit rvalue gccjit rvalue gccjit location}@anchor{1f8} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_comparison (enum gcc_jit_comparison, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{157}@anchor{cp/topics/expressions _CPPv3N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{292}@anchor{cp/topics/expressions _CPPv2N6gccjit7context14new_comparisonE18gcc_jit_comparisonN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{293}@anchor{cp/topics/expressions gccjit context new_comparison__gcc_jit_comparison gccjit rvalue gccjit rvalue gccjit location}@anchor{294} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_comparison (enum gcc_jit_comparison, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) Build a boolean rvalue out of the comparison of two other rvalues. @@ -12845,40 +13304,40 @@ There are shorter ways to spell the various specific kinds of binary operation: @geindex gccjit;;context;;new_eq (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1f9}@anchor{cp/topics/expressions gccjit context new_eq__gccjit rvalue gccjit rvalue gccjit location}@anchor{1fa} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_eq (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{295}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{296}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_eqEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{297}@anchor{cp/topics/expressions gccjit context new_eq__gccjit rvalue gccjit rvalue gccjit location}@anchor{298} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_eq (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_ne (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1fb}@anchor{cp/topics/expressions gccjit context new_ne__gccjit rvalue gccjit rvalue gccjit location}@anchor{1fc} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_ne (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{299}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29a}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_neEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29b}@anchor{cp/topics/expressions gccjit context new_ne__gccjit rvalue gccjit rvalue gccjit location}@anchor{29c} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_ne (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_lt (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1fd}@anchor{cp/topics/expressions gccjit context new_lt__gccjit rvalue gccjit rvalue gccjit location}@anchor{1fe} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_lt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29d}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29e}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_ltEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{29f}@anchor{cp/topics/expressions gccjit context new_lt__gccjit rvalue gccjit rvalue gccjit location}@anchor{2a0} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_lt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_le (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{1ff}@anchor{cp/topics/expressions gccjit context new_le__gccjit rvalue gccjit rvalue gccjit location}@anchor{200} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_le (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a1}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a2}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_leEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a3}@anchor{cp/topics/expressions gccjit context new_le__gccjit rvalue gccjit rvalue gccjit location}@anchor{2a4} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_le (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_gt (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{201}@anchor{cp/topics/expressions gccjit context new_gt__gccjit rvalue gccjit rvalue gccjit location}@anchor{202} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_gt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a5}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a6}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_gtEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a7}@anchor{cp/topics/expressions gccjit context new_gt__gccjit rvalue gccjit rvalue gccjit location}@anchor{2a8} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_gt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn @geindex gccjit;;context;;new_ge (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{203}@anchor{cp/topics/expressions gccjit context new_ge__gccjit rvalue gccjit rvalue gccjit location}@anchor{204} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_ge (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2a9}@anchor{cp/topics/expressions _CPPv3N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2aa}@anchor{cp/topics/expressions _CPPv2N6gccjit7context6new_geEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2ab}@anchor{cp/topics/expressions gccjit context new_ge__gccjit rvalue gccjit rvalue gccjit location}@anchor{2ac} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_ge (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc) @end deffn The most concise way to spell them is with overloaded operators: @geindex operator== (C++ function) -@anchor{cp/topics/expressions _CPPv2eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{205}@anchor{cp/topics/expressions eq-operator__gccjit rvalue gccjit rvalue}@anchor{206} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator== (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ad}@anchor{cp/topics/expressions _CPPv3eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ae}@anchor{cp/topics/expressions _CPPv2eqN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2af}@anchor{cp/topics/expressions eq-operator__gccjit rvalue gccjit rvalue}@anchor{2b0} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator== (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = (a == ctxt.zero (t_int)); @@ -12886,8 +13345,8 @@ gccjit::rvalue cond = (a == ctxt.zero (t_int)); @end deffn @geindex operator!= (C++ function) -@anchor{cp/topics/expressions _CPPv2neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{207}@anchor{cp/topics/expressions neq-operator__gccjit rvalue gccjit rvalue}@anchor{208} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator!= (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b1}@anchor{cp/topics/expressions _CPPv3neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b2}@anchor{cp/topics/expressions _CPPv2neN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b3}@anchor{cp/topics/expressions neq-operator__gccjit rvalue gccjit rvalue}@anchor{2b4} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator!= (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = (i != j); @@ -12895,8 +13354,8 @@ gccjit::rvalue cond = (i != j); @end deffn @geindex operator< (C++ function) -@anchor{cp/topics/expressions _CPPv2ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{209}@anchor{cp/topics/expressions lt-operator__gccjit rvalue gccjit rvalue}@anchor{20a} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator< (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b5}@anchor{cp/topics/expressions _CPPv3ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b6}@anchor{cp/topics/expressions _CPPv2ltN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b7}@anchor{cp/topics/expressions lt-operator__gccjit rvalue gccjit rvalue}@anchor{2b8} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator< (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = i < n; @@ -12904,8 +13363,8 @@ gccjit::rvalue cond = i < n; @end deffn @geindex operator<= (C++ function) -@anchor{cp/topics/expressions _CPPv2leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{20b}@anchor{cp/topics/expressions lte-operator__gccjit rvalue gccjit rvalue}@anchor{20c} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator<= (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2b9}@anchor{cp/topics/expressions _CPPv3leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2ba}@anchor{cp/topics/expressions _CPPv2leN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2bb}@anchor{cp/topics/expressions lte-operator__gccjit rvalue gccjit rvalue}@anchor{2bc} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator<= (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = i <= n; @@ -12913,8 +13372,8 @@ gccjit::rvalue cond = i <= n; @end deffn @geindex operator> (C++ function) -@anchor{cp/topics/expressions _CPPv2gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{20d}@anchor{cp/topics/expressions gt-operator__gccjit rvalue gccjit rvalue}@anchor{20e} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator> (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2bd}@anchor{cp/topics/expressions _CPPv3gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2be}@anchor{cp/topics/expressions _CPPv2gtN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2bf}@anchor{cp/topics/expressions gt-operator__gccjit rvalue gccjit rvalue}@anchor{2c0} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator> (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = (ch > limit); @@ -12922,8 +13381,8 @@ gccjit::rvalue cond = (ch > limit); @end deffn @geindex operator>= (C++ function) -@anchor{cp/topics/expressions _CPPv2geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{20f}@anchor{cp/topics/expressions gte-operator__gccjit rvalue gccjit rvalue}@anchor{210} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} operator>= (gccjit::rvalue a, gccjit::rvalue b) +@anchor{cp/topics/expressions _CPPv4geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c1}@anchor{cp/topics/expressions _CPPv3geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c2}@anchor{cp/topics/expressions _CPPv2geN6gccjit6rvalueEN6gccjit6rvalueE}@anchor{2c3}@anchor{cp/topics/expressions gte-operator__gccjit rvalue gccjit rvalue}@anchor{2c4} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} operator>= (gccjit::rvalue a, gccjit::rvalue b) @example gccjit::rvalue cond = (score >= ctxt.new_rvalue (t_int, 100)); @@ -12933,12 +13392,12 @@ gccjit::rvalue cond = (score >= ctxt.new_rvalue (t_int, 100)); @c TODO: beyond this point @node Function calls<2>,Function pointers<3>,Comparisons<2>,Rvalues<2> -@anchor{cp/topics/expressions function-calls}@anchor{211} +@anchor{cp/topics/expressions function-calls}@anchor{2c5} @subsubsection Function calls @geindex gcc_jit_context_new_call (C++ function) -@anchor{cp/topics/expressions _CPPv224gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{212}@anchor{cp/topics/expressions gcc_jit_context_new_call__gcc_jit_contextP gcc_jit_locationP gcc_jit_functionP i gcc_jit_rvaluePP}@anchor{213} +@anchor{cp/topics/expressions _CPPv424gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{2c6}@anchor{cp/topics/expressions _CPPv324gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{2c7}@anchor{cp/topics/expressions _CPPv224gcc_jit_context_new_callP15gcc_jit_contextP16gcc_jit_locationP16gcc_jit_functioniPP14gcc_jit_rvalue}@anchor{2c8}@anchor{cp/topics/expressions gcc_jit_context_new_call__gcc_jit_contextP gcc_jit_locationP gcc_jit_functionP i gcc_jit_rvaluePP}@anchor{2c9} @deffn {C++ Function} gcc_jit_rvalue *gcc_jit_context_new_call (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_function *func, int numargs, gcc_jit_rvalue **args) Given a function and the given table of argument rvalues, construct a @@ -12947,14 +13406,14 @@ call to the function, with the result as an rvalue. @cartouche @quotation Note @code{gccjit::context::new_call()} merely builds a -@ref{136,,gccjit;;rvalue} i.e. an expression that can be evaluated, +@ref{146,,gccjit;;rvalue} i.e. an expression that can be evaluated, perhaps as part of a more complicated expression. The call @emph{won’t} happen unless you add a statement to a function that evaluates the expression. For example, if you want to call a function and discard the result (or to call a function with @code{void} return type), use -@ref{214,,gccjit;;block;;add_eval()}: +@ref{2ca,,gccjit;;block;;add_eval()}: @example /* Add "(void)printf (arg0, arg1);". */ @@ -12965,26 +13424,26 @@ block.add_eval (ctxt.new_call (printf_func, arg0, arg1)); @end deffn @node Function pointers<3>,Type-coercion<2>,Function calls<2>,Rvalues<2> -@anchor{cp/topics/expressions function-pointers}@anchor{215} +@anchor{cp/topics/expressions function-pointers}@anchor{2cb} @subsubsection Function pointers @geindex gccjit;;function;;get_address (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{216}@anchor{cp/topics/expressions gccjit function get_address__gccjit location}@anchor{217} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::function::get_address (gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{2cc}@anchor{cp/topics/expressions _CPPv3N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{2cd}@anchor{cp/topics/expressions _CPPv2N6gccjit8function11get_addressEN6gccjit8locationE}@anchor{2ce}@anchor{cp/topics/expressions gccjit function get_address__gccjit location}@anchor{2cf} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{154,,function}::get_address (gccjit::location loc) Get the address of a function as an rvalue, of function pointer type. @end deffn @node Type-coercion<2>,,Function pointers<3>,Rvalues<2> -@anchor{cp/topics/expressions type-coercion}@anchor{218} +@anchor{cp/topics/expressions type-coercion}@anchor{2d0} @subsubsection Type-coercion @geindex gccjit;;context;;new_cast (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{219}@anchor{cp/topics/expressions gccjit context new_cast__gccjit rvalue gccjit type gccjit location}@anchor{21a} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::context::new_cast (gccjit::rvalue rvalue, gccjit::type type, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{2d1}@anchor{cp/topics/expressions _CPPv3N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{2d2}@anchor{cp/topics/expressions _CPPv2N6gccjit7context8new_castEN6gccjit6rvalueEN6gccjit4typeEN6gccjit8locationE}@anchor{2d3}@anchor{cp/topics/expressions gccjit context new_cast__gccjit rvalue gccjit type gccjit location}@anchor{2d4} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{13d,,context}::new_cast (gccjit::rvalue rvalue, gccjit::type type, gccjit::location loc) Given an rvalue of T, construct another rvalue of another type. @@ -13008,25 +13467,25 @@ P* <-> Q*, for pointer types P and Q @end deffn @node Lvalues<2>,Working with pointers structs and unions<2>,Rvalues<2>,Expressions<2> -@anchor{cp/topics/expressions lvalues}@anchor{21b} +@anchor{cp/topics/expressions lvalues}@anchor{2d5} @subsubsection Lvalues @geindex gccjit;;lvalue (C++ class) -@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalueE}@anchor{13f}@anchor{cp/topics/expressions gccjit lvalue}@anchor{21c} +@anchor{cp/topics/expressions _CPPv4N6gccjit6lvalueE}@anchor{14f}@anchor{cp/topics/expressions _CPPv3N6gccjit6lvalueE}@anchor{2d6}@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalueE}@anchor{2d7}@anchor{cp/topics/expressions gccjit lvalue}@anchor{2d8} @deffn {C++ Class} gccjit::lvalue @end deffn An lvalue is something that can of the @emph{left}-hand side of an assignment: a storage area (such as a variable). It is a subclass of -@ref{136,,gccjit;;rvalue}, where the rvalue is computed by reading from the +@ref{146,,gccjit;;rvalue}, where the rvalue is computed by reading from the storage area. It iss a thin wrapper around @ref{24,,gcc_jit_lvalue *} from the C API. @geindex gccjit;;lvalue;;get_address (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{21d}@anchor{cp/topics/expressions gccjit lvalue get_address__gccjit location}@anchor{21e} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::lvalue::get_address (gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{2d9}@anchor{cp/topics/expressions _CPPv3N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{2da}@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalue11get_addressEN6gccjit8locationE}@anchor{2db}@anchor{cp/topics/expressions gccjit lvalue get_address__gccjit location}@anchor{2dc} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{14f,,lvalue}::get_address (gccjit::location loc) Take the address of an lvalue; analogous to: @@ -13045,13 +13504,13 @@ Parameter “loc” is optional. @end menu @node Global variables<2>,,,Lvalues<2> -@anchor{cp/topics/expressions global-variables}@anchor{21f} +@anchor{cp/topics/expressions global-variables}@anchor{2dd} @subsubsection Global variables @geindex gccjit;;context;;new_global (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{220}@anchor{cp/topics/expressions gccjit context new_global__gcc_jit_global_kind gccjit type cCP gccjit location}@anchor{221} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::context::new_global (enum gcc_jit_global_kind, gccjit::type type, const char *name, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{2de}@anchor{cp/topics/expressions _CPPv3N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{2df}@anchor{cp/topics/expressions _CPPv2N6gccjit7context10new_globalE19gcc_jit_global_kindN6gccjit4typeEPKcN6gccjit8locationE}@anchor{2e0}@anchor{cp/topics/expressions gccjit context new_global__gcc_jit_global_kind gccjit type cCP gccjit location}@anchor{2e1} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{13d,,context}::new_global (enum gcc_jit_global_kind, gccjit::type type, const char *name, gccjit::location loc) Add a new global variable of the given type and name to the context. @@ -13060,13 +13519,13 @@ the C API; the “kind” parameter has the same meaning as there. @end deffn @node Working with pointers structs and unions<2>,,Lvalues<2>,Expressions<2> -@anchor{cp/topics/expressions working-with-pointers-structs-and-unions}@anchor{222} +@anchor{cp/topics/expressions working-with-pointers-structs-and-unions}@anchor{2e2} @subsubsection Working with pointers, structs and unions @geindex gccjit;;rvalue;;dereference (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{223}@anchor{cp/topics/expressions gccjit rvalue dereference__gccjit location}@anchor{224} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::rvalue::dereference (gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{2e3}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{2e4}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue11dereferenceEN6gccjit8locationE}@anchor{2e5}@anchor{cp/topics/expressions gccjit rvalue dereference__gccjit location}@anchor{2e6} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{146,,rvalue}::dereference (gccjit::location loc) Given an rvalue of pointer type @code{T *}, dereferencing the pointer, getting an lvalue of type @code{T}. Analogous to: @@ -13084,8 +13543,8 @@ If you don’t need to specify the location, this can also be expressed using an overloaded operator: @geindex gccjit;;rvalue;;operator* (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6rvaluemlEv}@anchor{225}@anchor{cp/topics/expressions gccjit rvalue mul-operator}@anchor{226} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::rvalue::operator* () +@anchor{cp/topics/expressions _CPPv4N6gccjit6rvaluemlEv}@anchor{2e7}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvaluemlEv}@anchor{2e8}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvaluemlEv}@anchor{2e9}@anchor{cp/topics/expressions gccjit rvalue mul-operator}@anchor{2ea} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{146,,rvalue}::operator* () @example gccjit::lvalue content = *ptr; @@ -13095,8 +13554,8 @@ gccjit::lvalue content = *ptr; Field access is provided separately for both lvalues and rvalues: @geindex gccjit;;lvalue;;access_field (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{227}@anchor{cp/topics/expressions gccjit lvalue access_field__gccjit field gccjit location}@anchor{228} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::lvalue::access_field (gccjit::field field, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2eb}@anchor{cp/topics/expressions _CPPv3N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2ec}@anchor{cp/topics/expressions _CPPv2N6gccjit6lvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2ed}@anchor{cp/topics/expressions gccjit lvalue access_field__gccjit field gccjit location}@anchor{2ee} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{14f,,lvalue}::access_field (gccjit::field field, gccjit::location loc) Given an lvalue of struct or union type, access the given field, getting an lvalue of the field’s type. Analogous to: @@ -13109,8 +13568,8 @@ in C. @end deffn @geindex gccjit;;rvalue;;access_field (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{229}@anchor{cp/topics/expressions gccjit rvalue access_field__gccjit field gccjit location}@anchor{22a} -@deffn {C++ Function} gccjit::@ref{136,,rvalue} gccjit::rvalue::access_field (gccjit::field field, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2ef}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2f0}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue12access_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2f1}@anchor{cp/topics/expressions gccjit rvalue access_field__gccjit field gccjit location}@anchor{2f2} +@deffn {C++ Function} gccjit::@ref{146,,rvalue} gccjit::@ref{146,,rvalue}::access_field (gccjit::field field, gccjit::location loc) Given an rvalue of struct or union type, access the given field as an rvalue. Analogous to: @@ -13123,8 +13582,8 @@ in C. @end deffn @geindex gccjit;;rvalue;;dereference_field (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{22b}@anchor{cp/topics/expressions gccjit rvalue dereference_field__gccjit field gccjit location}@anchor{22c} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::rvalue::dereference_field (gccjit::field field, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2f3}@anchor{cp/topics/expressions _CPPv3N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2f4}@anchor{cp/topics/expressions _CPPv2N6gccjit6rvalue17dereference_fieldEN6gccjit5fieldEN6gccjit8locationE}@anchor{2f5}@anchor{cp/topics/expressions gccjit rvalue dereference_field__gccjit field gccjit location}@anchor{2f6} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{146,,rvalue}::dereference_field (gccjit::field field, gccjit::location loc) Given an rvalue of pointer type @code{T *} where T is of struct or union type, access the given field as an lvalue. Analogous to: @@ -13137,8 +13596,8 @@ in C, itself equivalent to @code{(*EXPR).FIELD}. @end deffn @geindex gccjit;;context;;new_array_access (C++ function) -@anchor{cp/topics/expressions _CPPv2N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{22d}@anchor{cp/topics/expressions gccjit context new_array_access__gccjit rvalue gccjit rvalue gccjit location}@anchor{22e} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::context::new_array_access (gccjit::rvalue ptr, gccjit::rvalue index, gccjit::location loc) +@anchor{cp/topics/expressions _CPPv4N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2f7}@anchor{cp/topics/expressions _CPPv3N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2f8}@anchor{cp/topics/expressions _CPPv2N6gccjit7context16new_array_accessEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2f9}@anchor{cp/topics/expressions gccjit context new_array_access__gccjit rvalue gccjit rvalue gccjit location}@anchor{2fa} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{13d,,context}::new_array_access (gccjit::rvalue ptr, gccjit::rvalue index, gccjit::location loc) Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at the given index, using standard C array indexing rules i.e. each @@ -13154,7 +13613,7 @@ in C (or, indeed, to @code{PTR + INDEX}). Parameter “loc” is optional. @end deffn -For array accesses where you don’t need to specify a @ref{153,,gccjit;;location}, +For array accesses where you don’t need to specify a @ref{163,,gccjit;;location}, two overloaded operators are available: @quotation @@ -13190,7 +13649,7 @@ gccjit::lvalue element = array[0]; @c . @node Creating and using functions<2>,Source Locations<2>,Expressions<2>,Topic Reference<2> -@anchor{cp/topics/functions doc}@anchor{22f}@anchor{cp/topics/functions creating-and-using-functions}@anchor{230} +@anchor{cp/topics/functions doc}@anchor{2fb}@anchor{cp/topics/functions creating-and-using-functions}@anchor{2fc} @subsection Creating and using functions @@ -13203,36 +13662,36 @@ gccjit::lvalue element = array[0]; @end menu @node Params<2>,Functions<2>,,Creating and using functions<2> -@anchor{cp/topics/functions params}@anchor{231} +@anchor{cp/topics/functions params}@anchor{2fd} @subsubsection Params @geindex gccjit;;param (C++ class) -@anchor{cp/topics/functions _CPPv2N6gccjit5paramE}@anchor{140}@anchor{cp/topics/functions gccjit param}@anchor{232} +@anchor{cp/topics/functions _CPPv4N6gccjit5paramE}@anchor{150}@anchor{cp/topics/functions _CPPv3N6gccjit5paramE}@anchor{2fe}@anchor{cp/topics/functions _CPPv2N6gccjit5paramE}@anchor{2ff}@anchor{cp/topics/functions gccjit param}@anchor{300} @deffn {C++ Class} gccjit::param A @cite{gccjit::param} represents a parameter to a function. @end deffn @geindex gccjit;;context;;new_param (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{134}@anchor{cp/topics/functions gccjit context new_param__gccjit type cCP gccjit location}@anchor{233} -@deffn {C++ Function} gccjit::@ref{140,,param} gccjit::context::new_param (gccjit::type type, const char *name, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{144}@anchor{cp/topics/functions _CPPv3N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{301}@anchor{cp/topics/functions _CPPv2N6gccjit7context9new_paramEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{302}@anchor{cp/topics/functions gccjit context new_param__gccjit type cCP gccjit location}@anchor{303} +@deffn {C++ Function} gccjit::@ref{150,,param} gccjit::@ref{13d,,context}::new_param (gccjit::type type, const char *name, gccjit::location loc) In preparation for creating a function, create a new parameter of the given type and name. @end deffn -@ref{140,,gccjit;;param} is a subclass of @ref{13f,,gccjit;;lvalue} (and thus -of @ref{136,,gccjit;;rvalue} and @ref{132,,gccjit;;object}). It is a thin +@ref{150,,gccjit;;param} is a subclass of @ref{14f,,gccjit;;lvalue} (and thus +of @ref{146,,gccjit;;rvalue} and @ref{142,,gccjit;;object}). It is a thin wrapper around the C API’s @ref{25,,gcc_jit_param *}. @node Functions<2>,Blocks<2>,Params<2>,Creating and using functions<2> -@anchor{cp/topics/functions functions}@anchor{234} +@anchor{cp/topics/functions functions}@anchor{304} @subsubsection Functions @geindex gccjit;;function (C++ class) -@anchor{cp/topics/functions _CPPv2N6gccjit8functionE}@anchor{144}@anchor{cp/topics/functions gccjit function}@anchor{235} +@anchor{cp/topics/functions _CPPv4N6gccjit8functionE}@anchor{154}@anchor{cp/topics/functions _CPPv3N6gccjit8functionE}@anchor{305}@anchor{cp/topics/functions _CPPv2N6gccjit8functionE}@anchor{306}@anchor{cp/topics/functions gccjit function}@anchor{307} @deffn {C++ Class} gccjit::function A @cite{gccjit::function} represents a function - either one that we’re @@ -13240,8 +13699,8 @@ creating ourselves, or one that we’re referencing. @end deffn @geindex gccjit;;context;;new_function (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{236}@anchor{cp/topics/functions gccjit context new_function__gcc_jit_function_kind gccjit type cCP std vector param R i gccjit location}@anchor{237} -@deffn {C++ Function} gccjit::@ref{144,,function} gccjit::context::new_function (enum gcc_jit_function_kind, gccjit::type return_type, const char *name, std::vector ¶ms, int is_variadic, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{308}@anchor{cp/topics/functions _CPPv3N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{309}@anchor{cp/topics/functions _CPPv2N6gccjit7context12new_functionE21gcc_jit_function_kindN6gccjit4typeEPKcRNSt6vectorI5paramEEiN6gccjit8locationE}@anchor{30a}@anchor{cp/topics/functions gccjit context new_function__gcc_jit_function_kind gccjit type cCP std vector param R i gccjit location}@anchor{30b} +@deffn {C++ Function} gccjit::@ref{154,,function} gccjit::@ref{13d,,context}::new_function (enum gcc_jit_function_kind, gccjit::type return_type, const char *name, std::vector ¶ms, int is_variadic, gccjit::location loc) Create a gcc_jit_function with the given name and parameters. @@ -13251,49 +13710,49 @@ This is a wrapper around the C API’s @ref{11,,gcc_jit_context_new_function()}. @end deffn @geindex gccjit;;context;;get_builtin_function (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit7context20get_builtin_functionEPKc}@anchor{238}@anchor{cp/topics/functions gccjit context get_builtin_function__cCP}@anchor{239} -@deffn {C++ Function} gccjit::@ref{144,,function} gccjit::context::get_builtin_function (const char *name) +@anchor{cp/topics/functions _CPPv4N6gccjit7context20get_builtin_functionEPKc}@anchor{30c}@anchor{cp/topics/functions _CPPv3N6gccjit7context20get_builtin_functionEPKc}@anchor{30d}@anchor{cp/topics/functions _CPPv2N6gccjit7context20get_builtin_functionEPKc}@anchor{30e}@anchor{cp/topics/functions gccjit context get_builtin_function__cCP}@anchor{30f} +@deffn {C++ Function} gccjit::@ref{154,,function} gccjit::@ref{13d,,context}::get_builtin_function (const char *name) This is a wrapper around the C API’s @ref{e1,,gcc_jit_context_get_builtin_function()}. @end deffn @geindex gccjit;;function;;get_param (C++ function) -@anchor{cp/topics/functions _CPPv2NK6gccjit8function9get_paramEi}@anchor{23a}@anchor{cp/topics/functions gccjit function get_param__iC}@anchor{23b} -@deffn {C++ Function} gccjit::@ref{140,,param} gccjit::function::get_param (int index) const +@anchor{cp/topics/functions _CPPv4NK6gccjit8function9get_paramEi}@anchor{310}@anchor{cp/topics/functions _CPPv3NK6gccjit8function9get_paramEi}@anchor{311}@anchor{cp/topics/functions _CPPv2NK6gccjit8function9get_paramEi}@anchor{312}@anchor{cp/topics/functions gccjit function get_param__iC}@anchor{313} +@deffn {C++ Function} gccjit::@ref{150,,param} gccjit::@ref{154,,function}::get_param (int index) const Get the param of the given index (0-based). @end deffn @geindex gccjit;;function;;dump_to_dot (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit8function11dump_to_dotEPKc}@anchor{14c}@anchor{cp/topics/functions gccjit function dump_to_dot__cCP}@anchor{23c} -@deffn {C++ Function} void gccjit::function::dump_to_dot (const char *path) +@anchor{cp/topics/functions _CPPv4N6gccjit8function11dump_to_dotEPKc}@anchor{15c}@anchor{cp/topics/functions _CPPv3N6gccjit8function11dump_to_dotEPKc}@anchor{314}@anchor{cp/topics/functions _CPPv2N6gccjit8function11dump_to_dotEPKc}@anchor{315}@anchor{cp/topics/functions gccjit function dump_to_dot__cCP}@anchor{316} +@deffn {C++ Function} void gccjit::@ref{154,,function}::dump_to_dot (const char *path) Emit the function in graphviz format to the given path. @end deffn @geindex gccjit;;function;;new_local (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{141}@anchor{cp/topics/functions gccjit function new_local__gccjit type cCP gccjit location}@anchor{23d} -@deffn {C++ Function} gccjit::@ref{13f,,lvalue} gccjit::function::new_local (gccjit::type type, const char *name, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{151}@anchor{cp/topics/functions _CPPv3N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{317}@anchor{cp/topics/functions _CPPv2N6gccjit8function9new_localEN6gccjit4typeEPKcN6gccjit8locationE}@anchor{318}@anchor{cp/topics/functions gccjit function new_local__gccjit type cCP gccjit location}@anchor{319} +@deffn {C++ Function} gccjit::@ref{14f,,lvalue} gccjit::@ref{154,,function}::new_local (gccjit::type type, const char *name, gccjit::location loc) Create a new local variable within the function, of the given type and name. @end deffn @node Blocks<2>,Statements<2>,Functions<2>,Creating and using functions<2> -@anchor{cp/topics/functions blocks}@anchor{23e} +@anchor{cp/topics/functions blocks}@anchor{31a} @subsubsection Blocks @geindex gccjit;;block (C++ class) -@anchor{cp/topics/functions _CPPv2N6gccjit5blockE}@anchor{143}@anchor{cp/topics/functions gccjit block}@anchor{23f} +@anchor{cp/topics/functions _CPPv4N6gccjit5blockE}@anchor{153}@anchor{cp/topics/functions _CPPv3N6gccjit5blockE}@anchor{31b}@anchor{cp/topics/functions _CPPv2N6gccjit5blockE}@anchor{31c}@anchor{cp/topics/functions gccjit block}@anchor{31d} @deffn {C++ Class} gccjit::block A @cite{gccjit::block} represents a basic block within a function i.e. a sequence of statements with a single entry point and a single exit point. -@ref{143,,gccjit;;block} is a subclass of @ref{132,,gccjit;;object}. +@ref{153,,gccjit;;block} is a subclass of @ref{142,,gccjit;;object}. The first basic block that you create within a function will be the entrypoint. @@ -13307,8 +13766,8 @@ one function. @end deffn @geindex gccjit;;function;;new_block (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit8function9new_blockEPKc}@anchor{240}@anchor{cp/topics/functions gccjit function new_block__cCP}@anchor{241} -@deffn {C++ Function} gccjit::@ref{143,,block} gccjit::function::new_block (const char *name) +@anchor{cp/topics/functions _CPPv4N6gccjit8function9new_blockEPKc}@anchor{31e}@anchor{cp/topics/functions _CPPv3N6gccjit8function9new_blockEPKc}@anchor{31f}@anchor{cp/topics/functions _CPPv2N6gccjit8function9new_blockEPKc}@anchor{320}@anchor{cp/topics/functions gccjit function new_block__cCP}@anchor{321} +@deffn {C++ Function} gccjit::@ref{153,,block} gccjit::@ref{154,,function}::new_block (const char *name) Create a basic block of the given name. The name may be NULL, but providing meaningful names is often helpful when debugging: it may @@ -13317,13 +13776,13 @@ messages. @end deffn @node Statements<2>,,Blocks<2>,Creating and using functions<2> -@anchor{cp/topics/functions statements}@anchor{242} +@anchor{cp/topics/functions statements}@anchor{322} @subsubsection Statements @geindex gccjit;;block;;add_eval (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{214}@anchor{cp/topics/functions gccjit block add_eval__gccjit rvalue gccjit location}@anchor{243} -@deffn {C++ Function} void gccjit::block::add_eval (gccjit::rvalue rvalue, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{2ca}@anchor{cp/topics/functions _CPPv3N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{323}@anchor{cp/topics/functions _CPPv2N6gccjit5block8add_evalEN6gccjit6rvalueEN6gccjit8locationE}@anchor{324}@anchor{cp/topics/functions gccjit block add_eval__gccjit rvalue gccjit location}@anchor{325} +@deffn {C++ Function} void gccjit::@ref{153,,block}::add_eval (gccjit::rvalue rvalue, gccjit::location loc) Add evaluation of an rvalue, discarding the result (e.g. a function call that “returns” void). @@ -13336,8 +13795,8 @@ This is equivalent to this C code: @end deffn @geindex gccjit;;block;;add_assignment (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{145}@anchor{cp/topics/functions gccjit block add_assignment__gccjit lvalue gccjit rvalue gccjit location}@anchor{244} -@deffn {C++ Function} void gccjit::block::add_assignment (gccjit::lvalue lvalue, gccjit::rvalue rvalue, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{155}@anchor{cp/topics/functions _CPPv3N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{326}@anchor{cp/topics/functions _CPPv2N6gccjit5block14add_assignmentEN6gccjit6lvalueEN6gccjit6rvalueEN6gccjit8locationE}@anchor{327}@anchor{cp/topics/functions gccjit block add_assignment__gccjit lvalue gccjit rvalue gccjit location}@anchor{328} +@deffn {C++ Function} void gccjit::@ref{153,,block}::add_assignment (gccjit::lvalue lvalue, gccjit::rvalue rvalue, gccjit::location loc) Add evaluation of an rvalue, assigning the result to the given lvalue. @@ -13350,8 +13809,8 @@ lvalue = rvalue; @end deffn @geindex gccjit;;block;;add_assignment_op (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{149}@anchor{cp/topics/functions gccjit block add_assignment_op__gccjit lvalue gcc_jit_binary_op gccjit rvalue gccjit location}@anchor{245} -@deffn {C++ Function} void gccjit::block::add_assignment_op (gccjit::lvalue lvalue, enum gcc_jit_binary_op, gccjit::rvalue rvalue, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{159}@anchor{cp/topics/functions _CPPv3N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{329}@anchor{cp/topics/functions _CPPv2N6gccjit5block17add_assignment_opEN6gccjit6lvalueE17gcc_jit_binary_opN6gccjit6rvalueEN6gccjit8locationE}@anchor{32a}@anchor{cp/topics/functions gccjit block add_assignment_op__gccjit lvalue gcc_jit_binary_op gccjit rvalue gccjit location}@anchor{32b} +@deffn {C++ Function} void gccjit::@ref{153,,block}::add_assignment_op (gccjit::lvalue lvalue, enum gcc_jit_binary_op, gccjit::rvalue rvalue, gccjit::location loc) Add evaluation of an rvalue, using the result to modify an lvalue. @@ -13376,8 +13835,8 @@ loop_body.add_assignment_op ( @end deffn @geindex gccjit;;block;;add_comment (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{155}@anchor{cp/topics/functions gccjit block add_comment__cCP gccjit location}@anchor{246} -@deffn {C++ Function} void gccjit::block::add_comment (const char *text, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{165}@anchor{cp/topics/functions _CPPv3N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{32c}@anchor{cp/topics/functions _CPPv2N6gccjit5block11add_commentEPKcN6gccjit8locationE}@anchor{32d}@anchor{cp/topics/functions gccjit block add_comment__cCP gccjit location}@anchor{32e} +@deffn {C++ Function} void gccjit::@ref{153,,block}::add_comment (const char *text, gccjit::location loc) Add a no-op textual comment to the internal representation of the code. It will be optimized away, but will be visible in the dumps @@ -13390,8 +13849,8 @@ Parameter “loc” is optional. @end deffn @geindex gccjit;;block;;end_with_conditional (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{148}@anchor{cp/topics/functions gccjit block end_with_conditional__gccjit rvalue gccjit block gccjit block gccjit location}@anchor{247} -@deffn {C++ Function} void gccjit::block::end_with_conditional (gccjit::rvalue boolval, gccjit::block on_true, gccjit::block on_false, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{158}@anchor{cp/topics/functions _CPPv3N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{32f}@anchor{cp/topics/functions _CPPv2N6gccjit5block20end_with_conditionalEN6gccjit6rvalueEN6gccjit5blockEN6gccjit5blockEN6gccjit8locationE}@anchor{330}@anchor{cp/topics/functions gccjit block end_with_conditional__gccjit rvalue gccjit block gccjit block gccjit location}@anchor{331} +@deffn {C++ Function} void gccjit::@ref{153,,block}::end_with_conditional (gccjit::rvalue boolval, gccjit::block on_true, gccjit::block on_false, gccjit::location loc) Terminate a block by adding evaluation of an rvalue, branching on the result to the appropriate successor block. @@ -13409,8 +13868,8 @@ block, boolval, on_true, and on_false must be non-NULL. @end deffn @geindex gccjit;;block;;end_with_jump (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{248}@anchor{cp/topics/functions gccjit block end_with_jump__gccjit block gccjit location}@anchor{249} -@deffn {C++ Function} void gccjit::block::end_with_jump (gccjit::block target, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{332}@anchor{cp/topics/functions _CPPv3N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{333}@anchor{cp/topics/functions _CPPv2N6gccjit5block13end_with_jumpEN6gccjit5blockEN6gccjit8locationE}@anchor{334}@anchor{cp/topics/functions gccjit block end_with_jump__gccjit block gccjit location}@anchor{335} +@deffn {C++ Function} void gccjit::@ref{153,,block}::end_with_jump (gccjit::block target, gccjit::location loc) Terminate a block by adding a jump to the given target block. @@ -13422,8 +13881,8 @@ goto target; @end deffn @geindex gccjit;;block;;end_with_return (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{24a}@anchor{cp/topics/functions gccjit block end_with_return__gccjit rvalue gccjit location}@anchor{24b} -@deffn {C++ Function} void gccjit::block::end_with_return (gccjit::rvalue rvalue, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{336}@anchor{cp/topics/functions _CPPv3N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{337}@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_returnEN6gccjit6rvalueEN6gccjit8locationE}@anchor{338}@anchor{cp/topics/functions gccjit block end_with_return__gccjit rvalue gccjit location}@anchor{339} +@deffn {C++ Function} void gccjit::@ref{153,,block}::end_with_return (gccjit::rvalue rvalue, gccjit::location loc) Terminate a block. @@ -13452,8 +13911,8 @@ return; @end deffn @geindex gccjit;;block;;end_with_switch (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{24c}@anchor{cp/topics/functions gccjit block end_with_switch__gccjit rvalue gccjit block std vector gccjit case_ gccjit location}@anchor{24d} -@deffn {C++ Function} void gccjit::block::end_with_switch (gccjit::rvalue expr, gccjit::block default_block, std::vector cases, gccjit::location loc) +@anchor{cp/topics/functions _CPPv4N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{33a}@anchor{cp/topics/functions _CPPv3N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{33b}@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_switchEN6gccjit6rvalueEN6gccjit5blockENSt6vectorIN6gccjit5case_EEEN6gccjit8locationE}@anchor{33c}@anchor{cp/topics/functions gccjit block end_with_switch__gccjit rvalue gccjit block std vector gccjit case_ gccjit location}@anchor{33d} +@deffn {C++ Function} void gccjit::@ref{153,,block}::end_with_switch (gccjit::rvalue expr, gccjit::block default_block, std::vector cases, gccjit::location loc) Terminate a block by adding evalation of an rvalue, then performing a multiway branch. @@ -13493,10 +13952,10 @@ The API entrypoints relating to switch statements and cases: @itemize * @item -@code{gccjit::block::end_with_switch()} +@ref{33a,,gccjit;;block;;end_with_switch()} @item -@ref{24e,,gccjit;;context;;new_case()} +@code{gccjit::context::new_case()} @end itemize @end quotation @@ -13507,32 +13966,15 @@ using #ifdef LIBGCCJIT_HAVE_SWITCH_STATEMENTS @end example -@geindex gccjit;;block;;end_with_switch;;gccjit;;case_ (C++ class) -@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_switch6gccjit5case_E}@anchor{24f}@anchor{cp/topics/functions gccjit block end_with_switch gccjit case_}@anchor{250} -@deffn {C++ Class} gccjit::case_ -@end deffn - A @cite{gccjit::case_} represents a case within a switch statement, and -is created within a particular @code{gccjit::context} using -@ref{24e,,gccjit;;context;;new_case()}. It is a subclass of -@code{gccjit::object}. +is created within a particular @ref{13d,,gccjit;;context} using +@code{gccjit::context::new_case()}. It is a subclass of +@ref{142,,gccjit;;object}. Each case expresses a multivalued range of integer values. You can express single-valued cases by passing in the same value for both @cite{min_value} and @cite{max_value}. -@geindex gccjit;;block;;end_with_switch;;gccjit;;context;;new_case (C++ function) -@anchor{cp/topics/functions _CPPv2N6gccjit5block15end_with_switch6gccjit7context8new_caseEN6gccjit6rvalueEN6gccjit6rvalueEN6gccjit5blockE}@anchor{24e}@anchor{cp/topics/functions gccjit block end_with_switch gccjit context new_case__gccjit rvalue gccjit rvalue gccjit block}@anchor{251} -@deffn {C++ Function} gccjit::@ref{24f,,case_} *gccjit::context::new_case (gccjit::rvalue min_value, gccjit::rvalue max_value, gccjit::block dest_block) - -Create a new gccjit::case for use in a switch statement. -@cite{min_value} and @cite{max_value} must be constants of an integer type, -which must match that of the expression of the switch statement. - -@cite{dest_block} must be within the same function as the switch -statement. -@end deffn - Here’s an example of creating a switch statement: @quotation @@ -13630,12 +14072,12 @@ create_code (gcc_jit_context *c_ctxt, void *user_data) @c . @node Source Locations<2>,Compiling a context<2>,Creating and using functions<2>,Topic Reference<2> -@anchor{cp/topics/locations source-locations}@anchor{252}@anchor{cp/topics/locations doc}@anchor{253} +@anchor{cp/topics/locations doc}@anchor{33e}@anchor{cp/topics/locations source-locations}@anchor{33f} @subsection Source Locations @geindex gccjit;;location (C++ class) -@anchor{cp/topics/locations _CPPv2N6gccjit8locationE}@anchor{153}@anchor{cp/topics/locations gccjit location}@anchor{254} +@anchor{cp/topics/locations _CPPv4N6gccjit8locationE}@anchor{163}@anchor{cp/topics/locations _CPPv3N6gccjit8locationE}@anchor{340}@anchor{cp/topics/locations _CPPv2N6gccjit8locationE}@anchor{341}@anchor{cp/topics/locations gccjit location}@anchor{342} @deffn {C++ Class} gccjit::location A @cite{gccjit::location} encapsulates a source code location, so that @@ -13646,10 +14088,10 @@ single-step through your language. @cite{gccjit::location} instances are optional: you can always omit them from any C++ API entrypoint accepting one. -You can construct them using @ref{159,,gccjit;;context;;new_location()}. +You can construct them using @ref{169,,gccjit;;context;;new_location()}. You need to enable @ref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the -@ref{12d,,gccjit;;context} for these locations to actually be usable by +@ref{13d,,gccjit;;context} for these locations to actually be usable by the debugger: @example @@ -13658,8 +14100,8 @@ ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1); @end deffn @geindex gccjit;;context;;new_location (C++ function) -@anchor{cp/topics/locations _CPPv2N6gccjit7context12new_locationEPKcii}@anchor{159}@anchor{cp/topics/locations gccjit context new_location__cCP i i}@anchor{255} -@deffn {C++ Function} gccjit::@ref{153,,location} gccjit::context::new_location (const char *filename, int line, int column) +@anchor{cp/topics/locations _CPPv4N6gccjit7context12new_locationEPKcii}@anchor{169}@anchor{cp/topics/locations _CPPv3N6gccjit7context12new_locationEPKcii}@anchor{343}@anchor{cp/topics/locations _CPPv2N6gccjit7context12new_locationEPKcii}@anchor{344}@anchor{cp/topics/locations gccjit context new_location__cCP i i}@anchor{345} +@deffn {C++ Function} gccjit::@ref{163,,location} gccjit::@ref{13d,,context}::new_location (const char *filename, int line, int column) Create a @cite{gccjit::location} instance representing the given source location. @@ -13671,13 +14113,13 @@ location. @end menu @node Faking it<2>,,,Source Locations<2> -@anchor{cp/topics/locations faking-it}@anchor{256} +@anchor{cp/topics/locations faking-it}@anchor{346} @subsubsection Faking it If you don’t have source code for your internal representation, but need to debug, you can generate a C-like representation of the functions in -your context using @ref{16e,,gccjit;;context;;dump_to_file()}: +your context using @ref{188,,gccjit;;context;;dump_to_file()}: @example ctxt.dump_to_file ("/tmp/something.c", @@ -13706,14 +14148,14 @@ file, giving you @emph{something} you can step through in the debugger. @c along with this program. If not, see @c . -@node Compiling a context<2>,,Source Locations<2>,Topic Reference<2> -@anchor{cp/topics/compilation compiling-a-context}@anchor{257}@anchor{cp/topics/compilation doc}@anchor{258} +@node Compiling a context<2>,Using Assembly Language with libgccjit++,Source Locations<2>,Topic Reference<2> +@anchor{cp/topics/compilation doc}@anchor{347}@anchor{cp/topics/compilation compiling-a-context}@anchor{348} @subsection Compiling a context -Once populated, a @ref{12d,,gccjit;;context} can be compiled to -machine code, either in-memory via @ref{137,,gccjit;;context;;compile()} or -to disk via @ref{259,,gccjit;;context;;compile_to_file()}. +Once populated, a @ref{13d,,gccjit;;context} can be compiled to +machine code, either in-memory via @ref{147,,gccjit;;context;;compile()} or +to disk via @ref{349,,gccjit;;context;;compile_to_file()}. You can compile a context multiple times (using either form of compilation), although any errors that occur on the context will @@ -13726,13 +14168,13 @@ prevent any future compilation of that context. @end menu @node In-memory compilation<2>,Ahead-of-time compilation<2>,,Compiling a context<2> -@anchor{cp/topics/compilation in-memory-compilation}@anchor{25a} +@anchor{cp/topics/compilation in-memory-compilation}@anchor{34a} @subsubsection In-memory compilation @geindex gccjit;;context;;compile (C++ function) -@anchor{cp/topics/compilation _CPPv2N6gccjit7context7compileEv}@anchor{137}@anchor{cp/topics/compilation gccjit context compile}@anchor{25b} -@deffn {C++ Function} gcc_jit_result *gccjit::context::compile () +@anchor{cp/topics/compilation _CPPv4N6gccjit7context7compileEv}@anchor{147}@anchor{cp/topics/compilation _CPPv3N6gccjit7context7compileEv}@anchor{34b}@anchor{cp/topics/compilation _CPPv2N6gccjit7context7compileEv}@anchor{34c}@anchor{cp/topics/compilation gccjit context compile}@anchor{34d} +@deffn {C++ Function} gcc_jit_result *gccjit::@ref{13d,,context}::compile () This calls into GCC and builds the code, returning a @cite{gcc_jit_result *}. @@ -13742,25 +14184,418 @@ This is a thin wrapper around the @end deffn @node Ahead-of-time compilation<2>,,In-memory compilation<2>,Compiling a context<2> -@anchor{cp/topics/compilation ahead-of-time-compilation}@anchor{25c} +@anchor{cp/topics/compilation ahead-of-time-compilation}@anchor{34e} @subsubsection Ahead-of-time compilation Although libgccjit is primarily aimed at just-in-time compilation, it can also be used for implementing more traditional ahead-of-time -compilers, via the @ref{259,,gccjit;;context;;compile_to_file()} method. +compilers, via the @ref{349,,gccjit;;context;;compile_to_file()} method. @geindex gccjit;;context;;compile_to_file (C++ function) -@anchor{cp/topics/compilation _CPPv2N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{259}@anchor{cp/topics/compilation gccjit context compile_to_file__gcc_jit_output_kind cCP}@anchor{25d} -@deffn {C++ Function} void gccjit::context::compile_to_file (enum gcc_jit_output_kind, const char *output_path) +@anchor{cp/topics/compilation _CPPv4N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{349}@anchor{cp/topics/compilation _CPPv3N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{34f}@anchor{cp/topics/compilation _CPPv2N6gccjit7context15compile_to_fileE19gcc_jit_output_kindPKc}@anchor{350}@anchor{cp/topics/compilation gccjit context compile_to_file__gcc_jit_output_kind cCP}@anchor{351} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::compile_to_file (enum gcc_jit_output_kind, const char *output_path) -Compile the @ref{12d,,gccjit;;context} to a file of the given +Compile the @ref{13d,,gccjit;;context} to a file of the given kind. This is a thin wrapper around the @ref{4a,,gcc_jit_context_compile_to_file()} API entrypoint. @end deffn +@c Copyright (C) 2020 Free Software Foundation, Inc. +@c Originally contributed by David Malcolm +@c +@c This is free software: you can redistribute it and/or modify it +@c under the terms of the GNU General Public License as published by +@c the Free Software Foundation, either version 3 of the License, or +@c (at your option) any later version. +@c +@c This program is distributed in the hope that it will be useful, but +@c WITHOUT ANY WARRANTY; without even the implied warranty of +@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +@c General Public License for more details. +@c +@c You should have received a copy of the GNU General Public License +@c along with this program. If not, see +@c . + +@node Using Assembly Language with libgccjit++,,Compiling a context<2>,Topic Reference<2> +@anchor{cp/topics/asm doc}@anchor{352}@anchor{cp/topics/asm using-assembly-language-with-libgccjit}@anchor{353} +@subsection Using Assembly Language with libgccjit++ + + +libgccjit has some support for directly embedding assembler instructions. +This is based on GCC’s support for inline @code{asm} in C code, and the +following assumes a familiarity with that functionality. See +How to Use Inline Assembly Language in C Code@footnote{https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html} +in GCC’s documentation, the “Extended Asm” section in particular. + +These entrypoints were added in @ref{122,,LIBGCCJIT_ABI_15}; you can test +for their presence using + +@quotation + +@example +#ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS +@end example +@end quotation + +@menu +* Adding assembler instructions within a function: Adding assembler instructions within a function<2>. +* Adding top-level assembler statements: Adding top-level assembler statements<2>. + +@end menu + +@node Adding assembler instructions within a function<2>,Adding top-level assembler statements<2>,,Using Assembly Language with libgccjit++ +@anchor{cp/topics/asm adding-assembler-instructions-within-a-function}@anchor{354} +@subsubsection Adding assembler instructions within a function + + +@geindex gccjit;;extended_asm (C++ class) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asmE}@anchor{355}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asmE}@anchor{356}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asmE}@anchor{357}@anchor{cp/topics/asm gccjit extended_asm}@anchor{358} +@deffn {C++ Class} gccjit::extended_asm + +A @cite{gccjit::extended_asm} represents an extended @code{asm} statement: a +series of low-level instructions inside a function that convert inputs +to outputs. + +@ref{355,,gccjit;;extended_asm} is a subclass of @ref{142,,gccjit;;object}. +It is a thin wrapper around the C API’s @ref{f1,,gcc_jit_extended_asm *}. + +To avoid having an API entrypoint with a very large number of +parameters, an extended @code{asm} statement is made in stages: +an initial call to create the @ref{355,,gccjit;;extended_asm}, +followed by calls to add operands and set other properties of the +statement. + +There are two API entrypoints for creating a @ref{355,,gccjit;;extended_asm}: + + +@itemize * + +@item +@ref{359,,gccjit;;block;;add_extended_asm()} for an @code{asm} statement with +no control flow, and + +@item +@ref{35a,,gccjit;;block;;end_with_extended_asm_goto()} for an @code{asm goto}. +@end itemize + +For example, to create the equivalent of: + +@example + asm ("mov %1, %0\n\t" + "add $1, %0" + : "=r" (dst) + : "r" (src)); +@end example + +the following API calls could be used: + +@example + block.add_extended_asm ("mov %1, %0\n\t" + "add $1, %0") + .add_output_operand ("=r", dst) + .add_input_operand ("r", src); +@end example + +@cartouche +@quotation Warning +When considering the numbering of operands within an +extended @code{asm} statement (e.g. the @code{%0} and @code{%1} +above), the equivalent to the C syntax is followed i.e. all +output operands, then all input operands, regardless of +what order the calls to +@ref{35b,,gccjit;;extended_asm;;add_output_operand()} and +@ref{35c,,gccjit;;extended_asm;;add_input_operand()} were made in. +@end quotation +@end cartouche + +As in the C syntax, operands can be given symbolic names to avoid having +to number them. For example, to create the equivalent of: + +@example + asm ("bsfl %[aMask], %[aIndex]" + : [aIndex] "=r" (Index) + : [aMask] "r" (Mask) + : "cc"); +@end example + +the following API calls could be used: + +@example + block.add_extended_asm ("bsfl %[aMask], %[aIndex]") + .add_output_operand ("aIndex", "=r", index) + .add_input_operand ("aMask", "r", mask) + .add_clobber ("cc"); +@end example +@end deffn + +@geindex gccjit;;block;;add_extended_asm (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit5block16add_extended_asmERKNSt6stringEN6gccjit8locationE}@anchor{359}@anchor{cp/topics/asm _CPPv3N6gccjit5block16add_extended_asmERKNSt6stringEN6gccjit8locationE}@anchor{35d}@anchor{cp/topics/asm _CPPv2N6gccjit5block16add_extended_asmERKNSt6stringEN6gccjit8locationE}@anchor{35e}@anchor{cp/topics/asm gccjit block add_extended_asm__ssCR gccjit location}@anchor{35f} +@deffn {C++ Function} @ref{355,,extended_asm} gccjit::@ref{153,,block}::add_extended_asm (const std::string &asm_template, gccjit::location loc = location()) + +Create a @ref{355,,gccjit;;extended_asm} for an extended @code{asm} statement +with no control flow (i.e. without the @code{goto} qualifier). + +The parameter @code{asm_template} corresponds to the @cite{AssemblerTemplate} +within C’s extended @code{asm} syntax. It must be non-NULL. The call takes +a copy of the underlying string, so it is valid to pass in a pointer to +an on-stack buffer. +@end deffn + +@geindex gccjit;;block;;end_with_extended_asm_goto (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit5block26end_with_extended_asm_gotoERKNSt6stringENSt6vectorI5blockEEP5block8location}@anchor{35a}@anchor{cp/topics/asm _CPPv3N6gccjit5block26end_with_extended_asm_gotoERKNSt6stringENSt6vectorI5blockEEP5block8location}@anchor{360}@anchor{cp/topics/asm _CPPv2N6gccjit5block26end_with_extended_asm_gotoERKNSt6stringENSt6vectorI5blockEEP5block8location}@anchor{361}@anchor{cp/topics/asm gccjit block end_with_extended_asm_goto__ssCR std vector block blockP location}@anchor{362} +@deffn {C++ Function} @ref{355,,extended_asm} gccjit::@ref{153,,block}::end_with_extended_asm_goto (const std::string &asm_template, std::vector goto_blocks, block *fallthrough_block, location loc = location()) + +Create a @ref{355,,gccjit;;extended_asm} for an extended @code{asm} statement +that may perform jumps, and use it to terminate the given block. +This is equivalent to the @code{goto} qualifier in C’s extended @code{asm} +syntax. + +For example, to create the equivalent of: + +@example + asm goto ("btl %1, %0\n\t" + "jc %l[carry]" + : // No outputs + : "r" (p1), "r" (p2) + : "cc" + : carry); +@end example + +the following API calls could be used: + +@example + const char *asm_template = + (use_name + ? /* Label referred to by name: "%l[carry]". */ + ("btl %1, %0\n\t" + "jc %l[carry]") + : /* Label referred to numerically: "%l2". */ + ("btl %1, %0\n\t" + "jc %l2")); + + std::vector goto_blocks (@{b_carry@}); + gccjit::extended_asm ext_asm + = (b_start.end_with_extended_asm_goto (asm_template, + goto_blocks, + &b_fallthru) + .add_input_operand ("r", p1) + .add_input_operand ("r", p2) + .add_clobber ("cc")); +@end example + +here referencing a @code{gcc_jit_block} named “carry”. + +@code{num_goto_blocks} corresponds to the @code{GotoLabels} parameter within C’s +extended @code{asm} syntax. The block names can be referenced within the +assembler template. + +@code{fallthrough_block} can be NULL. If non-NULL, it specifies the block +to fall through to after the statement. + +@cartouche +@quotation Note +This is needed since each @ref{153,,gccjit;;block} must have a +single exit point, as a basic block: you can’t jump from the +middle of a block. A “goto” is implicitly added after the +asm to handle the fallthrough case, which is equivalent to what +would have happened in the C case. +@end quotation +@end cartouche +@end deffn + +@geindex gccjit;;extended_asm;;set_volatile_flag (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm17set_volatile_flagEb}@anchor{363}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm17set_volatile_flagEb}@anchor{364}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm17set_volatile_flagEb}@anchor{365}@anchor{cp/topics/asm gccjit extended_asm set_volatile_flag__b}@anchor{366} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::set_volatile_flag (bool flag) + +Set whether the @ref{355,,gccjit;;extended_asm} has side-effects, equivalent to the +volatile@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile} +qualifier in C’s extended asm syntax. + +For example, to create the equivalent of: + +@example +asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (msr) + : + : "rdx"); +@end example + +the following API calls could be used: + +@example + gccjit::extended_asm ext_asm + = block.add_extended_asm + ("rdtsc\n\t" /* Returns the time in EDX:EAX. */ + "shl $32, %%rdx\n\t" /* Shift the upper bits left. */ + "or %%rdx, %0") /* 'Or' in the lower bits. */ + .set_volatile_flag (true) + .add_output_operand ("=a", msr) + .add_clobber ("rdx"); +@end example + +where the @ref{355,,gccjit;;extended_asm} is flagged as volatile. +@end deffn + +@geindex gccjit;;extended_asm;;set_inline_flag (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm15set_inline_flagEb}@anchor{367}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm15set_inline_flagEb}@anchor{368}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm15set_inline_flagEb}@anchor{369}@anchor{cp/topics/asm gccjit extended_asm set_inline_flag__b}@anchor{36a} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::set_inline_flag (bool flag) + +Set the equivalent of the +inline@footnote{https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html#Size-of-an-asm} +qualifier in C’s extended @code{asm} syntax. +@end deffn + +@geindex gccjit;;extended_asm;;add_output_operand (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm18add_output_operandERKNSt6stringERKNSt6stringEN6gccjit6lvalueE}@anchor{35b}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm18add_output_operandERKNSt6stringERKNSt6stringEN6gccjit6lvalueE}@anchor{36b}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm18add_output_operandERKNSt6stringERKNSt6stringEN6gccjit6lvalueE}@anchor{36c}@anchor{cp/topics/asm gccjit extended_asm add_output_operand__ssCR ssCR gccjit lvalue}@anchor{36d} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::add_output_operand (const std::string &asm_symbolic_name, const std::string &constraint, gccjit::lvalue dest) + +Add an output operand to the extended @code{asm} statement. See the +Output Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands} +section of the documentation of the C syntax. + +@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component of +C’s extended @code{asm} syntax, and specifies the symbolic name for the operand. +See the overload below for an alternative that does not supply a symbolic +name. + +@code{constraint} corresponds to the @code{constraint} component of C’s extended +@code{asm} syntax. + +@code{dest} corresponds to the @code{cvariablename} component of C’s extended +@code{asm} syntax. + +@example +// Example with a symbolic name ("aIndex"), the equivalent of: +// : [aIndex] "=r" (index) +ext_asm.add_output_operand ("aIndex", "=r", index); +@end example + +This function can’t be called on an @code{asm goto} as such instructions can’t +have outputs; see the +Goto Labels@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels} +section of GCC’s “Extended Asm” documentation. +@end deffn + +@geindex gccjit;;extended_asm;;add_output_operand (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm18add_output_operandERKNSt6stringEN6gccjit6lvalueE}@anchor{36e}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm18add_output_operandERKNSt6stringEN6gccjit6lvalueE}@anchor{36f}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm18add_output_operandERKNSt6stringEN6gccjit6lvalueE}@anchor{370}@anchor{cp/topics/asm gccjit extended_asm add_output_operand__ssCR gccjit lvalue}@anchor{371} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::add_output_operand (const std::string &constraint, gccjit::lvalue dest) + +As above, but don’t supply a symbolic name for the operand. + +@example +// Example without a symbolic name, the equivalent of: +// : "=r" (dst) +ext_asm.add_output_operand ("=r", dst); +@end example +@end deffn + +@geindex gccjit;;extended_asm;;add_input_operand (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm17add_input_operandERKNSt6stringERKNSt6stringEN6gccjit6rvalueE}@anchor{35c}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm17add_input_operandERKNSt6stringERKNSt6stringEN6gccjit6rvalueE}@anchor{372}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm17add_input_operandERKNSt6stringERKNSt6stringEN6gccjit6rvalueE}@anchor{373}@anchor{cp/topics/asm gccjit extended_asm add_input_operand__ssCR ssCR gccjit rvalue}@anchor{374} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::add_input_operand (const std::string &asm_symbolic_name, const std::string &constraint, gccjit::rvalue src) + +Add an input operand to the extended @code{asm} statement. See the +Input Operands@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands} +section of the documentation of the C syntax. + +@code{asm_symbolic_name} corresponds to the @code{asmSymbolicName} component +of C’s extended @code{asm} syntax. See the overload below for an alternative +that does not supply a symbolic name. + +@code{constraint} corresponds to the @code{constraint} component of C’s extended +@code{asm} syntax. + +@code{src} corresponds to the @code{cexpression} component of C’s extended +@code{asm} syntax. + +@example +// Example with a symbolic name ("aMask"), the equivalent of: +// : [aMask] "r" (Mask) +ext_asm.add_input_operand ("aMask", "r", mask); +@end example +@end deffn + +@geindex gccjit;;extended_asm;;add_input_operand (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm17add_input_operandERKNSt6stringEN6gccjit6rvalueE}@anchor{375}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm17add_input_operandERKNSt6stringEN6gccjit6rvalueE}@anchor{376}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm17add_input_operandERKNSt6stringEN6gccjit6rvalueE}@anchor{377}@anchor{cp/topics/asm gccjit extended_asm add_input_operand__ssCR gccjit rvalue}@anchor{378} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::add_input_operand (const std::string &constraint, gccjit::rvalue src) + +As above, but don’t supply a symbolic name for the operand. + +@example +// Example without a symbolic name, the equivalent of: +// : "r" (src) +ext_asm.add_input_operand ("r", src); +@end example +@end deffn + +@geindex gccjit;;extended_asm;;add_clobber (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit12extended_asm11add_clobberERKNSt6stringE}@anchor{379}@anchor{cp/topics/asm _CPPv3N6gccjit12extended_asm11add_clobberERKNSt6stringE}@anchor{37a}@anchor{cp/topics/asm _CPPv2N6gccjit12extended_asm11add_clobberERKNSt6stringE}@anchor{37b}@anchor{cp/topics/asm gccjit extended_asm add_clobber__ssCR}@anchor{37c} +@deffn {C++ Function} gccjit::@ref{355,,extended_asm} &gccjit::@ref{355,,extended_asm}::add_clobber (const std::string &victim) + +Add @cite{victim} to the list of registers clobbered by the extended @code{asm} +statement. See the +Clobbers and Scratch Registers@footnote{https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers#} +section of the documentation of the C syntax. + +Statements with multiple clobbers will require multiple calls, one per +clobber. + +For example: + +@example +ext_asm.add_clobber ("r0").add_clobber ("cc").add_clobber ("memory"); +@end example +@end deffn + +@node Adding top-level assembler statements<2>,,Adding assembler instructions within a function<2>,Using Assembly Language with libgccjit++ +@anchor{cp/topics/asm adding-top-level-assembler-statements}@anchor{37d} +@subsubsection Adding top-level assembler statements + + +In addition to creating extended @code{asm} instructions within a function, +there is support for creating “top-level” assembler statements, outside +of any function. + +@geindex gccjit;;context;;add_top_level_asm (C++ function) +@anchor{cp/topics/asm _CPPv4N6gccjit7context17add_top_level_asmEPKcN6gccjit8locationE}@anchor{37e}@anchor{cp/topics/asm _CPPv3N6gccjit7context17add_top_level_asmEPKcN6gccjit8locationE}@anchor{37f}@anchor{cp/topics/asm _CPPv2N6gccjit7context17add_top_level_asmEPKcN6gccjit8locationE}@anchor{380}@anchor{cp/topics/asm gccjit context add_top_level_asm__cCP gccjit location}@anchor{381} +@deffn {C++ Function} void gccjit::@ref{13d,,context}::add_top_level_asm (const char *asm_stmts, gccjit::location loc = location()) + +Create a set of top-level asm statements, analogous to those created +by GCC’s “basic” @code{asm} syntax in C at file scope. + +For example, to create the equivalent of: + +@example + asm ("\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @@function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t.popsection\n"); +@end example + +the following API calls could be used: + +@example + ctxt.add_top_level_asm ("\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @@function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t# some asm here\n" + "\t.popsection\n"); +@end example +@end deffn + @c Copyright (C) 2014-2020 Free Software Foundation, Inc. @c Originally contributed by David Malcolm @c @@ -13779,7 +14614,7 @@ This is a thin wrapper around the @c . @node Internals,Indices and tables,C++ bindings for libgccjit,Top -@anchor{internals/index internals}@anchor{25e}@anchor{internals/index doc}@anchor{25f} +@anchor{internals/index doc}@anchor{382}@anchor{internals/index internals}@anchor{383} @chapter Internals @@ -13795,7 +14630,7 @@ This is a thin wrapper around the @end menu @node Working on the JIT library,Running the test suite,,Internals -@anchor{internals/index working-on-the-jit-library}@anchor{260} +@anchor{internals/index working-on-the-jit-library}@anchor{384} @section Working on the JIT library @@ -13828,7 +14663,7 @@ gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), Here’s what those configuration options mean: @geindex command line option; --enable-host-shared -@anchor{internals/index cmdoption-enable-host-shared}@anchor{261} +@anchor{internals/index cmdoption-enable-host-shared}@anchor{385} @deffn {Option} @w{-}@w{-}enable@w{-}host@w{-}shared Configuring with this option means that the compiler is built as @@ -13837,7 +14672,7 @@ but it necessary for a shared library. @end deffn @geindex command line option; --enable-languages=jit@comma{}c++ -@anchor{internals/index cmdoption-enable-languages}@anchor{262} +@anchor{internals/index cmdoption-enable-languages}@anchor{386} @deffn {Option} @w{-}@w{-}enable@w{-}languages=jit,c++ This specifies which frontends to build. The JIT library looks like @@ -13854,7 +14689,7 @@ c++: error trying to exec 'cc1plus': execvp: No such file or directory @end deffn @geindex command line option; --disable-bootstrap -@anchor{internals/index cmdoption-disable-bootstrap}@anchor{263} +@anchor{internals/index cmdoption-disable-bootstrap}@anchor{387} @deffn {Option} @w{-}@w{-}disable@w{-}bootstrap For hacking on the “jit” subdirectory, performing a full @@ -13864,7 +14699,7 @@ the compiler can still bootstrap itself. @end deffn @geindex command line option; --enable-checking=release -@anchor{internals/index cmdoption-enable-checking}@anchor{264} +@anchor{internals/index cmdoption-enable-checking}@anchor{388} @deffn {Option} @w{-}@w{-}enable@w{-}checking=release The compile can perform extensive self-checking as it runs, useful when @@ -13875,7 +14710,7 @@ disable this self-checking. @end deffn @node Running the test suite,Environment variables,Working on the JIT library,Internals -@anchor{internals/index running-the-test-suite}@anchor{265} +@anchor{internals/index running-the-test-suite}@anchor{389} @section Running the test suite @@ -13933,7 +14768,7 @@ and once a test has been compiled, you can debug it directly: @end menu @node Running under valgrind,,,Running the test suite -@anchor{internals/index running-under-valgrind}@anchor{266} +@anchor{internals/index running-under-valgrind}@anchor{38a} @subsection Running under valgrind @@ -13982,7 +14817,7 @@ When running under valgrind, it’s best to have configured gcc with various known false positives. @node Environment variables,Packaging notes,Running the test suite,Internals -@anchor{internals/index environment-variables}@anchor{267} +@anchor{internals/index environment-variables}@anchor{38b} @section Environment variables @@ -13990,7 +14825,7 @@ When running client code against a locally-built libgccjit, three environment variables need to be set up: @geindex environment variable; LD_LIBRARY_PATH -@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{268} +@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{38c} @deffn {Environment Variable} LD_LIBRARY_PATH @quotation @@ -14010,7 +14845,7 @@ libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), @end deffn @geindex environment variable; PATH -@anchor{internals/index envvar-PATH}@anchor{269} +@anchor{internals/index envvar-PATH}@anchor{38d} @deffn {Environment Variable} PATH The library uses a driver executable for converting from .s assembler @@ -14029,7 +14864,7 @@ of development. @end deffn @geindex environment variable; LIBRARY_PATH -@anchor{internals/index envvar-LIBRARY_PATH}@anchor{26a} +@anchor{internals/index envvar-LIBRARY_PATH}@anchor{38e} @deffn {Environment Variable} LIBRARY_PATH The driver executable invokes the linker, and the latter needs to locate @@ -14061,11 +14896,11 @@ hello world @end example @node Packaging notes,Overview of code structure,Environment variables,Internals -@anchor{internals/index packaging-notes}@anchor{26b} +@anchor{internals/index packaging-notes}@anchor{38f} @section Packaging notes -The configure-time option @ref{261,,--enable-host-shared} is needed when +The configure-time option @ref{385,,--enable-host-shared} is needed when building the jit in order to get position-independent code. This will slow down the regular compiler by a few percent. Hence when packaging gcc with libgccjit, please configure and build twice: @@ -14076,10 +14911,10 @@ with libgccjit, please configure and build twice: @itemize * @item -once without @ref{261,,--enable-host-shared} for most languages, and +once without @ref{385,,--enable-host-shared} for most languages, and @item -once with @ref{261,,--enable-host-shared} for the jit +once with @ref{385,,--enable-host-shared} for the jit @end itemize @end quotation @@ -14121,7 +14956,7 @@ popd @end example @node Overview of code structure,Design notes,Packaging notes,Internals -@anchor{internals/index overview-of-code-structure}@anchor{26c} +@anchor{internals/index overview-of-code-structure}@anchor{390} @section Overview of code structure @@ -14168,7 +15003,9 @@ The gcc::jit::recording classes (within @code{jit-recording.c} and class base_call; class function_pointer; class statement; + class extended_asm; class case_; + class top_level_asm; @end example @end quotation @@ -14588,7 +15425,7 @@ JIT: gcc::jit::logger::~logger() @end example @node Design notes,Submitting patches,Overview of code structure,Internals -@anchor{internals/index design-notes}@anchor{26d} +@anchor{internals/index design-notes}@anchor{391} @section Design notes @@ -14601,7 +15438,7 @@ close as possible to the error; failing that, a good place is within @code{recording::context::validate ()} in jit-recording.c. @node Submitting patches,,Design notes,Internals -@anchor{internals/index submitting-patches}@anchor{26e} +@anchor{internals/index submitting-patches}@anchor{392} @section Submitting patches @@ -14735,7 +15572,7 @@ large and inconsequential (e.g. anchor renumbering), rather like generated committing to svn. @node Indices and tables,Index,Internals,Top -@anchor{index indices-and-tables}@anchor{26f} +@anchor{index indices-and-tables}@anchor{393} @unnumbered Indices and tables diff --git a/gcc/jit/docs/cp/topics/asm.rst b/gcc/jit/docs/cp/topics/asm.rst new file mode 100644 index 0000000..69e2d1e --- /dev/null +++ b/gcc/jit/docs/cp/topics/asm.rst @@ -0,0 +1,308 @@ +.. Copyright (C) 2020 Free Software Foundation, Inc. + Originally contributed by David Malcolm + + This 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 3 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 + . + +.. default-domain:: cpp + +Using Assembly Language with libgccjit++ +======================================== + +libgccjit has some support for directly embedding assembler instructions. +This is based on GCC's support for inline ``asm`` in C code, and the +following assumes a familiarity with that functionality. See +`How to Use Inline Assembly Language in C Code `_ +in GCC's documentation, the "Extended Asm" section in particular. + +These entrypoints were added in :ref:`LIBGCCJIT_ABI_15`; you can test +for their presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS + +Adding assembler instructions within a function +*********************************************** + +.. class:: gccjit::extended_asm + + A `gccjit::extended_asm` represents an extended ``asm`` statement: a + series of low-level instructions inside a function that convert inputs + to outputs. + + :class:`gccjit::extended_asm` is a subclass of :class:`gccjit::object`. + It is a thin wrapper around the C API's :c:type:`gcc_jit_extended_asm *`. + + To avoid having an API entrypoint with a very large number of + parameters, an extended ``asm`` statement is made in stages: + an initial call to create the :type:`gccjit::extended_asm`, + followed by calls to add operands and set other properties of the + statement. + + There are two API entrypoints for creating a :type:`gccjit::extended_asm`: + + * :func:`gccjit::block::add_extended_asm` for an ``asm`` statement with + no control flow, and + + * :func:`gccjit::block::end_with_extended_asm_goto` for an ``asm goto``. + + For example, to create the equivalent of: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: // Quote from here in docs/cp/topics/asm.rst: example 1: C + :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 1: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 1: jit. */ + :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 1: jit. */ + :language: c + + .. warning:: When considering the numbering of operands within an + extended ``asm`` statement (e.g. the ``%0`` and ``%1`` + above), the equivalent to the C syntax is followed i.e. all + output operands, then all input operands, regardless of + what order the calls to + :func:`gccjit::extended_asm::add_output_operand` and + :func:`gccjit::extended_asm::add_input_operand` were made in. + + As in the C syntax, operands can be given symbolic names to avoid having + to number them. For example, to create the equivalent of: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: // Quote from here in docs/cp/topics/asm.rst: example 2: C + :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 2: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 2: jit. */ + :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 2: jit. */ + :language: c + +.. function:: extended_asm \ + gccjit::block::add_extended_asm (const std::string &asm_template,\ + gccjit::location loc = location ()) + + Create a :type:`gccjit::extended_asm` for an extended ``asm`` statement + with no control flow (i.e. without the ``goto`` qualifier). + + The parameter ``asm_template`` corresponds to the `AssemblerTemplate` + within C's extended ``asm`` syntax. It must be non-NULL. The call takes + a copy of the underlying string, so it is valid to pass in a pointer to + an on-stack buffer. + +.. function:: extended_asm\ + gccjit::block::end_with_extended_asm_goto (const std::string &asm_template,\ + std::vector goto_blocks,\ + block *fallthrough_block,\ + location loc = location ()) + + Create a :type:`gccjit::extended_asm` for an extended ``asm`` statement + that may perform jumps, and use it to terminate the given block. + This is equivalent to the ``goto`` qualifier in C's extended ``asm`` + syntax. + + For example, to create the equivalent of: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: // Quote from here in docs/cp/topics/asm.rst: example 3b: C + :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 3b: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 3: jit. */ + :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 3: jit. */ + :language: c + + here referencing a :type:`gcc_jit_block` named "carry". + + ``num_goto_blocks`` corresponds to the ``GotoLabels`` parameter within C's + extended ``asm`` syntax. The block names can be referenced within the + assembler template. + + ``fallthrough_block`` can be NULL. If non-NULL, it specifies the block + to fall through to after the statement. + + .. note:: This is needed since each :type:`gccjit::block` must have a + single exit point, as a basic block: you can't jump from the + middle of a block. A "goto" is implicitly added after the + asm to handle the fallthrough case, which is equivalent to what + would have happened in the C case. + +.. function:: gccjit::extended_asm &\ + gccjit::extended_asm::set_volatile_flag (bool flag) + + Set whether the :type:`gccjit::extended_asm` has side-effects, equivalent to the + `volatile `_ + qualifier in C's extended asm syntax. + + For example, to create the equivalent of: + + .. code-block:: c + + asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (msr) + : + : "rdx"); + + the following API calls could be used: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 4: jit. */ + :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 4: jit. */ + :language: c + + where the :type:`gccjit::extended_asm` is flagged as volatile. + +.. function:: gccjit::extended_asm &\ + gccjit::extended_asm::set_inline_flag (bool flag) + + Set the equivalent of the + `inline `_ + qualifier in C's extended ``asm`` syntax. + +.. function:: gccjit::extended_asm&\ + gccjit::extended_asm::add_output_operand (const std::string &asm_symbolic_name,\ + const std::string &constraint,\ + gccjit::lvalue dest) + + Add an output operand to the extended ``asm`` statement. See the + `Output Operands `_ + section of the documentation of the C syntax. + + ``asm_symbolic_name`` corresponds to the ``asmSymbolicName`` component of + C's extended ``asm`` syntax, and specifies the symbolic name for the operand. + See the overload below for an alternative that does not supply a symbolic + name. + + ``constraint`` corresponds to the ``constraint`` component of C's extended + ``asm`` syntax. + + ``dest`` corresponds to the ``cvariablename`` component of C's extended + ``asm`` syntax. + + .. code-block:: c++ + + // Example with a symbolic name ("aIndex"), the equivalent of: + // : [aIndex] "=r" (index) + ext_asm.add_output_operand ("aIndex", "=r", index); + + This function can't be called on an ``asm goto`` as such instructions can't + have outputs; see the + `Goto Labels `_ + section of GCC's "Extended Asm" documentation. + +.. function:: gccjit::extended_asm&\ + gccjit::extended_asm::add_output_operand (const std::string &constraint,\ + gccjit::lvalue dest) + + As above, but don't supply a symbolic name for the operand. + + .. code-block:: c++ + + // Example without a symbolic name, the equivalent of: + // : "=r" (dst) + ext_asm.add_output_operand ("=r", dst); + +.. function:: gccjit::extended_asm&\ + gccjit::extended_asm::add_input_operand (const std::string &asm_symbolic_name, \ + const std::string &constraint, \ + gccjit::rvalue src) + + Add an input operand to the extended ``asm`` statement. See the + `Input Operands `_ + section of the documentation of the C syntax. + + ``asm_symbolic_name`` corresponds to the ``asmSymbolicName`` component + of C's extended ``asm`` syntax. See the overload below for an alternative + that does not supply a symbolic name. + + ``constraint`` corresponds to the ``constraint`` component of C's extended + ``asm`` syntax. + + ``src`` corresponds to the ``cexpression`` component of C's extended + ``asm`` syntax. + + .. code-block:: c++ + + // Example with a symbolic name ("aMask"), the equivalent of: + // : [aMask] "r" (Mask) + ext_asm.add_input_operand ("aMask", "r", mask); + +.. function:: gccjit::extended_asm&\ + gccjit::extended_asm::add_input_operand (const std::string &constraint,\ + gccjit::rvalue src) + + As above, but don't supply a symbolic name for the operand. + + .. code-block:: c++ + + // Example without a symbolic name, the equivalent of: + // : "r" (src) + ext_asm.add_input_operand ("r", src); + +.. function:: gccjit::extended_asm&\ + gccjit::extended_asm::add_clobber (const std::string &victim) + + Add `victim` to the list of registers clobbered by the extended ``asm`` + statement. See the + `Clobbers and Scratch Registers `_ + section of the documentation of the C syntax. + + Statements with multiple clobbers will require multiple calls, one per + clobber. + + For example: + + .. code-block:: c++ + + ext_asm.add_clobber ("r0").add_clobber ("cc").add_clobber ("memory"); + + +Adding top-level assembler statements +************************************* + +In addition to creating extended ``asm`` instructions within a function, +there is support for creating "top-level" assembler statements, outside +of any function. + +.. function:: void\ + gccjit::context::add_top_level_asm (const char *asm_stmts,\ + gccjit::location loc = location ()) + + Create a set of top-level asm statements, analogous to those created + by GCC's "basic" ``asm`` syntax in C at file scope. + + For example, to create the equivalent of: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: // Quote from here in docs/cp/topics/asm.rst: example 5: C + :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 5: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc + :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */ + :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */ + :language: c diff --git a/gcc/jit/docs/cp/topics/index.rst b/gcc/jit/docs/cp/topics/index.rst index 187a20d..721e70c 100644 --- a/gcc/jit/docs/cp/topics/index.rst +++ b/gcc/jit/docs/cp/topics/index.rst @@ -28,3 +28,4 @@ Topic Reference functions.rst locations.rst compilation.rst + asm.rst diff --git a/gcc/jit/docs/topics/asm.rst b/gcc/jit/docs/topics/asm.rst new file mode 100644 index 0000000..b91514d --- /dev/null +++ b/gcc/jit/docs/topics/asm.rst @@ -0,0 +1,311 @@ +.. Copyright (C) 2020 Free Software Foundation, Inc. + Originally contributed by David Malcolm + + This 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 3 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 + . + +.. default-domain:: c + +Using Assembly Language with libgccjit +====================================== + +libgccjit has some support for directly embedding assembler instructions. +This is based on GCC's support for inline ``asm`` in C code, and the +following assumes a familiarity with that functionality. See +`How to Use Inline Assembly Language in C Code `_ +in GCC's documentation, the "Extended Asm" section in particular. + +These entrypoints were added in :ref:`LIBGCCJIT_ABI_15`; you can test +for their presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS + +Adding assembler instructions within a function +*********************************************** + +.. type:: gcc_jit_extended_asm + + A `gcc_jit_extended_asm` represents an extended ``asm`` statement: a + series of low-level instructions inside a function that convert inputs + to outputs. + + To avoid having an API entrypoint with a very large number of + parameters, an extended ``asm`` statement is made in stages: + an initial call to create the :type:`gcc_jit_extended_asm`, + followed by calls to add operands and set other properties of the + statement. + + There are two API entrypoints for creating a :type:`gcc_jit_extended_asm`: + + * :func:`gcc_jit_block_add_extended_asm` for an ``asm`` statement with + no control flow, and + + * :func:`gcc_jit_block_end_with_extended_asm_goto` for an ``asm goto``. + + For example, to create the equivalent of: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: // Quote from here in docs/topics/asm.rst: example 1: C + :end-before: // Quote up to here in docs/topics/asm.rst: example 1: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: /* Quote from here in docs/topics/asm.rst: example 1: jit. */ + :end-before: /* Quote up to here in docs/topics/asm.rst: example 1: jit. */ + :language: c + + .. warning:: When considering the numbering of operands within an + extended ``asm`` statement (e.g. the ``%0`` and ``%1`` + above), the equivalent to the C syntax is followed i.e. all + output operands, then all input operands, regardless of + what order the calls to + :func:`gcc_jit_extended_asm_add_output_operand` and + :func:`gcc_jit_extended_asm_add_input_operand` were made in. + + As in the C syntax, operands can be given symbolic names to avoid having + to number them. For example, to create the equivalent of: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: // Quote from here in docs/topics/asm.rst: example 2: C + :end-before: // Quote up to here in docs/topics/asm.rst: example 2: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: /* Quote from here in docs/topics/asm.rst: example 2: jit. */ + :end-before: /* Quote up to here in docs/topics/asm.rst: example 2: jit. */ + :language: c + +.. function:: gcc_jit_extended_asm *\ + gcc_jit_block_add_extended_asm (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + const char *asm_template) + + Create a :type:`gcc_jit_extended_asm` for an extended ``asm`` statement + with no control flow (i.e. without the ``goto`` qualifier). + + The parameter ``asm_template`` corresponds to the `AssemblerTemplate` + within C's extended ``asm`` syntax. It must be non-NULL. The call takes + a copy of the underlying string, so it is valid to pass in a pointer to + an on-stack buffer. + +.. function:: gcc_jit_extended_asm *\ + gcc_jit_block_end_with_extended_asm_goto (gcc_jit_block *block,\ + gcc_jit_location *loc,\ + const char *asm_template,\ + int num_goto_blocks,\ + gcc_jit_block **goto_blocks,\ + gcc_jit_block *fallthrough_block) + + Create a :type:`gcc_jit_extended_asm` for an extended ``asm`` statement + that may perform jumps, and use it to terminate the given block. + This is equivalent to the ``goto`` qualifier in C's extended ``asm`` + syntax. + + For example, to create the equivalent of: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: // Quote from here in docs/topics/asm.rst: example 3b: C + :end-before: // Quote up to here in docs/topics/asm.rst: example 3b: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: /* Quote from here in docs/topics/asm.rst: example 3: jit. */ + :end-before: /* Quote up to here in docs/topics/asm.rst: example 3: jit. */ + :language: c + + here referencing a :type:`gcc_jit_block` named "carry". + + ``num_goto_blocks`` must be >= 0. + + ``goto_blocks`` must be non-NULL. This corresponds to the ``GotoLabels`` + parameter within C's extended ``asm`` syntax. The block names can be + referenced within the assembler template. + + ``fallthrough_block`` can be NULL. If non-NULL, it specifies the block + to fall through to after the statement. + + .. note:: This is needed since each :type:`gcc_jit_block` must have a + single exit point, as a basic block: you can't jump from the + middle of a block. A "goto" is implicitly added after the + asm to handle the fallthrough case, which is equivalent to what + would have happened in the C case. + +.. function:: void\ + gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm *ext_asm,\ + int flag) + + Set whether the :type:`gcc_jit_extended_asm` has side-effects, equivalent to the + `volatile `_ + qualifier in C's extended asm syntax. + + For example, to create the equivalent of: + + .. code-block:: c + + asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (msr) + : + : "rdx"); + + the following API calls could be used: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: /* Quote from here in docs/topics/asm.rst: example 4: jit. */ + :end-before: /* Quote up to here in docs/topics/asm.rst: example 4: jit. */ + :language: c + + where the :type:`gcc_jit_extended_asm` is flagged as volatile. + +.. function:: void\ + gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm *ext_asm,\ + int flag) + + Set the equivalent of the + `inline `_ + qualifier in C's extended ``asm`` syntax. + +.. function:: void\ + gcc_jit_extended_asm_add_output_operand (gcc_jit_extended_asm *ext_asm,\ + const char *asm_symbolic_name,\ + const char *constraint,\ + gcc_jit_lvalue *dest) + + Add an output operand to the extended ``asm`` statement. See the + `Output Operands `_ + section of the documentation of the C syntax. + + ``asm_symbolic_name`` corresponds to the ``asmSymbolicName`` component of C's + extended ``asm`` syntax. It can be NULL. If non-NULL it specifies the + symbolic name for the operand. + + ``constraint`` corresponds to the ``constraint`` component of C's extended + ``asm`` syntax. It must be non-NULL. + + ``dest`` corresponds to the ``cvariablename`` component of C's extended + ``asm`` syntax. It must be non-NULL. + + .. code-block:: c + + // Example with a NULL symbolic name, the equivalent of: + // : "=r" (dst) + gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); + + // Example with a symbolic name ("aIndex"), the equivalent of: + // : [aIndex] "=r" (index) + gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index); + + This function can't be called on an ``asm goto`` as such instructions can't + have outputs; see the + `Goto Labels `_ + section of GCC's "Extended Asm" documentation. + +.. function:: void\ + gcc_jit_extended_asm_add_input_operand (gcc_jit_extended_asm *ext_asm,\ + const char *asm_symbolic_name,\ + const char *constraint,\ + gcc_jit_rvalue *src) + + Add an input operand to the extended ``asm`` statement. See the + `Input Operands `_ + section of the documentation of the C syntax. + + ``asm_symbolic_name`` corresponds to the ``asmSymbolicName`` component of C's + extended ``asm`` syntax. It can be NULL. If non-NULL it specifies the + symbolic name for the operand. + + ``constraint`` corresponds to the ``constraint`` component of C's extended + ``asm`` syntax. It must be non-NULL. + + ``src`` corresponds to the ``cexpression`` component of C's extended + ``asm`` syntax. It must be non-NULL. + + .. code-block:: c + + // Example with a NULL symbolic name, the equivalent of: + // : "r" (src) + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_lvalue_as_rvalue (src)); + + // Example with a symbolic name ("aMask"), the equivalent of: + // : [aMask] "r" (Mask) + gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", + gcc_jit_lvalue_as_rvalue (mask)); + +.. function:: void\ + gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm *ext_asm,\ + const char *victim) + + Add `victim` to the list of registers clobbered by the extended ``asm`` + statement. It must be non-NULL. See the + `Clobbers and Scratch Registers `_ + section of the documentation of the C syntax. + + Statements with multiple clobbers will require multiple calls, one per + clobber. + + For example: + + .. code-block:: c + + gcc_jit_extended_asm_add_clobber (ext_asm, "r0"); + gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); + gcc_jit_extended_asm_add_clobber (ext_asm, "memory"); + +A :type:`gcc_jit_extended_asm` is a :type:`gcc_jit_object` "owned" by +the block's context. The following upcast is available: + +.. function:: gcc_jit_object *\ + gcc_jit_extended_asm_as_object (gcc_jit_extended_asm *ext_asm) + + Upcast from extended ``asm`` to object. + + +Adding top-level assembler statements +************************************* + +In addition to creating extended ``asm`` instructions within a function, +there is support for creating "top-level" assembler statements, outside +of any function. + +.. function:: void \ + gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt,\ + gcc_jit_location *loc,\ + const char *asm_stmts) + + Create a set of top-level asm statements, analogous to those created + by GCC's "basic" ``asm`` syntax in C at file scope. + + For example, to create the equivalent of: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: // Quote from here in docs/topics/asm.rst: example 5: C + :end-before: // Quote up to here in docs/topics/asm.rst: example 5: C + :language: c + + the following API calls could be used: + + .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c + :start-after: /* Quote from here in docs/topics/asm.rst: example 5: jit. */ + :end-before: /* Quote up to here in docs/topics/asm.rst: example 5: jit. */ + :language: c diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 6bfa101..b953da5 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -226,3 +226,20 @@ entrypoints: -------------------- ``LIBGCCJIT_ABI_14`` covers the addition of :func:`gcc_jit_global_set_initializer` + +.. _LIBGCCJIT_ABI_15: + +``LIBGCCJIT_ABI_15`` +----------------------- +``LIBGCCJIT_ABI_15`` covers the addition of API entrypoints for directly +embedding assembler instructions: + + * :func:`gcc_jit_block_add_extended_asm` + * :func:`gcc_jit_block_end_with_extended_asm_goto` + * :func:`gcc_jit_extended_asm_as_object` + * :func:`gcc_jit_extended_asm_set_volatile_flag` + * :func:`gcc_jit_extended_asm_set_inline_flag` + * :func:`gcc_jit_extended_asm_add_output_operand` + * :func:`gcc_jit_extended_asm_add_input_operand` + * :func:`gcc_jit_extended_asm_add_clobber` + * :func:`gcc_jit_context_add_top_level_asm` diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst index eb40d64..b869256 100644 --- a/gcc/jit/docs/topics/functions.rst +++ b/gcc/jit/docs/topics/functions.rst @@ -458,3 +458,6 @@ Statements :start-after: /* Quote from here in docs/topics/functions.rst. */ :end-before: /* Quote up to here in docs/topics/functions.rst. */ :language: c + +See also :type:`gcc_jit_extended_asm` for entrypoints for adding inline +assembler statements to a function. diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst index 8352ca2..d7cb86a 100644 --- a/gcc/jit/docs/topics/index.rst +++ b/gcc/jit/docs/topics/index.rst @@ -31,3 +31,4 @@ Topic Reference compilation.rst compatibility.rst performance.rst + asm.rst diff --git a/gcc/jit/docs/topics/objects.rst b/gcc/jit/docs/topics/objects.rst index 12d3c9f..cdee2c0 100644 --- a/gcc/jit/docs/topics/objects.rst +++ b/gcc/jit/docs/topics/objects.rst @@ -48,6 +48,7 @@ looks like this:: +- gcc_jit_lvalue +- gcc_jit_param +- gcc_jit_case + +- gcc_jit_extended_asm There are casting methods for upcasting from subclasses to parent classes. For example, :c:func:`gcc_jit_type_as_object`: diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index 4570bd2..b8c3685 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -131,7 +131,9 @@ namespace recording { class base_call; class function_pointer; class statement; + class extended_asm; class case_; + class top_level_asm; /* End of recording types. */ } diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 4fac64d..5bccf59 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "opt-suggestions.h" #include "gcc.h" #include "diagnostic.h" +#include "stmt.h" #include @@ -86,6 +87,18 @@ namespace jit { Playback. **********************************************************************/ +/* Build a STRING_CST tree for STR, or return NULL if it is NULL. + The TREE_TYPE is not initialized. */ + +static tree +build_string (const char *str) +{ + if (str) + return ::build_string (strlen (str), str); + else + return NULL_TREE; +} + /* The constructor for gcc::jit::playback::context. */ playback::context::context (recording::context *ctxt) @@ -774,7 +787,7 @@ new_string_literal (const char *value) tree a_type = build_array_type (char_type_node, i_type); /* build_string len parameter must include NUL terminator when building C strings. */ - tree t_str = build_string (len + 1, value); + tree t_str = ::build_string (len + 1, value); TREE_TYPE (t_str) = a_type; /* Convert to (const char*), loosely based on @@ -821,6 +834,18 @@ as_truth_value (tree expr, location *loc) return expr; } +/* Add a "top-level" basic asm statement (i.e. one outside of any functions) + containing ASM_STMTS. + + Compare with c_parser_asm_definition. */ + +void +playback::context::add_top_level_asm (const char *asm_stmts) +{ + tree asm_str = build_string (asm_stmts); + symtab->finalize_toplevel_asm (asm_str); +} + /* Construct a playback::rvalue instance (wrapping a tree) for a unary op. */ @@ -1897,6 +1922,104 @@ add_switch (location *loc, add_stmt (switch_stmt); } +/* Convert OPERANDS to a tree-based chain suitable for creating an + extended asm stmt. + Compare with c_parser_asm_operands. */ + +static tree +build_operand_chain (const auto_vec *operands) +{ + tree result = NULL_TREE; + unsigned i; + playback::asm_operand *asm_op; + FOR_EACH_VEC_ELT (*operands, i, asm_op) + { + tree name = build_string (asm_op->m_asm_symbolic_name); + tree str = build_string (asm_op->m_constraint); + tree value = asm_op->m_expr; + result = chainon (result, + build_tree_list (build_tree_list (name, str), + value)); + } + return result; +} + +/* Convert CLOBBERS to a tree-based list suitable for creating an + extended asm stmt. + Compare with c_parser_asm_clobbers. */ + +static tree +build_clobbers (const auto_vec *clobbers) +{ + tree list = NULL_TREE; + unsigned i; + const char *clobber; + FOR_EACH_VEC_ELT (*clobbers, i, clobber) + { + tree str = build_string (clobber); + list = tree_cons (NULL_TREE, str, list); + } + return list; +} + +/* Convert BLOCKS to a tree-based list suitable for creating an + extended asm stmt. + Compare with c_parser_asm_goto_operands. */ + +static tree +build_goto_operands (const auto_vec *blocks) +{ + tree list = NULL_TREE; + unsigned i; + playback::block *b; + FOR_EACH_VEC_ELT (*blocks, i, b) + { + tree label = b->as_label_decl (); + tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label))); + TREE_USED (label) = 1; + list = tree_cons (name, label, list); + } + return nreverse (list); +} + +/* Add an extended asm statement to this block. + + Compare with c_parser_asm_statement (in c/c-parser.c) + and build_asm_expr (in c/c-typeck.c). */ + +void +playback::block::add_extended_asm (location *loc, + const char *asm_template, + bool is_volatile, + bool is_inline, + const auto_vec *outputs, + const auto_vec *inputs, + const auto_vec *clobbers, + const auto_vec *goto_blocks) +{ + tree t_string = build_string (asm_template); + tree t_outputs = build_operand_chain (outputs); + tree t_inputs = build_operand_chain (inputs); + tree t_clobbers = build_clobbers (clobbers); + tree t_labels = build_goto_operands (goto_blocks); + t_string + = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels); + tree asm_stmt + = build5 (ASM_EXPR, void_type_node, + t_string, t_outputs, t_inputs, t_clobbers, t_labels); + + /* asm statements without outputs, including simple ones, are treated + as volatile. */ + ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0); + ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */ + ASM_INLINE_P (asm_stmt) = is_inline; + if (is_volatile) + ASM_VOLATILE_P (asm_stmt) = 1; + if (loc) + set_tree_location (asm_stmt, loc); + add_stmt (asm_stmt); +} + /* Constructor for gcc::jit::playback::block. */ playback::block:: diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 50b6975..ff1f778 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -252,6 +252,8 @@ public: timer *get_timer () const { return m_recording_ctxt->get_timer (); } + void add_top_level_asm (const char *asm_stmts); + private: void dump_generated_code (); @@ -514,6 +516,21 @@ struct case_ block *m_dest_block; }; +struct asm_operand +{ + asm_operand (const char *asm_symbolic_name, + const char *constraint, + tree expr) + : m_asm_symbolic_name (asm_symbolic_name), + m_constraint (constraint), + m_expr (expr) + {} + + const char *m_asm_symbolic_name; + const char *m_constraint; + tree m_expr; +}; + class block : public wrapper { public: @@ -563,6 +580,16 @@ public: block *default_block, const auto_vec *cases); + void + add_extended_asm (location *loc, + const char *asm_template, + bool is_volatile, + bool is_inline, + const auto_vec *outputs, + const auto_vec *inputs, + const auto_vec *clobbers, + const auto_vec *goto_blocks); + private: void set_tree_location (tree t, location *loc) diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 3a84c1f..1b0f8bc 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -1578,6 +1578,10 @@ recording::context::dump_to_file (const char *path, bool update_locations) { fn->write_to_dump (d); } + + top_level_asm *tla; + FOR_EACH_VEC_ELT (m_top_level_asms, i, tla) + tla->write_to_dump (d); } static const char * const @@ -1904,6 +1908,22 @@ recording::context::get_all_requested_dumps (vec *ou out->splice (m_requested_dumps); } +/* Create a recording::top_level_asm instance and add it to this + context's list of mementos and to m_top_level_asms. + + Implements the post-error-checking part of + gcc_jit_context_add_top_level_asm. */ + +void +recording::context::add_top_level_asm (recording::location *loc, + const char *asm_stmts) +{ + recording::top_level_asm *asm_obj + = new recording::top_level_asm (this, loc, new_string (asm_stmts)); + record (asm_obj); + m_top_level_asms.safe_push (asm_obj); +} + /* This is a pre-compilation check for the context (and any parents). Detect errors within the context, adding errors if any are found. */ @@ -4206,6 +4226,23 @@ recording::block::add_comment (recording::location *loc, return result; } +/* Create a recording::extended_asm_simple instance and add it to + the block's context's list of mementos, and to the block's + list of statements. + + Implements the heart of gcc_jit_block_add_extended_asm. */ + +recording::extended_asm * +recording::block::add_extended_asm (location *loc, + const char *asm_template) +{ + extended_asm *result + = new extended_asm_simple (this, loc, new_string (asm_template)); + m_ctxt->record (result); + m_statements.safe_push (result); + return result; +} + /* Create a recording::end_with_conditional instance and add it to the block's context's list of mementos, and to the block's list of statements. @@ -4288,6 +4325,30 @@ recording::block::end_with_switch (recording::location *loc, return result; } +/* Create a recording::extended_asm_goto instance and add it to + the block's context's list of mementos, and to the block's + list of statements. + + Implements the heart of gcc_jit_block_end_with_extended_asm_goto. */ + + +recording::extended_asm * +recording::block::end_with_extended_asm_goto (location *loc, + const char *asm_template, + int num_goto_blocks, + block **goto_blocks, + block *fallthrough_block) +{ + extended_asm *result + = new extended_asm_goto (this, loc, new_string (asm_template), + num_goto_blocks, goto_blocks, + fallthrough_block); + m_ctxt->record (result); + m_statements.safe_push (result); + m_has_been_terminated = true; + return result; +} + /* Override the default implementation of recording::memento::write_to_dump for blocks by writing an unindented block name as a label, followed by the indented @@ -6508,6 +6569,459 @@ recording::switch_::write_reproducer (reproducer &r) cases_id); } +/* class asm_operand : public memento. */ + +recording::asm_operand::asm_operand (extended_asm *ext_asm, + string *asm_symbolic_name, + string *constraint) +: memento (ext_asm->get_context ()), + m_ext_asm (ext_asm), + m_asm_symbolic_name (asm_symbolic_name), + m_constraint (constraint) +{ +} + +void +recording::asm_operand::print (pretty_printer *pp) const +{ + if (m_asm_symbolic_name) + { + pp_character (pp, '['); + pp_string (pp, m_asm_symbolic_name->c_str ()); + pp_character (pp, ']'); + pp_space (pp); + } + pp_string (pp, m_constraint->get_debug_string ()); + /* Subclass will add lvalue/rvalue. */ +} + +recording::string * +recording::asm_operand::make_debug_string () +{ + pretty_printer pp; + print (&pp); + return m_ctxt->new_string (pp_formatted_text (&pp), false); +} + +/* class output_asm_operand : public asm_operand. */ + +void +recording::output_asm_operand::write_reproducer (reproducer &r) +{ + const char *fmt = + " gcc_jit_extended_asm_add_output_operand (%s, /* gcc_jit_extended_asm *ext_asm */\n" + " %s, /* const char *asm_symbolic_name */\n" + " %s, /* const char *constraint */\n" + " %s); /* gcc_jit_lvalue *dest */\n"; + r.write (fmt, + r.get_identifier (m_ext_asm), + (m_asm_symbolic_name + ? m_asm_symbolic_name->get_debug_string () : "NULL"), + m_constraint->get_debug_string (), + r.get_identifier (m_dest)); +} + +void +recording::output_asm_operand::print (pretty_printer *pp) const +{ + asm_operand::print (pp); + pp_string (pp, " ("); + pp_string (pp, m_dest->get_debug_string ()); + pp_string (pp, ")"); +} + +/* class input_asm_operand : public asm_operand. */ + +void +recording::input_asm_operand::write_reproducer (reproducer &r) +{ + const char *fmt = + " gcc_jit_extended_asm_add_input_operand (%s, /* gcc_jit_extended_asm *ext_asm */\n" + " %s, /* const char *asm_symbolic_name */\n" + " %s, /* const char *constraint */\n" + " %s); /* gcc_jit_rvalue *src */\n"; + r.write (fmt, + r.get_identifier (m_ext_asm), + (m_asm_symbolic_name + ? m_asm_symbolic_name->get_debug_string () : "NULL"), + m_constraint->get_debug_string (), + r.get_identifier_as_rvalue (m_src)); +} + +void +recording::input_asm_operand::print (pretty_printer *pp) const +{ + asm_operand::print (pp); + pp_string (pp, " ("); + pp_string (pp, m_src->get_debug_string ()); + pp_string (pp, ")"); +} + +/* The implementation of class gcc::jit::recording::extended_asm. */ + +void +recording::extended_asm::add_output_operand (const char *asm_symbolic_name, + const char *constraint, + lvalue *dest) +{ + output_asm_operand *op + = new output_asm_operand (this, + new_string (asm_symbolic_name), + new_string (constraint), + dest); + m_ctxt->record (op); + m_output_ops.safe_push (op); +} + +void +recording::extended_asm::add_input_operand (const char *asm_symbolic_name, + const char *constraint, + rvalue *src) +{ + input_asm_operand *op + = new input_asm_operand (this, + new_string (asm_symbolic_name), + new_string (constraint), + src); + m_ctxt->record (op); + m_input_ops.safe_push (op); +} + +void +recording::extended_asm::add_clobber (const char *victim) +{ + m_clobbers.safe_push (new_string (victim)); +} + +/* Implementation of recording::memento::replay_into + for recording::extended_asm. */ + +void +recording::extended_asm::replay_into (replayer *r) +{ + auto_vec playback_output_ops; + auto_vec playback_input_ops; + auto_vec playback_clobbers; + auto_vec playback_goto_blocks; + + /* Populate outputs. */ + { + output_asm_operand *rec_asm_op; + unsigned i; + FOR_EACH_VEC_ELT (m_output_ops, i, rec_asm_op) + { + playback::asm_operand playback_asm_op + (rec_asm_op->get_symbolic_name (), + rec_asm_op->get_constraint (), + rec_asm_op->get_lvalue ()->playback_lvalue ()->as_tree ()); + playback_output_ops.safe_push (playback_asm_op); + } + } + + /* Populate inputs. */ + { + input_asm_operand *rec_asm_op; + unsigned i; + FOR_EACH_VEC_ELT (m_input_ops, i, rec_asm_op) + { + playback::asm_operand playback_asm_op + (rec_asm_op->get_symbolic_name (), + rec_asm_op->get_constraint (), + rec_asm_op->get_rvalue ()->playback_rvalue ()->as_tree ()); + playback_input_ops.safe_push (playback_asm_op); + } + } + + /* Populate clobbers. */ + { + string *rec_clobber; + unsigned i; + FOR_EACH_VEC_ELT (m_clobbers, i, rec_clobber) + playback_clobbers.safe_push (rec_clobber->c_str ()); + } + + /* Populate playback blocks if an "asm goto". */ + maybe_populate_playback_blocks (&playback_goto_blocks); + + playback_block (get_block ()) + ->add_extended_asm (playback_location (r), + m_asm_template->c_str (), + m_is_volatile, m_is_inline, + &playback_output_ops, + &playback_input_ops, + &playback_clobbers, + &playback_goto_blocks); +} + +/* Implementation of recording::memento::make_debug_string for + an extended_asm "statement". */ + +recording::string * +recording::extended_asm::make_debug_string () +{ + pretty_printer pp; + pp_string (&pp, "asm "); + if (m_is_volatile) + pp_string (&pp, "volatile "); + if (m_is_inline) + pp_string (&pp, "inline "); + if (is_goto ()) + pp_string (&pp, "goto "); + pp_character (&pp, '('); + pp_string (&pp, m_asm_template->get_debug_string ()); + pp_string (&pp, " : "); + unsigned i; + { + output_asm_operand *asm_op; + FOR_EACH_VEC_ELT (m_output_ops, i, asm_op) + { + if (i > 0) + pp_string (&pp, ", "); + asm_op->print (&pp); + } + } + pp_string (&pp, " : "); + { + input_asm_operand *asm_op; + FOR_EACH_VEC_ELT (m_input_ops, i, asm_op) + { + if (i > 0) + pp_string (&pp, ", "); + asm_op->print (&pp); + } + } + pp_string (&pp, " : "); + string *rec_clobber; + FOR_EACH_VEC_ELT (m_clobbers, i, rec_clobber) + { + if (i > 0) + pp_string (&pp, ", "); + pp_string (&pp, rec_clobber->get_debug_string ()); + } + maybe_print_gotos (&pp); + pp_character (&pp, ')'); + return new_string (pp_formatted_text (&pp)); +} + +void +recording::extended_asm::write_flags (reproducer &r) +{ + if (m_is_volatile) + r.write (" gcc_jit_extended_asm_set_volatile_flag (%s, 1);\n", + r.get_identifier (this)); + if (m_is_inline) + r.write (" gcc_jit_extended_asm_set_inline_flag (%s, 1);\n", + r.get_identifier (this)); +} + +void +recording::extended_asm::write_clobbers (reproducer &r) +{ + string *clobber; + unsigned i; + FOR_EACH_VEC_ELT (m_clobbers, i, clobber) + r.write (" gcc_jit_extended_asm_add_clobber (%s, %s);\n", + r.get_identifier (this), + clobber->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for + extended_asm_simple. */ + +void +recording::extended_asm_simple::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "extended_asm"); + r.write (" gcc_jit_extended_asm *%s =\n" + " gcc_jit_block_add_extended_asm (%s, /*gcc_jit_block *block */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s); /* const char *asm_template */\n", + id, + r.get_identifier (get_block ()), + r.get_identifier (get_loc ()), + m_asm_template->get_debug_string ()); + write_flags (r); + write_clobbers (r); +} + +void +recording::extended_asm:: +maybe_populate_playback_blocks (auto_vec *) +{ + /* Do nothing; not an "asm goto". */ +} + +/* The implementation of class gcc::jit::recording::extended_asm_goto. */ + +/* recording::extended_asm_goto's ctor. */ + +recording::extended_asm_goto::extended_asm_goto (block *b, + location *loc, + string *asm_template, + int num_goto_blocks, + block **goto_blocks, + block *fallthrough_block) +: extended_asm (b, loc, asm_template), + m_goto_blocks (num_goto_blocks), + m_fallthrough_block (fallthrough_block) +{ + for (int i = 0; i < num_goto_blocks; i++) + m_goto_blocks.quick_push (goto_blocks[i]); +} + +/* Implementation of recording::memento::replay_into + for recording::extended_asm_goto. */ + +void +recording::extended_asm_goto::replay_into (replayer *r) +{ + /* Chain up to base class impl. */ + recording::extended_asm::replay_into (r); + + /* ...and potentially add a goto for the fallthrough. */ + if (m_fallthrough_block) + playback_block (get_block ()) + ->add_jump (playback_location (r), + m_fallthrough_block->playback_block ()); +} + +/* Implementation of recording::memento::write_reproducer for + extended_asm_goto. */ + +void +recording::extended_asm_goto::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "extended_asm"); + const char *blocks_id = r.make_tmp_identifier ("blocks_for", this); + r.write (" gcc_jit_block *%s[%i] = {\n", + blocks_id, + m_goto_blocks.length ()); + int i; + block *b; + FOR_EACH_VEC_ELT (m_goto_blocks, i, b) + r.write (" %s,\n", r.get_identifier (b)); + r.write (" };\n"); + r.write (" gcc_jit_extended_asm *%s =\n" + " gcc_jit_block_end_with_extended_asm_goto (%s, /*gcc_jit_block *block */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s, /* const char *asm_template */\n" + " %i, /* int num_goto_blocks */\n" + " %s, /* gcc_jit_block **goto_blocks */\n" + " %s); /* gcc_jit_block *fallthrough_block */\n", + id, + r.get_identifier (get_block ()), + r.get_identifier (get_loc ()), + m_asm_template->get_debug_string (), + m_goto_blocks.length (), + blocks_id, + (m_fallthrough_block + ? r.get_identifier (m_fallthrough_block) + : "NULL")); + write_flags (r); + write_clobbers (r); +} + +/* Override the poisoned default implementation of + gcc::jit::recording::statement::get_successor_blocks + + An extended_asm_goto can jump to the m_goto_blocks, and to + the (optional) m_fallthrough_block. */ + +vec +recording::extended_asm_goto::get_successor_blocks () const +{ + vec result; + result.create (m_goto_blocks.length () + 1); + if (m_fallthrough_block) + result.quick_push (m_fallthrough_block); + result.splice (m_goto_blocks); + return result; +} + +/* Vfunc for use by recording::extended_asm::make_debug_string. */ + +void +recording::extended_asm_goto::maybe_print_gotos (pretty_printer *pp) const +{ + pp_string (pp, " : "); + unsigned i; + block *b; + FOR_EACH_VEC_ELT (m_goto_blocks, i, b) + { + if (i > 0) + pp_string (pp, ", "); + pp_string (pp, b->get_debug_string ()); + } + /* Non-C syntax here. */ + if (m_fallthrough_block) + pp_printf (pp, " [fallthrough: %s]", + m_fallthrough_block->get_debug_string ()); +} + +/* Vfunc for use by recording::extended_asm::replay_into. */ + +void +recording::extended_asm_goto:: +maybe_populate_playback_blocks (auto_vec *out) +{ + unsigned i; + block *b; + FOR_EACH_VEC_ELT (m_goto_blocks, i, b) + out->safe_push (b->playback_block ()); +} + +/* class top_level_asm : public memento. */ + +recording::top_level_asm::top_level_asm (context *ctxt, + location *loc, + string *asm_stmts) +: memento (ctxt), + m_loc (loc), + m_asm_stmts (asm_stmts) +{ +} + +/* Implementation of recording::memento::replay_into for top-level asm. */ + +void +recording::top_level_asm::replay_into (replayer *r) +{ + r->add_top_level_asm (m_asm_stmts->c_str ()); +} + +/* Implementation of recording::memento::make_debug_string for + top-level asm. */ + +recording::string * +recording::top_level_asm::make_debug_string () +{ + return string::from_printf (m_ctxt, "asm (%s)", + m_asm_stmts->get_debug_string ()); +} + +/* Override the default implementation of + recording::memento::write_to_dump. + Don't indent the string. */ + +void +recording::top_level_asm::write_to_dump (dump &d) +{ + d.write ("%s;\n", get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for top-level asm. */ + +void +recording::top_level_asm::write_reproducer (reproducer &r) +{ + r.write (" gcc_jit_context_add_top_level_asm (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s); /* const char *asm_stmts */\n", + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + m_asm_stmts->get_debug_string ()); +} + } // namespace gcc::jit } // namespace gcc diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 9a43a7b..e694882 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -301,6 +301,8 @@ public: void set_timer (timer *t) { m_timer = t; } timer *get_timer () const { return m_timer; } + void add_top_level_asm (location *loc, const char *asm_stmts); + private: void log_all_options () const; void log_str_option (enum gcc_jit_str_option opt) const; @@ -344,6 +346,7 @@ private: auto_vec m_compound_types; auto_vec m_globals; auto_vec m_functions; + auto_vec m_top_level_asms; type *m_basic_types[NUM_GCC_JIT_TYPES]; type *m_FILE_type; @@ -1275,6 +1278,10 @@ public: add_comment (location *loc, const char *text); + extended_asm * + add_extended_asm (location *loc, + const char *asm_template); + statement * end_with_conditional (location *loc, rvalue *boolval, @@ -1296,6 +1303,13 @@ public: int num_cases, case_ **cases); + extended_asm * + end_with_extended_asm_goto (location *loc, + const char *asm_template, + int num_goto_blocks, + block **goto_blocks, + block *fallthrough_block); + playback::block * playback_block () const { @@ -2112,6 +2126,207 @@ private: auto_vec m_cases; }; +class asm_operand : public memento +{ +public: + asm_operand (extended_asm *ext_asm, + string *asm_symbolic_name, + string *constraint); + + const char *get_symbolic_name () const + { + if (m_asm_symbolic_name) + return m_asm_symbolic_name->c_str (); + else + return NULL; + } + + const char *get_constraint () const + { + return m_constraint->c_str (); + } + + virtual void print (pretty_printer *pp) const; + +private: + string * make_debug_string () FINAL OVERRIDE; + +protected: + extended_asm *m_ext_asm; + string *m_asm_symbolic_name; + string *m_constraint; +}; + +class output_asm_operand : public asm_operand +{ +public: + output_asm_operand (extended_asm *ext_asm, + string *asm_symbolic_name, + string *constraint, + lvalue *dest) + : asm_operand (ext_asm, asm_symbolic_name, constraint), + m_dest (dest) + {} + + lvalue *get_lvalue () const { return m_dest; } + + void replay_into (replayer *) FINAL OVERRIDE {} + + void print (pretty_printer *pp) const FINAL OVERRIDE; + +private: + void write_reproducer (reproducer &r) FINAL OVERRIDE; + +private: + lvalue *m_dest; +}; + +class input_asm_operand : public asm_operand +{ +public: + input_asm_operand (extended_asm *ext_asm, + string *asm_symbolic_name, + string *constraint, + rvalue *src) + : asm_operand (ext_asm, asm_symbolic_name, constraint), + m_src (src) + {} + + rvalue *get_rvalue () const { return m_src; } + + void replay_into (replayer *) FINAL OVERRIDE {} + + void print (pretty_printer *pp) const FINAL OVERRIDE; + +private: + void write_reproducer (reproducer &r) FINAL OVERRIDE; + +private: + rvalue *m_src; +}; + +/* Abstract base class for extended_asm statements. */ + +class extended_asm : public statement +{ +public: + extended_asm (block *b, + location *loc, + string *asm_template) + : statement (b, loc), + m_asm_template (asm_template), + m_is_volatile (false), + m_is_inline (false) + {} + + void set_volatile_flag (bool flag) { m_is_volatile = flag; } + void set_inline_flag (bool flag) { m_is_inline = flag; } + + void add_output_operand (const char *asm_symbolic_name, + const char *constraint, + lvalue *dest); + void add_input_operand (const char *asm_symbolic_name, + const char *constraint, + rvalue *src); + void add_clobber (const char *victim); + + void replay_into (replayer *r) OVERRIDE; + + string *get_asm_template () const { return m_asm_template; } + + virtual bool is_goto () const = 0; + virtual void maybe_print_gotos (pretty_printer *) const = 0; + +protected: + void write_flags (reproducer &r); + void write_clobbers (reproducer &r); + +private: + string * make_debug_string () FINAL OVERRIDE; + virtual void maybe_populate_playback_blocks + (auto_vec *out) = 0; + +protected: + string *m_asm_template; + bool m_is_volatile; + bool m_is_inline; + auto_vec m_output_ops; + auto_vec m_input_ops; + auto_vec m_clobbers; +}; + +/* An extended_asm that's not a goto, as created by + gcc_jit_block_add_extended_asm. */ + +class extended_asm_simple : public extended_asm +{ +public: + extended_asm_simple (block *b, + location *loc, + string *asm_template) + : extended_asm (b, loc, asm_template) + {} + + void write_reproducer (reproducer &r) OVERRIDE; + bool is_goto () const FINAL OVERRIDE { return false; } + void maybe_print_gotos (pretty_printer *) const FINAL OVERRIDE {} + +private: + void maybe_populate_playback_blocks + (auto_vec *) FINAL OVERRIDE + {} +}; + +/* An extended_asm that's a asm goto, as created by + gcc_jit_block_end_with_extended_asm_goto. */ + +class extended_asm_goto : public extended_asm +{ +public: + extended_asm_goto (block *b, + location *loc, + string *asm_template, + int num_goto_blocks, + block **goto_blocks, + block *fallthrough_block); + + void replay_into (replayer *r) FINAL OVERRIDE; + void write_reproducer (reproducer &r) OVERRIDE; + + vec get_successor_blocks () const FINAL OVERRIDE; + + bool is_goto () const FINAL OVERRIDE { return true; } + void maybe_print_gotos (pretty_printer *) const FINAL OVERRIDE; + +private: + void maybe_populate_playback_blocks + (auto_vec *out) FINAL OVERRIDE; + +private: + auto_vec m_goto_blocks; + block *m_fallthrough_block; +}; + +/* A group of top-level asm statements, as created by + gcc_jit_context_add_top_level_asm. */ + +class top_level_asm : public memento +{ +public: + top_level_asm (context *ctxt, location *loc, string *asm_stmts); + + void write_to_dump (dump &d) FINAL OVERRIDE; + +private: + void replay_into (replayer *r) FINAL OVERRIDE; + string * make_debug_string () FINAL OVERRIDE; + void write_reproducer (reproducer &r) FINAL OVERRIDE; + +private: + location *m_loc; + string *m_asm_stmts; +}; + } // namespace gcc::jit::recording /* Create a recording::memento_of_new_rvalue_from_const instance and add diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 1b9ef1a..b4901ce 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -46,6 +46,7 @@ namespace gccjit class lvalue; class param; class case_; + class extended_asm; class timer; class auto_time; @@ -316,6 +317,9 @@ namespace gccjit rvalue max_value, block dest_block); + void add_top_level_asm (const char *asm_stmts, + location loc = location ()); + private: gcc_jit_context *m_inner_ctxt; }; @@ -449,6 +453,13 @@ namespace gccjit block default_block, std::vector cases, location loc = location ()); + + extended_asm add_extended_asm (const std::string &asm_template, + location loc = location ()); + extended_asm end_with_extended_asm_goto (const std::string &asm_template, + std::vector goto_blocks, + block *fallthrough_block, + location loc = location ()); }; class rvalue : public object @@ -509,6 +520,40 @@ namespace gccjit gcc_jit_case *get_inner_case () const; }; + class extended_asm : public object + { + public: + extended_asm (); + extended_asm (gcc_jit_extended_asm *inner); + + extended_asm & + set_volatile_flag (bool flag); + + extended_asm & + set_inline_flag (bool flag); + + extended_asm& + add_output_operand (const std::string &asm_symbolic_name, + const std::string &constraint, + gccjit::lvalue dest); + extended_asm& + add_output_operand (const std::string &constraint, + gccjit::lvalue dest); + + extended_asm& + add_input_operand (const std::string &asm_symbolic_name, + const std::string &constraint, + gccjit::rvalue src); + extended_asm& + add_input_operand (const std::string &constraint, + gccjit::rvalue src); + + extended_asm& + add_clobber (const std::string &victim); + + gcc_jit_extended_asm *get_inner_extended_asm () const; + }; + /* Overloaded operators, for those who want the most terse API (at the possible risk of being a little too magical). @@ -1259,6 +1304,14 @@ context::new_case (rvalue min_value, dest_block.get_inner_block ())); } +inline void +context::add_top_level_asm (const char *asm_stmts, location loc) +{ + gcc_jit_context_add_top_level_asm (m_inner_ctxt, + loc.get_inner_location (), + asm_stmts); +} + // class object inline context object::get_context () const @@ -1554,6 +1607,37 @@ block::end_with_switch (rvalue expr, as_array_of_ptrs); } +inline extended_asm +block::add_extended_asm (const std::string &asm_template, + location loc) +{ + return gcc_jit_block_add_extended_asm (get_inner_block (), + loc.get_inner_location (), + asm_template.c_str ()); +} + +inline extended_asm +block::end_with_extended_asm_goto (const std::string &asm_template, + std::vector goto_blocks, + block *fallthrough_block, + location loc) +{ + /* Treat std::vector as an array, relying on it not being resized: */ + block *as_array_of_wrappers = &goto_blocks[0]; + + /* Treat the array as being of the underlying pointers, relying on + the wrapper type being such a pointer internally. */ + gcc_jit_block **as_array_of_ptrs = + reinterpret_cast (as_array_of_wrappers); + return gcc_jit_block_end_with_extended_asm_goto + (get_inner_block (), + loc.get_inner_location (), + asm_template.c_str (), + goto_blocks.size (), + as_array_of_ptrs, + fallthrough_block ? fallthrough_block->get_inner_block () : NULL); +} + inline rvalue block::add_call (function other, location loc) @@ -1767,6 +1851,92 @@ case_::get_inner_case () const return reinterpret_cast (get_inner_object ()); } +// class extended_asm : public object +inline extended_asm::extended_asm () : object () {} +inline extended_asm::extended_asm (gcc_jit_extended_asm *inner) + : object (gcc_jit_extended_asm_as_object (inner)) +{ +} + +inline extended_asm& +extended_asm::set_volatile_flag (bool flag) +{ + gcc_jit_extended_asm_set_volatile_flag (get_inner_extended_asm (), flag); + return *this; +} + +inline extended_asm& +extended_asm::set_inline_flag (bool flag) +{ + gcc_jit_extended_asm_set_inline_flag (get_inner_extended_asm (), flag); + return *this; +} + +inline extended_asm& +extended_asm::add_output_operand (const std::string &asm_symbolic_name, + const std::string &constraint, + gccjit::lvalue dest) +{ + gcc_jit_extended_asm_add_output_operand + (get_inner_extended_asm (), + asm_symbolic_name.c_str (), + constraint.c_str (), + dest.get_inner_lvalue ()); + return *this; +} + +inline extended_asm& +extended_asm::add_output_operand (const std::string &constraint, + gccjit::lvalue dest) +{ + gcc_jit_extended_asm_add_output_operand + (get_inner_extended_asm (), + NULL, /* asm_symbolic_name */ + constraint.c_str (), + dest.get_inner_lvalue ()); + return *this; +} + +inline extended_asm& +extended_asm::add_input_operand (const std::string &asm_symbolic_name, + const std::string &constraint, + gccjit::rvalue src) +{ + gcc_jit_extended_asm_add_input_operand + (get_inner_extended_asm (), + asm_symbolic_name.c_str (), + constraint.c_str (), + src.get_inner_rvalue ()); + return *this; +} + +inline extended_asm& +extended_asm::add_input_operand (const std::string &constraint, + gccjit::rvalue src) +{ + gcc_jit_extended_asm_add_input_operand + (get_inner_extended_asm (), + NULL, /* asm_symbolic_name */ + constraint.c_str (), + src.get_inner_rvalue ()); + return *this; +} + +inline extended_asm& +extended_asm::add_clobber (const std::string &victim) +{ + gcc_jit_extended_asm_add_clobber (get_inner_extended_asm (), + victim.c_str ()); + return *this; +} + +inline gcc_jit_extended_asm * +extended_asm::get_inner_extended_asm () const +{ + /* Manual downcast: */ + return reinterpret_cast (get_inner_object ()); +} + /* Overloaded operators. */ // Unary operators inline rvalue operator- (rvalue a) diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index a00aefc..f9c33c6 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -96,6 +96,11 @@ struct gcc_jit_timer : public timer { }; +struct gcc_jit_extended_asm : public gcc::jit::recording::extended_asm +{ +}; + + /********************************************************************** Error-handling. @@ -300,13 +305,13 @@ struct gcc_jit_timer : public timer static void jit_error (gcc::jit::recording::context *ctxt, - gcc_jit_location *loc, + gcc::jit::recording::location *loc, const char *fmt, ...) GNU_PRINTF(3, 4); static void jit_error (gcc::jit::recording::context *ctxt, - gcc_jit_location *loc, + gcc::jit::recording::location *loc, const char *fmt, ...) { va_list ap; @@ -3290,3 +3295,182 @@ gcc_jit_version_patchlevel (void) version_info vi; return vi.patchlevel; } + +/********************************************************************** + Asm support. + **********************************************************************/ + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::block::add_extended_asm, in + jit-recording.c. */ + +gcc_jit_extended_asm * +gcc_jit_block_add_extended_asm (gcc_jit_block *block, + gcc_jit_location *loc, + const char *asm_template) +{ + RETURN_NULL_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_NULL_IF_FAIL (asm_template, ctxt, loc, "NULL asm_template"); + + return (gcc_jit_extended_asm *)block->add_extended_asm (loc, asm_template); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::block::end_with_extended_asm_goto, in + jit-recording.c. */ + +gcc_jit_extended_asm * +gcc_jit_block_end_with_extended_asm_goto (gcc_jit_block *block, + gcc_jit_location *loc, + const char *asm_template, + int num_goto_blocks, + gcc_jit_block **goto_blocks, + gcc_jit_block *fallthrough_block) +{ + RETURN_NULL_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_NULL_IF_FAIL (asm_template, ctxt, loc, "NULL asm_template"); + RETURN_NULL_IF_FAIL (num_goto_blocks >= 0, ctxt, loc, "num_goto_blocks < 0"); + for (int i = 0; i < num_goto_blocks; i++) + RETURN_NULL_IF_FAIL_PRINTF1 (goto_blocks[i], + ctxt, loc, + "NULL goto_blocks[%i]", i); + /* fallthrough_block can be NULL. */ + return (gcc_jit_extended_asm *)block->end_with_extended_asm_goto + (loc, asm_template, + num_goto_blocks, (gcc::jit::recording::block **)goto_blocks, + fallthrough_block); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, this calls the trivial + gcc::jit::recording::memento::as_object method (an extended_asm is a + memento), in jit-recording.h. */ + +gcc_jit_object * +gcc_jit_extended_asm_as_object (gcc_jit_extended_asm *ext_asm) +{ + RETURN_NULL_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm"); + + return static_cast (ext_asm->as_object ()); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::extended_asm::set_volatile_flag, in + jit-recording.c. */ + +void +gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm *ext_asm, + int flag) +{ + RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm"); + ext_asm->set_volatile_flag (flag); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::extended_asm::set_inline_flag, in + jit-recording.c. */ + +void +gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm *ext_asm, + int flag) +{ + RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm"); + ext_asm->set_inline_flag (flag); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::extended_asm::add_output_operand, in + jit-recording.c. */ + +void +gcc_jit_extended_asm_add_output_operand (gcc_jit_extended_asm *ext_asm, + const char *asm_symbolic_name, + const char *constraint, + gcc_jit_lvalue *dest) +{ + RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm"); + gcc::jit::recording::context *ctxt = ext_asm->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + gcc::jit::recording::location *loc = ext_asm->get_loc (); + /* asm_symbolic_name can be NULL. */ + RETURN_IF_FAIL (constraint, ctxt, loc, "NULL constraint"); + RETURN_IF_FAIL (dest, ctxt, loc, "NULL dest"); + RETURN_IF_FAIL (!ext_asm->is_goto (), ctxt, loc, + "cannot add output operand to asm goto"); + ext_asm->add_output_operand (asm_symbolic_name, constraint, dest); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::extended_asm::add_input_operand, in + jit-recording.c. */ + +extern void +gcc_jit_extended_asm_add_input_operand (gcc_jit_extended_asm *ext_asm, + const char *asm_symbolic_name, + const char *constraint, + gcc_jit_rvalue *src) +{ + RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm"); + gcc::jit::recording::context *ctxt = ext_asm->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + gcc::jit::recording::location *loc = ext_asm->get_loc (); + /* asm_symbolic_name can be NULL. */ + RETURN_IF_FAIL (constraint, ctxt, loc, "NULL constraint"); + RETURN_IF_FAIL (src, ctxt, loc, "NULL src"); + ext_asm->add_input_operand (asm_symbolic_name, constraint, src); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::extended_asm::add_clobber, in + jit-recording.c. */ + +void +gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm *ext_asm, + const char *victim) +{ + RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm"); + gcc::jit::recording::context *ctxt = ext_asm->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + gcc::jit::recording::location *loc = ext_asm->get_loc (); + RETURN_IF_FAIL (victim, ctxt, loc, "NULL victim"); + ext_asm->add_clobber (victim); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::add_top_level_asm, in + jit-recording.c. */ + +void +gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt, + gcc_jit_location *loc, + const char *asm_stmts) +{ + RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt"); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_IF_FAIL (asm_stmts, ctxt, NULL, "NULL asm_stmts"); + ctxt->add_top_level_asm (loc, asm_stmts); +} diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 7fbaa9f..c523f93 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -68,6 +68,7 @@ typedef struct gcc_jit_result gcc_jit_result; +- gcc_jit_lvalue +- gcc_jit_param +- gcc_jit_case + +- gcc_jit_extended_asm */ typedef struct gcc_jit_object gcc_jit_object; @@ -138,6 +139,12 @@ typedef struct gcc_jit_param gcc_jit_param; destination block. */ typedef struct gcc_jit_case gcc_jit_case; +/* A gcc_jit_extended_asm represents an assembly language statement, + analogous to an extended "asm" statement in GCC's C front-end: a series + of low-level instructions inside a function that convert inputs to + outputs. */ +typedef struct gcc_jit_extended_asm gcc_jit_extended_asm; + /* Acquire a JIT-compilation context. */ extern gcc_jit_context * gcc_jit_context_acquire (void); @@ -1518,6 +1525,102 @@ gcc_jit_version_minor (void); extern int gcc_jit_version_patchlevel (void); +/********************************************************************** + Asm support. + **********************************************************************/ + +/* Functions for adding inline assembler code, analogous to GCC's + "extended asm" syntax. + + See https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html + + These API entrypoints were added in LIBGCCJIT_ABI_15; you can test for their + presence using + #ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS +*/ + +#define LIBGCCJIT_HAVE_ASM_STATEMENTS + +/* Create a gcc_jit_extended_asm for an extended asm statement + with no control flow (i.e. without the goto qualifier). + + The asm_template parameter corresponds to the AssemblerTemplate + within C's extended asm syntax. It must be non-NULL. */ + +extern gcc_jit_extended_asm * +gcc_jit_block_add_extended_asm (gcc_jit_block *block, + gcc_jit_location *loc, + const char *asm_template); + +/* Create a gcc_jit_extended_asm for an extended asm statement + that may perform jumps, and use it to terminate the given block. + This is equivalent to the "goto" qualifier in C's extended asm + syntax. */ + +extern gcc_jit_extended_asm * +gcc_jit_block_end_with_extended_asm_goto (gcc_jit_block *block, + gcc_jit_location *loc, + const char *asm_template, + int num_goto_blocks, + gcc_jit_block **goto_blocks, + gcc_jit_block *fallthrough_block); + +/* Upcasting from extended asm to object. */ + +extern gcc_jit_object * +gcc_jit_extended_asm_as_object (gcc_jit_extended_asm *ext_asm); + +/* Set whether the gcc_jit_extended_asm has side-effects, equivalent to + the "volatile" qualifier in C's extended asm syntax. */ + +extern void +gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm *ext_asm, + int flag); + +/* Set the equivalent of the "inline" qualifier in C's extended asm + syntax. */ + +extern void +gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm *ext_asm, + int flag); + +/* Add an output operand to the extended asm statement. + "asm_symbolic_name" can be NULL. + "constraint" and "dest" must be non-NULL. + This function can't be called on an "asm goto" as such instructions + can't have outputs */ + +extern void +gcc_jit_extended_asm_add_output_operand (gcc_jit_extended_asm *ext_asm, + const char *asm_symbolic_name, + const char *constraint, + gcc_jit_lvalue *dest); + +/* Add an input operand to the extended asm statement. + "asm_symbolic_name" can be NULL. + "constraint" and "src" must be non-NULL. */ + +extern void +gcc_jit_extended_asm_add_input_operand (gcc_jit_extended_asm *ext_asm, + const char *asm_symbolic_name, + const char *constraint, + gcc_jit_rvalue *src); + +/* Add "victim" to the list of registers clobbered by the extended + asm statement. It must be non-NULL. */ + +extern void +gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm *ext_asm, + const char *victim); + +/* Add "asm_stmts", a set of top-level asm statements, analogous to + those created by GCC's "basic" asm syntax in C at file scope. */ + +extern void +gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt, + gcc_jit_location *loc, + const char *asm_stmts); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index a6e67e78..bcabe16 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -192,3 +192,16 @@ LIBGCCJIT_ABI_14 { global: gcc_jit_global_set_initializer; } LIBGCCJIT_ABI_13; + +LIBGCCJIT_ABI_15 { + global: + gcc_jit_block_add_extended_asm; + gcc_jit_block_end_with_extended_asm_goto; + gcc_jit_extended_asm_as_object; + gcc_jit_extended_asm_set_volatile_flag; + gcc_jit_extended_asm_set_inline_flag; + gcc_jit_extended_asm_add_output_operand; + gcc_jit_extended_asm_add_input_operand; + gcc_jit_extended_asm_add_clobber; + gcc_jit_context_add_top_level_asm; +} LIBGCCJIT_ABI_14; diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp index 2d8c884..9af87f9 100644 --- a/gcc/testsuite/jit.dg/jit.exp +++ b/gcc/testsuite/jit.dg/jit.exp @@ -37,12 +37,16 @@ load_lib target-libpath.exp load_lib gcc.exp load_lib g++.exp load_lib dejagnu.exp +load_lib target-supports-dg.exp # Skip these tests for targets that don't support -lgccjit if { ![check_effective_target_lgccjit] } { return } +# The default do-what keyword. +set dg-do-what-default compile + # Look for lines of the form: # definitely lost: 11,316 bytes in 235 blocks # indirectly lost: 352 bytes in 4 blocks @@ -379,6 +383,33 @@ proc jit-dg-test { prog do_what extra_tool_flags } { verbose " do_what: $do_what" verbose " extra_tool_flags: $extra_tool_flags" + global dg-do-what-default + set dg-do-what [list ${dg-do-what-default} "" P] + + set tmp [dg-get-options $prog] + foreach op $tmp { + verbose "Processing option: $op" 3 + set status [catch "$op" errmsg] + if { $status != 0 } { + if { 0 && [info exists errorInfo] } { + # This also prints a backtrace which will just confuse + # testcase writers, so it's disabled. + perror "$name: $errorInfo\n" + } else { + perror "$name: $errmsg for \"$op\"\n" + } + perror "$name: $errmsg for \"$op\"" 0 + return + } + } + + # If we're not supposed to try this test on this target, we're done. + if { [lindex ${dg-do-what} 1] == "N" } { + unsupported "$name" + verbose "$name not supported on this target, skipping it" 3 + return + } + # test-threads.c needs to be linked against pthreads if {[string match "*test-threads.c" $prog]} { append extra_tool_flags " -lpthread" diff --git a/gcc/testsuite/jit.dg/test-asm.c b/gcc/testsuite/jit.dg/test-asm.c new file mode 100644 index 0000000..e7777ee --- /dev/null +++ b/gcc/testsuite/jit.dg/test-asm.c @@ -0,0 +1,492 @@ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ + +#include +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +/********************************************************************** + Support fns for creating code. + **********************************************************************/ + +/* Make a "void FUNC_NAME (void)" function with a single block, returning + that block. */ + +static gcc_jit_block * +make_single_block_func (gcc_jit_context *ctxt, const char *func_name) +{ + gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_function *func + = gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + func_name, + 0, NULL, 0); + return gcc_jit_function_new_block (func, "initial"); +} + +static const char * +get_desc (gcc_jit_extended_asm *ext_asm) +{ + return gcc_jit_object_get_debug_string + (gcc_jit_extended_asm_as_object (ext_asm)); +} + +/********************************************************************** + Support fns for verifying code. + **********************************************************************/ + +typedef void (*void_void_fn) (void); + +static void_void_fn +get_test_fn (gcc_jit_result *result, const char *func_name) +{ + return (void_void_fn)gcc_jit_result_get_code (result, func_name); +} + +/********************************************************************** + test_i386_basic_asm_1: simple example of asm + **********************************************************************/ + +/* Create the equivalent of: + + int src; + int dst; + + void test_i386_basic_asm_1 (void) + { + // Quote from here in docs/topics/asm.rst: example 1: C + asm ("mov %1, %0\n\t" + "add $1, %0" + : "=r" (dst) + : "r" (src)); + // Quote up to here in docs/topics/asm.rst: example 1: C + } + + i.e. copy src to dst and add 1 to dst. */ + +static void +create_test_i386_basic_asm_1 (gcc_jit_context *ctxt) +{ + gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_lvalue *dst + = gcc_jit_context_new_global (ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, "dst"); + gcc_jit_lvalue *src + = gcc_jit_context_new_global (ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, "src"); + + gcc_jit_block *block + = make_single_block_func (ctxt, "test_i386_basic_asm_1"); + + /* Quote from here in docs/topics/asm.rst: example 1: jit. */ + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_add_extended_asm (block, NULL, + "mov %1, %0\n\t" + "add $1, %0"); + gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_lvalue_as_rvalue (src)); + /* Quote up to here in docs/topics/asm.rst: example 1: jit. */ + + const char *desc = get_desc (ext_asm); + CHECK_STRING_VALUE + (desc, + "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )"); + + gcc_jit_block_end_with_void_return (block, NULL); +} + +static void +verify_code_1 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + void_void_fn test_i386_basic_asm_1 + = get_test_fn (result, "test_i386_basic_asm_1"); + CHECK_NON_NULL (test_i386_basic_asm_1); + + int *dst_ptr = (int *)gcc_jit_result_get_global (result, "dst"); + CHECK_NON_NULL (dst_ptr); + int *src_ptr = (int *)gcc_jit_result_get_global (result, "src"); + CHECK_NON_NULL (src_ptr); + + *src_ptr = 42; + *dst_ptr = 0; + test_i386_basic_asm_1 (); + CHECK_VALUE (*src_ptr, 42); + CHECK_VALUE (*dst_ptr, 43); +} + +/********************************************************************** + test_i386_basic_asm_2: test of symbolic names and clobbers + **********************************************************************/ + +/* Create the equivalent of: + uint32_t test_i386_basic_asm_2 (uint32_t Mask) + { + uint32_t Index; + // Quote from here in docs/topics/asm.rst: example 2: C + asm ("bsfl %[aMask], %[aIndex]" + : [aIndex] "=r" (Index) + : [aMask] "r" (Mask) + : "cc"); + // Quote up to here in docs/topics/asm.rst: example 2: C + return Index; + } + i.e. return the first bit set in "Mask" + + This exercises symbolic names and clobbers. */ + +static void +create_test_i386_basic_asm_2 (gcc_jit_context *ctxt) +{ + gcc_jit_type *uint32_type = gcc_jit_context_get_int_type (ctxt, 4, 0); + gcc_jit_param *mask + = gcc_jit_context_new_param (ctxt, NULL, + uint32_type, "Mask"); + gcc_jit_function *func + = gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + uint32_type, + "test_i386_basic_asm_2", + 1, &mask, 0); + gcc_jit_lvalue *index + = gcc_jit_function_new_local (func, NULL, + uint32_type, "Index"); + gcc_jit_block *block = gcc_jit_function_new_block (func, "initial"); + + /* Quote from here in docs/topics/asm.rst: example 2: jit. */ + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_add_extended_asm (block, NULL, + "bsfl %[aMask], %[aIndex]"); + gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index); + gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", + gcc_jit_param_as_rvalue (mask)); + gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); + /* Quote up to here in docs/topics/asm.rst: example 2: jit. */ + + const char *desc = get_desc (ext_asm); + CHECK_STRING_VALUE + (desc, + "asm (\"bsfl %[aMask], %[aIndex]\"" + " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")"); + + gcc_jit_block_end_with_return (block, NULL, + gcc_jit_lvalue_as_rvalue (index)); +} + +static void +verify_code_2 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef uint32_t (*fntype) (uint32_t); + fntype test_i386_basic_asm_2 + = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_2"); + CHECK_NON_NULL (test_i386_basic_asm_2); + + CHECK_VALUE (test_i386_basic_asm_2 (1), 0); + CHECK_VALUE (test_i386_basic_asm_2 (2), 1); + CHECK_VALUE (test_i386_basic_asm_2 (4), 2); + CHECK_VALUE (test_i386_basic_asm_2 (8), 3); +} + +/********************************************************************** + test_i386_basic_asm_3a/b: test of control flow: "asm goto" + **********************************************************************/ + +/* Create the equivalent of: + + int test_i386_basic_asm_3a (int p1, int p2) + { + asm goto ("btl %1, %0\n\t" + "jc %l2" + : // No outputs + : "r" (p1), "r" (p2) + : "cc" + : carry); + + return 0; + + carry: + return 1; + } + + or (the "_3b" variant) using a name rather than a number for the goto + label: + + // Quote from here in docs/topics/asm.rst: example 3b: C + asm goto ("btl %1, %0\n\t" + "jc %l[carry]" + : // No outputs + : "r" (p1), "r" (p2) + : "cc" + : carry); + // Quote up to here in docs/topics/asm.rst: example 3b: C + + This exercises control flow with an asm. */ + +static void +create_test_i386_basic_asm_3 (gcc_jit_context *ctxt, + const char *funcname, + int use_name) +{ + gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_param *p1 = gcc_jit_context_new_param (ctxt, NULL, int_type, "p1"); + gcc_jit_param *p2 = gcc_jit_context_new_param (ctxt, NULL, int_type, "p2"); + gcc_jit_param *params[2] = {p1, p2}; + gcc_jit_function *func + = gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + funcname, + 2, params, 0); + gcc_jit_block *b_start = gcc_jit_function_new_block (func, "start"); + gcc_jit_block *b_fallthru = gcc_jit_function_new_block (func, "fallthru"); + gcc_jit_block *b_carry = gcc_jit_function_new_block (func, "carry"); + + gcc_jit_rvalue *zero + = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0); + gcc_jit_rvalue *one + = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1); + + /* Quote from here in docs/topics/asm.rst: example 3: jit. */ + const char *asm_template = + (use_name + ? /* Label referred to by name: "%l[carry]". */ + ("btl %1, %0\n\t" + "jc %l[carry]") + : /* Label referred to numerically: "%l2". */ + ("btl %1, %0\n\t" + "jc %l2")); + + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_end_with_extended_asm_goto (b_start, NULL, + asm_template, + 1, &b_carry, + b_fallthru); + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_param_as_rvalue (p1)); + gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", + gcc_jit_param_as_rvalue (p2)); + gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); + /* Quote up to here in docs/topics/asm.rst: example 3: jit. */ + + const char *desc = get_desc (ext_asm); + CHECK_STRING_VALUE + (desc, + (use_name + ? ("asm goto (\"btl %1, %0\\n\\tjc %l[carry]\" " + ": : \"r\" (p1), \"r\" (p2) : \"cc\" " + ": carry [fallthrough: fallthru])") + : ("asm goto (\"btl %1, %0\\n\\tjc %l2\" " + ": : \"r\" (p1), \"r\" (p2) : \"cc\" " + ": carry [fallthrough: fallthru])"))); + + gcc_jit_block_end_with_return (b_fallthru, NULL, zero); + gcc_jit_block_end_with_return (b_carry, NULL, one); +} + +static void +verify_code_3 (gcc_jit_context *ctxt, gcc_jit_result *result, + const char *funcname) +{ + typedef int (*test_i386_basic_asm_3_type) (int, int); + + test_i386_basic_asm_3_type test_i386_basic_asm_3 + = (test_i386_basic_asm_3_type) gcc_jit_result_get_code (result, funcname); + CHECK_NON_NULL (test_i386_basic_asm_3); + + /* The fn should test bits, returning 0 or 1. */ + /* Bit 0. */ + CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 0), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 0), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 0), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 0), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 0), 0); + /* Bit 1. */ + CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 1), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 1), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 1), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 1), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 1), 0); + + for (int i = 0; i < 15; i++) + { + CHECK_VALUE (test_i386_basic_asm_3 (0x0000, i), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0xffff, i), 1); + } +} + +/********************************************************************** + test_i386_basic_asm_4: test of "volatile" + **********************************************************************/ + +/* Create the equivalent of: + uint64_t test_i386_basic_asm_4 (void) + { + uint64_t start_time, end_time; + + // Get start time + asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (start_time) + : + : "rdx"); + + // could do other work here + + // Get end time + asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (start_time) + : + : "rdx"); + + // Get elapsed time + return end_time - start_time; + } + + This exercises "volatile"; without it, the optimizer can assume that + both asm generate the same value and thus the time difference is zero. */ + +static void +add_rdtsc (gcc_jit_block *block, gcc_jit_lvalue *msr) +{ + /* Quote from here in docs/topics/asm.rst: example 4: jit. */ + gcc_jit_extended_asm *ext_asm + = gcc_jit_block_add_extended_asm + (block, NULL, + "rdtsc\n\t" /* Returns the time in EDX:EAX. */ + "shl $32, %%rdx\n\t" /* Shift the upper bits left. */ + "or %%rdx, %0"); /* 'Or' in the lower bits. */ + gcc_jit_extended_asm_set_volatile_flag (ext_asm, 1); + gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=a", msr); + gcc_jit_extended_asm_add_clobber (ext_asm, "rdx"); + /* Quote up to here in docs/topics/asm.rst: example 4: jit. */ + + const char *desc = get_desc (ext_asm); + CHECK_STRING_STARTS_WITH (desc, "asm volatile ("); +} + +static void +create_test_i386_basic_asm_4 (gcc_jit_context *ctxt) +{ + gcc_jit_type *uint64_type = gcc_jit_context_get_int_type (ctxt, 8, 0); + gcc_jit_function *func + = gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + uint64_type, + "test_i386_basic_asm_4", + 0, NULL, 0); + gcc_jit_block *block = gcc_jit_function_new_block (func, NULL); + + gcc_jit_lvalue *start_time + = gcc_jit_function_new_local (func, NULL, uint64_type, "start_time"); + add_rdtsc (block, start_time); + + gcc_jit_block_add_comment (block, NULL, "other work here"); + + gcc_jit_lvalue *end_time + = gcc_jit_function_new_local (func, NULL, uint64_type, "end_time"); + add_rdtsc (block, end_time); + + gcc_jit_rvalue *elapsed + = gcc_jit_context_new_binary_op (ctxt, NULL, GCC_JIT_BINARY_OP_MINUS, + uint64_type, + gcc_jit_lvalue_as_rvalue (end_time), + gcc_jit_lvalue_as_rvalue (start_time)); + gcc_jit_block_end_with_return (block, NULL, elapsed); +} + +static void +verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef uint64_t (*fntype) (void); + fntype test_i386_basic_asm_4 + = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_4"); + + CHECK_NON_NULL (test_i386_basic_asm_4); + + test_i386_basic_asm_4 (); +} + +/********************************************************************** + test_i386_basic_asm_5: test of top-level asm + **********************************************************************/ + +/* Create the equivalent of: + + // Quote from here in docs/topics/asm.rst: example 5: C + asm ("\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t.popsection\n"); + // Quote up to here in docs/topics/asm.rst: example 5: C + + to add a simple function ("add_asm") directly in assembly language. */ + +static void +create_test_i386_basic_asm_5 (gcc_jit_context *ctxt) +{ + /* Quote from here in docs/topics/asm.rst: example 5: jit. */ + gcc_jit_context_add_top_level_asm (ctxt, NULL, + "\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t# some asm here\n" + "\t.popsection\n"); + /* Quote up to here in docs/topics/asm.rst: example 5: jit. */ +} + +static void +verify_code_5 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*test_i386_basic_asm_5_type) (int, int); + test_i386_basic_asm_5_type test_i386_basic_asm_5 + = (test_i386_basic_asm_5_type) gcc_jit_result_get_code (result, "add_asm"); + CHECK_NON_NULL (test_i386_basic_asm_5); + + CHECK_VALUE (test_i386_basic_asm_5 (2, 2), 4); + CHECK_VALUE (test_i386_basic_asm_5 (20, 7), 27); +} + +/********************************************************************** + Code for harness + **********************************************************************/ + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + create_test_i386_basic_asm_1 (ctxt); + create_test_i386_basic_asm_2 (ctxt); + create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3a", 0); + create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3b", 1); + create_test_i386_basic_asm_4 (ctxt); + create_test_i386_basic_asm_5 (ctxt); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + verify_code_1 (ctxt, result); + verify_code_2 (ctxt, result); + verify_code_3 (ctxt, result, "test_i386_basic_asm_3a"); + verify_code_3 (ctxt, result, "test_i386_basic_asm_3b"); + verify_code_4 (ctxt, result); + verify_code_5 (ctxt, result); +} diff --git a/gcc/testsuite/jit.dg/test-asm.cc b/gcc/testsuite/jit.dg/test-asm.cc new file mode 100644 index 0000000..6f18280 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-asm.cc @@ -0,0 +1,453 @@ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ + +#include "libgccjit++.h" + +#include "harness.h" + +/********************************************************************** + Support fns for creating code. + **********************************************************************/ + +/* Make a "void FUNC_NAME (void)" function with a single block, returning + that block. */ + +static gccjit::block +make_single_block_func (gccjit::context ctxt, const char *func_name) +{ + gccjit::type void_type = ctxt.get_type (GCC_JIT_TYPE_VOID); + std::vector params; + gccjit::function func + = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + void_type, + func_name, params, 0); + return func.new_block ("initial"); +} + +/********************************************************************** + Support fns for verifying code. + **********************************************************************/ + +typedef void (*void_void_fn) (void); + +static void_void_fn +get_test_fn (gcc_jit_result *result, const char *func_name) +{ + return (void_void_fn)gcc_jit_result_get_code (result, func_name); +} + +/********************************************************************** + test_i386_basic_asm_1: simple example of asm + **********************************************************************/ + +/* Create the equivalent of: + + int src; + int dst; + + void test_i386_basic_asm_1 (void) + { + // Quote from here in docs/cp/topics/asm.rst: example 1: C + asm ("mov %1, %0\n\t" + "add $1, %0" + : "=r" (dst) + : "r" (src)); + // Quote up to here in docs/cp/topics/asm.rst: example 1: C + } + + i.e. copy src to dst and add 1 to dst. */ + +static void +create_test_i386_basic_asm_1 (gcc_jit_context *c_ctxt) +{ + gccjit::context ctxt (c_ctxt); + gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT); + gccjit::lvalue dst + = ctxt.new_global (GCC_JIT_GLOBAL_EXPORTED, int_type, "dst"); + gccjit::lvalue src + = ctxt.new_global (GCC_JIT_GLOBAL_EXPORTED, int_type, "src"); + + gccjit::block block + = make_single_block_func (ctxt, "test_i386_basic_asm_1"); + + gccjit::extended_asm ext_asm = + /* Quote from here in docs/cp/topics/asm.rst: example 1: jit. */ + block.add_extended_asm ("mov %1, %0\n\t" + "add $1, %0") + .add_output_operand ("=r", dst) + .add_input_operand ("r", src); + /* Quote up to here in docs/cp/topics/asm.rst: example 1: jit. */ + + std::string desc = ext_asm.get_debug_string (); + CHECK_STRING_VALUE + (desc.c_str (), + "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )"); + + block.end_with_return (); +} + +static void +verify_code_1 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + void_void_fn test_i386_basic_asm_1 + = get_test_fn (result, "test_i386_basic_asm_1"); + CHECK_NON_NULL (test_i386_basic_asm_1); + + int *dst_ptr = (int *)gcc_jit_result_get_global (result, "dst"); + CHECK_NON_NULL (dst_ptr); + int *src_ptr = (int *)gcc_jit_result_get_global (result, "src"); + CHECK_NON_NULL (src_ptr); + + *src_ptr = 42; + *dst_ptr = 0; + test_i386_basic_asm_1 (); + CHECK_VALUE (*src_ptr, 42); + CHECK_VALUE (*dst_ptr, 43); +} + +/********************************************************************** + test_i386_basic_asm_2: test of symbolic names and clobbers + **********************************************************************/ + +/* Create the equivalent of: + uint32_t test_i386_basic_asm_2 (uint32_t Mask) + { + uint32_t Index; + // Quote from here in docs/cp/topics/asm.rst: example 2: C + asm ("bsfl %[aMask], %[aIndex]" + : [aIndex] "=r" (Index) + : [aMask] "r" (Mask) + : "cc"); + // Quote up to here in docs/cp/topics/asm.rst: example 2: C + return Index; + } + i.e. return the first bit set in "Mask" + + This exercises symbolic names and clobbers. */ + +static void +create_test_i386_basic_asm_2 (gcc_jit_context *c_ctxt) +{ + gccjit::context ctxt (c_ctxt); + gccjit::type uint32_type = ctxt.get_int_type (4, 0); + gccjit::param mask = ctxt.new_param (uint32_type, "Mask"); + std::vector params {mask}; + gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + uint32_type, + "test_i386_basic_asm_2", + params, 0); + gccjit::lvalue index = func.new_local (uint32_type, "Index"); + gccjit::block block = func.new_block ("initial"); + gccjit::extended_asm ext_asm = + /* Quote from here in docs/cp/topics/asm.rst: example 2: jit. */ + block.add_extended_asm ("bsfl %[aMask], %[aIndex]") + .add_output_operand ("aIndex", "=r", index) + .add_input_operand ("aMask", "r", mask) + .add_clobber ("cc"); + /* Quote up to here in docs/cp/topics/asm.rst: example 2: jit. */ + + std::string desc = ext_asm.get_debug_string (); + CHECK_STRING_VALUE + (desc.c_str (), + "asm (\"bsfl %[aMask], %[aIndex]\"" + " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")"); + + block.end_with_return (index); +} + +static void +verify_code_2 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef uint32_t (*fntype) (uint32_t); + fntype test_i386_basic_asm_2 + = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_2"); + CHECK_NON_NULL (test_i386_basic_asm_2); + + CHECK_VALUE (test_i386_basic_asm_2 (1), 0); + CHECK_VALUE (test_i386_basic_asm_2 (2), 1); + CHECK_VALUE (test_i386_basic_asm_2 (4), 2); + CHECK_VALUE (test_i386_basic_asm_2 (8), 3); +} + +/********************************************************************** + test_i386_basic_asm_3a/b: test of control flow: "asm goto" + **********************************************************************/ + +/* Create the equivalent of: + + int test_i386_basic_asm_3a (int p1, int p2) + { + asm goto ("btl %1, %0\n\t" + "jc %l2" + : // No outputs + : "r" (p1), "r" (p2) + : "cc" + : carry); + + return 0; + + carry: + return 1; + } + + or (the "_3b" variant) using a name rather than a number for the goto + label: + + // Quote from here in docs/cp/topics/asm.rst: example 3b: C + asm goto ("btl %1, %0\n\t" + "jc %l[carry]" + : // No outputs + : "r" (p1), "r" (p2) + : "cc" + : carry); + // Quote up to here in docs/cp/topics/asm.rst: example 3b: C + + This exercises control flow with an asm. */ + +static void +create_test_i386_basic_asm_3 (gcc_jit_context *c_ctxt, + const char *funcname, + int use_name) +{ + gccjit::context ctxt (c_ctxt); + gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT); + gccjit::param p1 = ctxt.new_param (int_type, "p1"); + gccjit::param p2 = ctxt.new_param (int_type, "p2"); + std::vector params ({p1, p2}); + gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + int_type, + funcname, + params, 0); + gccjit::block b_start = func.new_block ("start"); + gccjit::block b_fallthru = func.new_block ("fallthru"); + gccjit::block b_carry = func.new_block ("carry"); + + gccjit::rvalue zero = ctxt.new_rvalue (int_type, 0); + gccjit::rvalue one = ctxt.new_rvalue (int_type, 1); + + /* Quote from here in docs/cp/topics/asm.rst: example 3: jit. */ + const char *asm_template = + (use_name + ? /* Label referred to by name: "%l[carry]". */ + ("btl %1, %0\n\t" + "jc %l[carry]") + : /* Label referred to numerically: "%l2". */ + ("btl %1, %0\n\t" + "jc %l2")); + + std::vector goto_blocks ({b_carry}); + gccjit::extended_asm ext_asm + = (b_start.end_with_extended_asm_goto (asm_template, + goto_blocks, + &b_fallthru) + .add_input_operand ("r", p1) + .add_input_operand ("r", p2) + .add_clobber ("cc")); + /* Quote up to here in docs/cp/topics/asm.rst: example 3: jit. */ + + std::string desc = ext_asm.get_debug_string (); + CHECK_STRING_VALUE + (desc.c_str (), + (use_name + ? ("asm goto (\"btl %1, %0\\n\\tjc %l[carry]\" " + ": : \"r\" (p1), \"r\" (p2) : \"cc\" " + ": carry [fallthrough: fallthru])") + : ("asm goto (\"btl %1, %0\\n\\tjc %l2\" " + ": : \"r\" (p1), \"r\" (p2) : \"cc\" " + ": carry [fallthrough: fallthru])"))); + + b_fallthru.end_with_return (zero); + b_carry.end_with_return (one); +} + +static void +verify_code_3 (gcc_jit_context *ctxt, gcc_jit_result *result, + const char *funcname) +{ + typedef int (*test_i386_basic_asm_3_type) (int, int); + + test_i386_basic_asm_3_type test_i386_basic_asm_3 + = (test_i386_basic_asm_3_type) gcc_jit_result_get_code (result, funcname); + CHECK_NON_NULL (test_i386_basic_asm_3); + + /* The fn should test bits, returning 0 or 1. */ + /* Bit 0. */ + CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 0), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 0), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 0), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 0), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 0), 0); + /* Bit 1. */ + CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 1), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 1), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 1), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 1), 1); + CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 1), 0); + + for (int i = 0; i < 15; i++) + { + CHECK_VALUE (test_i386_basic_asm_3 (0x0000, i), 0); + CHECK_VALUE (test_i386_basic_asm_3 (0xffff, i), 1); + } +} + +/********************************************************************** + test_i386_basic_asm_4: test of "volatile" + **********************************************************************/ + +/* Create the equivalent of: + uint64_t test_i386_basic_asm_4 (void) + { + uint64_t start_time, end_time; + + // Get start time + asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (start_time) + : + : "rdx"); + + // could do other work here + + // Get end time + asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. + "shl $32, %%rdx\n\t" // Shift the upper bits left. + "or %%rdx, %0" // 'Or' in the lower bits. + : "=a" (start_time) + : + : "rdx"); + + // Get elapsed time + return end_time - start_time; + } + + This exercises "volatile"; without it, the optimizer can assume that + both asm generate the same value and thus the time difference is zero. */ + +static void +add_rdtsc (gccjit::block block, gccjit::lvalue msr) +{ + /* Quote from here in docs/cp/topics/asm.rst: example 4: jit. */ + gccjit::extended_asm ext_asm + = block.add_extended_asm + ("rdtsc\n\t" /* Returns the time in EDX:EAX. */ + "shl $32, %%rdx\n\t" /* Shift the upper bits left. */ + "or %%rdx, %0") /* 'Or' in the lower bits. */ + .set_volatile_flag (true) + .add_output_operand ("=a", msr) + .add_clobber ("rdx"); + /* Quote up to here in docs/cp/topics/asm.rst: example 4: jit. */ + + std::string desc = ext_asm.get_debug_string (); + CHECK_STRING_STARTS_WITH (desc.c_str (), "asm volatile ("); +} + +static void +create_test_i386_basic_asm_4 (gcc_jit_context *c_ctxt) +{ + gccjit::context ctxt (c_ctxt); + gccjit::type uint64_type = ctxt.get_int_type (8, 0); + std::vector params; + gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + uint64_type, + "test_i386_basic_asm_4", + params, 0); + gccjit::block block = func.new_block (); + + gccjit::lvalue start_time = func.new_local (uint64_type, "start_time"); + add_rdtsc (block, start_time); + + block.add_comment ("other work here"); + + gccjit::lvalue end_time = func.new_local (uint64_type, "end_time"); + add_rdtsc (block, end_time); + + block.end_with_return (end_time - start_time); +} + +static void +verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef uint64_t (*fntype) (void); + fntype test_i386_basic_asm_4 + = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_4"); + + CHECK_NON_NULL (test_i386_basic_asm_4); + + test_i386_basic_asm_4 (); +} + +/********************************************************************** + test_i386_basic_asm_5: test of top-level asm + **********************************************************************/ + +/* Create the equivalent of: + + // Quote from here in docs/cp/topics/asm.rst: example 5: C + asm ("\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t.popsection\n"); + // Quote up to here in docs/cp/topics/asm.rst: example 5: C + + to add a simple function ("add_asm") directly in assembly language. */ + +static void +create_test_i386_basic_asm_5 (gcc_jit_context *c_ctxt) +{ + gccjit::context ctxt (c_ctxt); + /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */ + ctxt.add_top_level_asm ("\t.pushsection .text\n" + "\t.globl add_asm\n" + "\t.type add_asm, @function\n" + "add_asm:\n" + "\tmovq %rdi, %rax\n" + "\tadd %rsi, %rax\n" + "\tret\n" + "\t# some asm here\n" + "\t.popsection\n"); + /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */ +} + +static void +verify_code_5 (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*test_i386_basic_asm_5_type) (int, int); + test_i386_basic_asm_5_type test_i386_basic_asm_5 + = (test_i386_basic_asm_5_type) gcc_jit_result_get_code (result, "add_asm"); + CHECK_NON_NULL (test_i386_basic_asm_5); + + CHECK_VALUE (test_i386_basic_asm_5 (2, 2), 4); + CHECK_VALUE (test_i386_basic_asm_5 (20, 7), 27); +} + +/********************************************************************** + Code for harness + **********************************************************************/ + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + create_test_i386_basic_asm_1 (ctxt); + create_test_i386_basic_asm_2 (ctxt); + create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3a", 0); + create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3b", 1); + create_test_i386_basic_asm_4 (ctxt); + create_test_i386_basic_asm_5 (ctxt); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + verify_code_1 (ctxt, result); + verify_code_2 (ctxt, result); + verify_code_3 (ctxt, result, "test_i386_basic_asm_3a"); + verify_code_3 (ctxt, result, "test_i386_basic_asm_3b"); + verify_code_4 (ctxt, result); + verify_code_5 (ctxt, result); +} -- cgit v1.1 From de6f64f9556ae39317186f3486135f1ef308a096 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 12 Nov 2020 19:07:40 -0500 Subject: c++: Don't form a templated TARGET_EXPR in finish_compound_literal The atom_cache in normalize_atom relies on the assumption that two equivalent (templated) trees (in the sense of cp_tree_equal) must use the same template parameters (according to find_template_parameters). This assumption unfortunately doesn't always hold for TARGET_EXPRs, because cp_tree_equal ignores an artificial target of a TARGET_EXPR, but find_template_parameters walks this target (and its DECL_CONTEXT). Hence two TARGET_EXPRs built by force_target_expr with the same initializer and under different settings of current_function_decl will compare equal according to cp_tree_equal, but find_template_parameters may return a different set of template parameters for them. This breaks the below testcase because during normalization we build two such TARGET_EXPRs (one under current_function_decl=f and another under =g), and then share the same ATOMIC_CONSTR for the two corresponding atoms, leading to a crash during satisfaction of g's associated constraints. This patch works around this issue by removing the source of these templated TARGET_EXPRs. The relevant call to get_target_expr_sfinae was added in r9-6043, and it seems it's no longer necessary (according to https://gcc.gnu.org/pipermail/gcc-patches/2019-February/517323.html, the call was added in order to avoid regressing on initlist109.C at the time). gcc/cp/ChangeLog: * semantics.c (finish_compound_literal): Don't wrap the original compound literal in a TARGET_EXPR when inside a template. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-decltype3.C: New test. --- gcc/cp/semantics.c | 7 +------ gcc/testsuite/g++.dg/cpp2a/concepts-decltype3.C | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-decltype3.C (limited to 'gcc') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index df698d5..0389198 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3006,12 +3006,7 @@ finish_compound_literal (tree type, tree compound_literal, /* If we're in a template, return the original compound literal. */ if (orig_cl) - { - if (!VECTOR_TYPE_P (type)) - return get_target_expr_sfinae (orig_cl, complain); - else - return orig_cl; - } + return orig_cl; if (TREE_CODE (compound_literal) == CONSTRUCTOR) { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-decltype3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-decltype3.C new file mode 100644 index 0000000..837855c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-decltype3.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++20 } } + +template concept C = requires(T t) { t; }; + +template using A = decltype((T{}, int{})); + +template concept D = C>; + +template void f() requires D; +template void g() requires D; + +void h() { + f(); + g(); +} -- cgit v1.1 From a5a115258afd6c0bdd8ff4c8071dcffbafb88186 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 13 Nov 2020 00:16:35 +0000 Subject: Daily bump. --- gcc/ChangeLog | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 35 +++++++++++ gcc/c-family/ChangeLog | 14 +++++ gcc/cp/ChangeLog | 12 ++++ gcc/fortran/ChangeLog | 21 +++++++ gcc/jit/ChangeLog | 132 +++++++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 74 +++++++++++++++++++++++ 8 files changed, 442 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e515b38..a180527 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,156 @@ +2020-11-12 Nelson Chu + + * configure: Regenerated. + * configure.ac: If ifunc was supported in the binutils for + linux toolchain, then set enable_gnu_indirect_function to yes. + +2020-11-12 Joseph Myers + + * doc/cpp.texi (__has_attribute): Document when scopes are allowed + for C. + (__has_c_attribute): New. + +2020-11-12 Jakub Jelinek + + * builtin-types.def (BT_FN_PTR_SIZE_SIZE_PTRMODE): New function type. + * omp-builtins.def (BUILT_IN_GOACC_DECLARE): Move earlier. + (BUILT_IN_GOMP_ALLOC, BUILT_IN_GOMP_FREE): New builtins. + * gimplify.c (gimplify_scan_omp_clauses): Force allocator into a + decl if it is not NULL, INTEGER_CST or decl. + (gimplify_adjust_omp_clauses): Clear GOVD_EXPLICIT on explicit clauses + which are being removed. Remove allocate clauses for variables not seen + if they are private, firstprivate or linear too. Call + omp_notice_variable on the allocator otherwise. + (gimplify_omp_for): Handle iterator vars mentioned in allocate clauses + similarly to non-is_gimple_reg iterators. + * omp-low.c (struct omp_context): Add allocate_map field. + (delete_omp_context): Delete it. + (scan_sharing_clauses): Fill it from allocate clauses. Remove it + if mentioned also in shared clause. + (lower_private_allocate): New function. + (lower_rec_input_clauses): Handle allocate clause for privatized + variables, except for task/taskloop, C/C++ array reductions for now + and task/inscan variables. + (lower_send_shared_vars): Don't consider variables in allocate_map + as shared. + * omp-expand.c (expand_omp_for_generic, expand_omp_for_static_nochunk, + expand_omp_for_static_chunk): Use expand_omp_build_assign instead of + gimple_build_assign + gsi_insert_after. + * builtins.c (builtin_fnspec): Handle BUILTIN_GOMP_ALLOC and + BUILTIN_GOMP_FREE. + * tree-ssa-ccp.c (evaluate_stmt): Handle BUILTIN_GOMP_ALLOC. + * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Handle + BUILTIN_GOMP_ALLOC. + (mark_all_reaching_defs_necessary_1): Handle BUILTIN_GOMP_ALLOC + and BUILTIN_GOMP_FREE. + (propagate_necessity): Likewise. + +2020-11-12 Martin Jambor + + * cgraphclones.c (cgraph_node::materialize_clone): Check that clone + info is not NULL before attempting to dump it. + +2020-11-12 Martin Jambor + + * ipa-cp.c (class ipcp_value_base): Change the type of + local_time_benefit and prop_time_benefit to sreal. Adjust the + constructor initializer. + (ipcp_lattice::print): Dump sreals. + (struct caller_statistics): Change the type of freq_sum to sreal. + (gather_caller_stats): Work with sreal freq_sum. + (incorporate_penalties): Work with sreal evaluation. + (good_cloning_opportunity_p): Adjusted for sreal sreal time_benefit + and freq_sum. Bail out if size_cost is INT_MAX. + (perform_estimation_of_a_value): Work with sreal time_benefit. Avoid + unnecessary capping. + (estimate_local_effects): Pass sreal time benefit to + good_cloning_opportunity_p without capping it. Adjust dumping. + (safe_add): If there can be overflow, return INT_MAX. + (propagate_effects): Work with sreal times. + (get_info_about_necessary_edges): Work with sreal frequencies. + (decide_about_value): Likewise and with sreal time benefits. + +2020-11-12 Marek Polacek + + * system.h (WARN_UNUSED_RESULT): Define for GCC >= 3.4. + * tree.h (maybe_wrap_with_location): Add WARN_UNUSED_RESULT. + +2020-11-12 Jan Hubicka + + * fold-const.c (operand_compare::operand_equal_p): Compare field + offsets in operand_equal_p and OEP_ADDRESS_OF. + (operand_compare::hash_operand): Update. + +2020-11-12 Richard Biener + + * bitmap.c (bitmap_list_view): Restore head->current. + * tree-ssa-pre.c (pre_expr_DFS): Elide expr_visited bitmap. + Special-case value expression bitmaps with one element. + (bitmap_find_leader): Likewise. + (sorted_array_from_bitmap_set): Elide expr_visited bitmap. + +2020-11-12 Jan Hubicka + + * attr-fnspec.h: Update topleve comment. + (attr_fnspec::arg_direct_p): Accept 1...9. + (attr_fnspec::arg_maybe_written_p): Reject 1...9. + (attr_fnspec::arg_copied_to_arg_p): New member function. + * builtins.c (builtin_fnspec): Update fnspec of block copy. + * tree-ssa-alias.c (attr_fnspec::verify): Update. + +2020-11-12 Richard Biener + + * tree-ssa-pre.c (bitmap_value_replace_in_set): Return + whether we have changed anything. + (do_pre_regular_insertion): Get topologically sorted array + of expressions from caller. + (do_pre_partial_partial_insertion): Likewise. + (insert): Compute topologically sorted arrays of expressions + here and locally iterate actual insertion. Iterate only + when AVAIL_OUT of an already visited block source changed. + +2020-11-12 Alex Coplan + + PR target/97730 + * config/aarch64/aarch64-sve2.md (@aarch64_sve2_bcax): + Change to define_expand, add missing (trivially-predicated) not + rtx to fix wrong code bug. + (*aarch64_sve2_bcax): New. + +2020-11-12 Richard Biener + + PR tree-optimization/97806 + * tree-ssa-pre.c (pre_expr_DFS): New overload for visiting + values, visiting all leaders for a value. Use a bitmap + for visited values. + (sorted_array_from_bitmap_set): Walk over values and adjust. + +2020-11-12 Andreas Krebbel + + PR target/97326 + * config/s390/vector.md: Support vector floating point modes in + vec_cmp. + +2020-11-12 Andreas Krebbel + + * config/s390/vector.md: Rename tointvec to TOINTVEC. + * config/s390/vx-builtins.md: Likewise. + +2020-11-12 Jason Merrill + + PR debug/97060 + * dwarf2out.c (gen_subprogram_die): It's a declaration + if DECL_INITIAL isn't set. + +2020-11-12 David Malcolm + + PR tree-optimization/97424 + * doc/invoke.texi (Static Analyzer Options): Add + -Wno-analyzer-shift-count-negative and + -Wno-analyzer-shift-count-overflow. + (-Wno-analyzer-shift-count-negative): New. + (-Wno-analyzer-shift-count-overflow): New. + 2020-11-11 Iain Sandoe * config/darwin-protos.h (darwin_make_eh_symbol_indirect): New. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 95634e0..b84a76f 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20201112 +20201113 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 143f2f8..f0dd270 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,38 @@ +2020-11-12 David Malcolm + + * checker-path.h (checker_event::get_id_ptr): New. + * diagnostic-manager.cc (path_builder::path_builder): Add "sd" + param and use it to initialize new field "m_sd". + (path_builder::get_pending_diagnostic): New. + (path_builder::m_sd): New field. + (diagnostic_manager::emit_saved_diagnostic): Pass sd to + path_builder ctor. + (diagnostic_manager::add_events_for_superedge): Call new + maybe_add_custom_events_for_superedge vfunc. + * engine.cc (stale_jmp_buf::stale_jmp_buf): Add "setjmp_point" + param and use it to initialize new field "m_setjmp_point". + Initialize new field "m_stack_pop_event". + (stale_jmp_buf::maybe_add_custom_events_for_superedge): New vfunc + implementation. + (stale_jmp_buf::describe_final_event): New vfunc implementation. + (stale_jmp_buf::m_setjmp_point): New field. + (stale_jmp_buf::m_stack_pop_event): New field. + (exploded_node::on_longjmp): Pass setjmp_point to stale_jmp_buf + ctor. + * pending-diagnostic.h + (pending_diagnostic::maybe_add_custom_events_for_superedge): New + vfunc. + +2020-11-12 David Malcolm + + PR tree-optimization/97424 + * analyzer.opt (Wanalyzer-shift-count-negative): New. + (Wanalyzer-shift-count-overflow): New. + * region-model.cc (class shift_count_negative_diagnostic): New. + (class shift_count_overflow_diagnostic): New. + (region_model::get_gassign_result): Complain about shift counts that + are negative or are >= the operand's type's width. + 2020-11-10 Martin Liska * constraint-manager.cc (constraint_manager::merge): Remove diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 772b0f5..5761942 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,17 @@ +2020-11-12 Joseph Myers + + * c-lex.c (c_common_has_attribute): Take argument std_syntax. + Allow scope for C. Handle standard attributes for C. Do not + accept unscoped attributes if std_syntax and not handled as + standard attributes. + * c-common.h (c_common_has_attribute): Update prototype. + +2020-11-12 Nicholas Guriev + + PR pch/86674 + * c-pch.c (c_common_valid_pch): Use cpp_warning with CPP_W_INVALID_PCH + reason to fix -Werror=invalid-pch and -Wno-error=invalid-pch switches. + 2020-11-11 Patrick Palka PR c++/88115 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index babb459..f514ceb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2020-11-13 Patrick Palka + + * semantics.c (finish_compound_literal): Don't wrap the original + compound literal in a TARGET_EXPR when inside a template. + +2020-11-12 Jakub Jelinek + + PR c++/97790 + * constexpr.c (cxx_eval_constant_expression) : Don't pass jump_target to + cxx_eval_constant_expression when evaluating the cleanups. + 2020-11-11 Iain Sandoe * parser.c (cp_parser_declaration): Unless we are compiling for diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6eb6500..91b519d 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,24 @@ +2020-11-12 Jakub Jelinek + + * f95-lang.c (ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST): + Define. + (gfc_init_builtin_functions): Add alloc_size and warn_unused_result + attributes to __builtin_GOMP_alloc. + * types.def (BT_PTRMODE): New primitive type. + (BT_FN_VOID_PTR_PTRMODE, BT_FN_PTR_SIZE_SIZE_PTRMODE): New function + types. + +2020-11-12 Tobias Burnus + + PR fortran/97782 + * trans-openmp.c (gfc_trans_oacc_construct, gfc_trans_omp_parallel_do, + gfc_trans_omp_parallel_do_simd, gfc_trans_omp_parallel_sections, + gfc_trans_omp_parallel_workshare, gfc_trans_omp_sections + gfc_trans_omp_single, gfc_trans_omp_task, gfc_trans_omp_teams + gfc_trans_omp_target, gfc_trans_omp_target_data, + gfc_trans_omp_workshare): Use code->loc instead of input_location + when building the OMP_/OACC_ construct. + 2020-11-11 Jakub Jelinek PR fortran/97768 diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 48bd54d..e45b4e3 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,135 @@ +2020-11-12 David Malcolm + + PR jit/87291 + * docs/cp/topics/asm.rst: New file. + * docs/cp/topics/index.rst (Topic Reference): Add it. + * docs/topics/asm.rst: New file. + * docs/topics/compatibility.rst (LIBGCCJIT_ABI_15): New. + * docs/topics/functions.rst (Statements): Add link to extended + asm. + * docs/topics/index.rst (Topic Reference): Add asm.rst. + * docs/topics/objects.rst: Add gcc_jit_extended_asm to ASCII art. + * docs/_build/texinfo/Makefile: Regenerate. + * docs/_build/texinfo/libgccjit.texi: Regenerate. + * jit-common.h (gcc::jit::recording::extended_asm): New forward + decl. + (gcc::jit::recording::top_level_asm): Likewise. + * jit-playback.c: Include "stmt.h". + (build_string): New. + (gcc::jit::playback::context::new_string_literal): Disambiguate + build_string call. + (gcc::jit::playback::context::add_top_level_asm): New. + (build_operand_chain): New. + (build_clobbers): New. + (build_goto_operands): New. + (gcc::jit::playback::block::add_extended_asm): New. + * jit-playback.h (gcc::jit::playback::context::add_top_level_asm): + New decl. + (struct gcc::jit::playback::asm_operand): New struct. + (gcc::jit::playback::block::add_extended_asm): New decl. + * jit-recording.c (gcc::jit::recording::context::dump_to_file): + Dump top-level asms. + (gcc::jit::recording::context::add_top_level_asm): New. + (gcc::jit::recording::block::add_extended_asm): New. + (gcc::jit::recording::block::end_with_extended_asm_goto): New. + (gcc::jit::recording::asm_operand::asm_operand): New. + (gcc::jit::recording::asm_operand::print): New. + (gcc::jit::recording::asm_operand::make_debug_string): New. + (gcc::jit::recording::output_asm_operand::write_reproducer): New. + (gcc::jit::recording::output_asm_operand::print): New. + (gcc::jit::recording::input_asm_operand::write_reproducer): New. + (gcc::jit::recording::input_asm_operand::print): New. + (gcc::jit::recording::extended_asm::add_output_operand): New. + (gcc::jit::recording::extended_asm::add_input_operand): New. + (gcc::jit::recording::extended_asm::add_clobber): New. + (gcc::jit::recording::extended_asm::replay_into): New. + (gcc::jit::recording::extended_asm::make_debug_string): New. + (gcc::jit::recording::extended_asm::write_flags): New. + (gcc::jit::recording::extended_asm::write_clobbers): New. + (gcc::jit::recording::extended_asm_simple::write_reproducer): New. + (gcc::jit::recording::extended_asm::maybe_populate_playback_blocks): + New. + (gcc::jit::recording::extended_asm_goto::extended_asm_goto): New. + (gcc::jit::recording::extended_asm_goto::replay_into): New. + (gcc::jit::recording::extended_asm_goto::write_reproducer): New. + (gcc::jit::recording::extended_asm_goto::get_successor_blocks): + New. + (gcc::jit::recording::extended_asm_goto::maybe_print_gotos): New. + (gcc::jit::recording::extended_asm_goto::maybe_populate_playback_blocks): + New. + (gcc::jit::recording::top_level_asm::top_level_asm): New. + (gcc::jit::recording::top_level_asm::replay_into): New. + (gcc::jit::recording::top_level_asm::make_debug_string): New. + (gcc::jit::recording::top_level_asm::write_to_dump): New. + (gcc::jit::recording::top_level_asm::write_reproducer): New. + * jit-recording.h + (gcc::jit::recording::context::add_top_level_asm): New decl. + (gcc::jit::recording::context::m_top_level_asms): New field. + (gcc::jit::recording::block::add_extended_asm): New decl. + (gcc::jit::recording::block::end_with_extended_asm_goto): New + decl. + (gcc::jit::recording::asm_operand): New class. + (gcc::jit::recording::output_asm_operand): New class. + (gcc::jit::recording::input_asm_operand): New class. + (gcc::jit::recording::extended_asm): New class. + (gcc::jit::recording::extended_asm_simple): New class. + (gcc::jit::recording::extended_asm_goto): New class. + (gcc::jit::recording::top_level_asm): New class. + * libgccjit++.h (gccjit::extended_asm): New forward decl. + (gccjit::context::add_top_level_asm): New. + (gccjit::block::add_extended_asm): New. + (gccjit::block::end_with_extended_asm_goto): New. + (gccjit::extended_asm): New class. + (gccjit::extended_asm::extended_asm): New ctors. + (gccjit::extended_asm::set_volatile_flag): New. + (gccjit::extended_asm::set_inline_flag): New. + (gccjit::extended_asm::add_output_operand): New. + (gccjit::extended_asm::add_input_operand): New. + (gccjit::extended_asm::add_clobber): New. + (gccjit::extended_asm::get_inner_extended_asm): New. + * libgccjit.c (struct gcc_jit_extended_asm): New. + (jit_error): Make "loc" param take a gcc::jit::recording::location * + rather than a gcc_jit_location *. + (gcc_jit_block_add_extended_asm): New entrypoint. + (gcc_jit_block_end_with_extended_asm_goto): New entrypoint. + (gcc_jit_extended_asm_as_object): New entrypoint. + (gcc_jit_extended_asm_set_volatile_flag): New entrypoint. + (gcc_jit_extended_asm_set_inline_flag): New entrypoint. + (gcc_jit_extended_asm_add_output_operand): New entrypoint. + (gcc_jit_extended_asm_add_clobber): New entrypoint. + (gcc_jit_context_add_top_level_asm): New entrypoint. + * libgccjit.h: Add gcc_jit_extended_asm to ASCII art. + (gcc_jit_extended_asm): New typedef. + (LIBGCCJIT_HAVE_ASM_STATEMENTS): New define. + (gcc_jit_block_add_extended_asm): New entrypoint. + (gcc_jit_block_end_with_extended_asm_goto): New entrypoint. + (gcc_jit_extended_asm_as_object): New entrypoint. + (gcc_jit_extended_asm_set_volatile_flag): New entrypoint. + (gcc_jit_extended_asm_set_inline_flag): New entrypoint. + (gcc_jit_extended_asm_add_output_operand): New entrypoint. + (gcc_jit_extended_asm_add_input_operand): New entrypoint. + (gcc_jit_extended_asm_add_clobber): New entrypoint. + (gcc_jit_context_add_top_level_asm): New entrypoint. + * libgccjit.map (LIBGCCJIT_ABI_15): New. + +2020-11-12 David Malcolm + + * jit-recording.c (recording::context::new_string): Add "escaped" + param and use it when creating the new recording::string instance. + (recording::string::string): Add "escaped" param and use it to + initialize m_escaped. + (recording::string::make_debug_string): Replace check that first + char is double-quote with use of m_escaped. Fix escaping of + '\t' and '\n'. Set "escaped" on the result. + * jit-recording.h (recording::context::new_string): Add "escaped" + param. + (recording::string::string): Add "escaped" param. + (recording::string::m_escaped): New field. + +2020-11-12 David Malcolm + + * libgccjit.h: Fix typo in comment. + 2020-09-14 Andrea Corallo * docs/_build/texinfo/libgccjit.texi: Regenerate. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cc2d10d..5edac48 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,77 @@ +2020-11-13 Patrick Palka + + * g++.dg/cpp2a/concepts-decltype3.C: New test. + +2020-11-12 David Malcolm + + PR jit/87291 + * jit.dg/jit.exp: Load target-supports-dg.exp. + Set dg-do-what-default. + (jit-dg-test): Set dg-do-what and call dg-get-options, skipping + the test if it's not supported on the given target. + * jit.dg/test-asm.c: New test. + * jit.dg/test-asm.cc: New test. + +2020-11-12 David Malcolm + + * jit.dg/test-debug-strings.c (create_code): Add tests of + string literal escaping. + +2020-11-12 Joseph Myers + + * gcc.dg/c2x-has-c-attribute-1.c, gcc.dg/c2x-has-c-attribute-2.c, + gcc.dg/c2x-has-c-attribute-3.c, gcc.dg/c2x-has-c-attribute-4.c: + New tests. + +2020-11-12 Tobias Burnus + + PR fortran/97782 + * gfortran.dg/goacc/classify-kernels-unparallelized.f95: Move dg-message + one line up. + * gfortran.dg/goacc/classify-kernels.f95: Likewise. + +2020-11-12 Thomas Koenig + + * gfortran.dg/entry_23.f: New test. + +2020-11-12 Alex Coplan + + PR target/97730 + * gcc.target/aarch64/sve2/bcax_1.c (OP): Add missing bitwise not + to match correct bcax semantics. + * gcc.dg/vect/pr97730.c: New test. + +2020-11-12 Richard Biener + + PR tree-optimization/97806 + * gcc.dg/pr97806.c: New testcase. + +2020-11-12 Jakub Jelinek + + PR c++/97790 + * g++.dg/cpp2a/constexpr-dtor9.C: New test. + +2020-11-12 Jason Merrill + + PR debug/97060 + * gcc.dg/debug/dwarf2/pr97060.c: New test. + +2020-11-12 Kewen Lin + + * gcc.dg/tree-ssa/pr96789.c: Adjusted by disabling loop + vectorization. + +2020-11-12 David Malcolm + + * gcc.dg/analyzer/setjmp-5.c: Update expected path output to show + an event where the pertinent stack frame is popped. Update + expected message from final event to reference this event. + +2020-11-12 David Malcolm + + PR tree-optimization/97424 + * gcc.dg/analyzer/invalid-shift-1.c: New test. + 2020-11-11 Patrick Palka PR c++/88115 -- cgit v1.1 From ee24da1b983a89b05303f2ac8828dd8cbe28d3b4 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 12 Nov 2020 19:25:59 -0500 Subject: Change range_handler, was Re: Fix gimple_expr_code? Adjust the range_handler to not use gimple_expr_code/type. * gimple-range.h (gimple_range_handler): Use gimple_assign and gimple_cond routines to get type and code. * range-op.cc (range_op_handler): Check for integral types. --- gcc/gimple-range.h | 8 ++++++-- gcc/range-op.cc | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 0aa6d46..88d2ada 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -97,8 +97,12 @@ extern bool gimple_range_calc_op2 (irange &r, const gimple *s, static inline range_operator * gimple_range_handler (const gimple *s) { - if ((gimple_code (s) == GIMPLE_ASSIGN) || (gimple_code (s) == GIMPLE_COND)) - return range_op_handler (gimple_expr_code (s), gimple_expr_type (s)); + if (gimple_code (s) == GIMPLE_ASSIGN) + return range_op_handler (gimple_assign_rhs_code (s), + TREE_TYPE (gimple_assign_lhs (s))); + if (gimple_code (s) == GIMPLE_COND) + return range_op_handler (gimple_cond_code (s), + TREE_TYPE (gimple_cond_lhs (s))); return NULL; } diff --git a/gcc/range-op.cc b/gcc/range-op.cc index aff9383..86d1af7 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3341,10 +3341,12 @@ pointer_table::pointer_table () range_operator * range_op_handler (enum tree_code code, tree type) { - // First check if there is apointer specialization. + // First check if there is a pointer specialization. if (POINTER_TYPE_P (type)) return pointer_tree_table[code]; - return integral_tree_table[code]; + if (INTEGRAL_TYPE_P (type)) + return integral_tree_table[code]; + return NULL; } // Cast the range in R to TYPE. -- cgit v1.1 From 2efb9eaaedfaa5b3d194c3184a1d56b702e2fe39 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 11 Nov 2020 18:30:01 +0100 Subject: Group tree-vrp.c by functionality. Earlier in this cycle there was some work by Giuliano Belinassi and myself to refactor tree-vrp.c. A lot of functions and globals were moved into independent classes, but the haphazard layout remained. Assertion methods were indispersed with the propagation code, and with the jump threading code, etc etc. This series of patches moves things around so that common functionality is geographically close. There is no change in behavior. I know this is all slated to go in the next release, but finding things in the current code base, even if just to compare with the ranger, is difficult. Since I keep getting bit by aarch64 regressions, I've tested the whole set of patches on aarch64, as well as individually on x86-64 Linux. gcc/ChangeLog: * tree-vrp.c (struct assert_locus): Move. (class vrp_insert): Rename to vrp_asserts. (vrp_insert::build_assert_expr_for): Move to vrp_asserts. (fp_predicate): Same. (vrp_insert::dump): Same. (vrp_insert::register_new_assert_for): Same. (extract_code_and_val_from_cond_with_ops): Move. (vrp_insert::finish_register_edge_assert_for): Move to vrp_asserts. (maybe_set_nonzero_bits): Move. (vrp_insert::find_conditional_asserts): Move to vrp_asserts. (stmt_interesting_for_vrp): Move. (struct case_info): Move. (compare_case_labels): Move. (lhs_of_dominating_assert): Move. (find_case_label_index): Move. (find_case_label_range): Move. (class vrp_asserts): New. (vrp_asserts::build_assert_expr_for): Rename from vrp_insert. (vrp_asserts::dump): Same. (vrp_asserts::register_new_assert_for): Same. (vrp_asserts::finish_register_edge_assert_for): Same. (vrp_asserts::find_conditional_asserts): Same. (vrp_asserts::compare_case_labels): Same. (vrp_asserts::find_switch_asserts): Same. (vrp_asserts::find_assert_locations_in_bb): Same. (vrp_asserts::find_assert_locations): Same. (vrp_asserts::process_assert_insertions_for): Same. (vrp_asserts::compare_assert_loc): Same. (vrp_asserts::process_assert_insertions): Same. (vrp_asserts::insert_range_assertions): Same. (vrp_asserts::all_imm_uses_in_stmt_or_feed_cond): Same. (vrp_asserts::remove_range_assertions): Same. (class vrp_prop): Move. (all_imm_uses_in_stmt_or_feed_cond): Move. (vrp_prop::vrp_initialize): Move. (class vrp_folder): Move. (vrp_folder::fold_predicate_in): Move. (vrp_folder::fold_stmt): Move. (vrp_prop::initialize): Move. (vrp_prop::visit_stmt): Move. (enum ssa_prop_result): Move. (vrp_prop::visit_phi): Move. (vrp_prop::finalize): Move. (class vrp_dom_walker): Rename to... (class vrp_jump_threader): ...this. (vrp_jump_threader::before_dom_children): Rename from vrp_dom_walker. (simplify_stmt_for_jump_threading): Rename to... (vrp_jump_threader::simplify_stmt): ...here. (vrp_jump_threader::after_dom_children): Same. (identify_jump_threads): Move. (vrp_prop::vrp_finalize): Move array bounds setup code to... (execute_vrp): ...here. --- gcc/tree-vrp.c | 2127 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 1057 insertions(+), 1070 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index e00c034..d3816ab 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -161,153 +161,6 @@ live_names::live_on_block_p (tree name, basic_block bb) && bitmap_bit_p (live[bb->index], SSA_NAME_VERSION (name))); } - -/* Location information for ASSERT_EXPRs. Each instance of this - structure describes an ASSERT_EXPR for an SSA name. Since a single - SSA name may have more than one assertion associated with it, these - locations are kept in a linked list attached to the corresponding - SSA name. */ -struct assert_locus -{ - /* Basic block where the assertion would be inserted. */ - basic_block bb; - - /* Some assertions need to be inserted on an edge (e.g., assertions - generated by COND_EXPRs). In those cases, BB will be NULL. */ - edge e; - - /* Pointer to the statement that generated this assertion. */ - gimple_stmt_iterator si; - - /* Predicate code for the ASSERT_EXPR. Must be COMPARISON_CLASS_P. */ - enum tree_code comp_code; - - /* Value being compared against. */ - tree val; - - /* Expression to compare. */ - tree expr; - - /* Next node in the linked list. */ - assert_locus *next; -}; - -class vrp_insert -{ -public: - vrp_insert (struct function *fn) : fun (fn) { } - - /* Traverse the flowgraph looking for conditional jumps to insert range - expressions. These range expressions are meant to provide information - to optimizations that need to reason in terms of value ranges. They - will not be expanded into RTL. See method implementation comment - for example. */ - void insert_range_assertions (); - - /* Convert range assertion expressions into the implied copies and - copy propagate away the copies. */ - void remove_range_assertions (); - - /* Dump all the registered assertions for all the names to FILE. */ - void dump (FILE *); - - /* Dump all the registered assertions for NAME to FILE. */ - void dump (FILE *file, tree name); - - /* Dump all the registered assertions for NAME to stderr. */ - void debug (tree name) - { - dump (stderr, name); - } - - /* Dump all the registered assertions for all the names to stderr. */ - void debug () - { - dump (stderr); - } - -private: - /* Set of SSA names found live during the RPO traversal of the function - for still active basic-blocks. */ - live_names live; - - /* Function to work on. */ - struct function *fun; - - /* If bit I is present, it means that SSA name N_i has a list of - assertions that should be inserted in the IL. */ - bitmap need_assert_for; - - /* Array of locations lists where to insert assertions. ASSERTS_FOR[I] - holds a list of ASSERT_LOCUS_T nodes that describe where - ASSERT_EXPRs for SSA name N_I should be inserted. */ - assert_locus **asserts_for; - - /* Finish found ASSERTS for E and register them at GSI. */ - void finish_register_edge_assert_for (edge e, gimple_stmt_iterator gsi, - vec &asserts); - - /* Determine whether the outgoing edges of BB should receive an - ASSERT_EXPR for each of the operands of BB's LAST statement. The - last statement of BB must be a SWITCH_EXPR. - - If any of the sub-graphs rooted at BB have an interesting use of - the predicate operands, an assert location node is added to the - list of assertions for the corresponding operands. */ - void find_switch_asserts (basic_block bb, gswitch *last); - - /* Do an RPO walk over the function computing SSA name liveness - on-the-fly and deciding on assert expressions to insert. */ - void find_assert_locations (); - - /* Traverse all the statements in block BB looking for statements that - may generate useful assertions for the SSA names in their operand. - See method implementation comentary for more information. */ - void find_assert_locations_in_bb (basic_block bb); - - /* Determine whether the outgoing edges of BB should receive an - ASSERT_EXPR for each of the operands of BB's LAST statement. - The last statement of BB must be a COND_EXPR. - - If any of the sub-graphs rooted at BB have an interesting use of - the predicate operands, an assert location node is added to the - list of assertions for the corresponding operands. */ - void find_conditional_asserts (basic_block bb, gcond *last); - - /* Process all the insertions registered for every name N_i registered - in NEED_ASSERT_FOR. The list of assertions to be inserted are - found in ASSERTS_FOR[i]. */ - void process_assert_insertions (); - - /* If NAME doesn't have an ASSERT_EXPR registered for asserting - 'EXPR COMP_CODE VAL' at a location that dominates block BB or - E->DEST, then register this location as a possible insertion point - for ASSERT_EXPR . - - BB, E and SI provide the exact insertion point for the new - ASSERT_EXPR. If BB is NULL, then the ASSERT_EXPR is to be inserted - on edge E. Otherwise, if E is NULL, the ASSERT_EXPR is inserted on - BB. If SI points to a COND_EXPR or a SWITCH_EXPR statement, then E - must not be NULL. */ - void register_new_assert_for (tree name, tree expr, - enum tree_code comp_code, - tree val, basic_block bb, - edge e, gimple_stmt_iterator si); - - /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, - create a new SSA name N and return the assertion assignment - 'N = ASSERT_EXPR '. */ - gimple *build_assert_expr_for (tree cond, tree v); - - /* Create an ASSERT_EXPR for NAME and insert it in the location - indicated by LOC. Return true if we made any edge insertions. */ - bool process_assert_insertions_for (tree name, assert_locus *loc); - - /* Qsort callback for sorting assert locations. */ - template static int compare_assert_loc (const void *, - const void *); -}; - /* Return true if the SSA name NAME is live on the edge E. */ bool @@ -1266,48 +1119,6 @@ range_fold_unary_expr (value_range *vr, op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type)); } -/* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, - create a new SSA name N and return the assertion assignment - 'N = ASSERT_EXPR '. */ - -gimple * -vrp_insert::build_assert_expr_for (tree cond, tree v) -{ - tree a; - gassign *assertion; - - gcc_assert (TREE_CODE (v) == SSA_NAME - && COMPARISON_CLASS_P (cond)); - - a = build2 (ASSERT_EXPR, TREE_TYPE (v), v, cond); - assertion = gimple_build_assign (NULL_TREE, a); - - /* The new ASSERT_EXPR, creates a new SSA name that replaces the - operand of the ASSERT_EXPR. Create it so the new name and the old one - are registered in the replacement table so that we can fix the SSA web - after adding all the ASSERT_EXPRs. */ - tree new_def = create_new_def_for (v, assertion, NULL); - /* Make sure we preserve abnormalness throughout an ASSERT_EXPR chain - given we have to be able to fully propagate those out to re-create - valid SSA when removing the asserts. */ - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (v)) - SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_def) = 1; - - return assertion; -} - - -/* Return false if EXPR is a predicate expression involving floating - point values. */ - -static inline bool -fp_predicate (gimple *stmt) -{ - GIMPLE_CHECK (stmt, GIMPLE_COND); - - return FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))); -} - /* If the range of values taken by OP can be inferred after STMT executes, return the comparison code (COMP_CODE_P) and value (VAL_P) that describes the inferred range. Return true if a range could be @@ -1350,54 +1161,6 @@ infer_value_range (gimple *stmt, tree op, tree_code *comp_code_p, tree *val_p) return false; } -/* Dump all the registered assertions for NAME to FILE. */ - -void -vrp_insert::dump (FILE *file, tree name) -{ - assert_locus *loc; - - fprintf (file, "Assertions to be inserted for "); - print_generic_expr (file, name); - fprintf (file, "\n"); - - loc = asserts_for[SSA_NAME_VERSION (name)]; - while (loc) - { - fprintf (file, "\t"); - print_gimple_stmt (file, gsi_stmt (loc->si), 0); - fprintf (file, "\n\tBB #%d", loc->bb->index); - if (loc->e) - { - fprintf (file, "\n\tEDGE %d->%d", loc->e->src->index, - loc->e->dest->index); - dump_edge_info (file, loc->e, dump_flags, 0); - } - fprintf (file, "\n\tPREDICATE: "); - print_generic_expr (file, loc->expr); - fprintf (file, " %s ", get_tree_code_name (loc->comp_code)); - print_generic_expr (file, loc->val); - fprintf (file, "\n\n"); - loc = loc->next; - } - - fprintf (file, "\n"); -} - -/* Dump all the registered assertions for all the names to FILE. */ - -void -vrp_insert::dump (FILE *file) -{ - unsigned i; - bitmap_iterator bi; - - fprintf (file, "\nASSERT_EXPRs to be inserted\n\n"); - EXECUTE_IF_SET_IN_BITMAP (need_assert_for, 0, i, bi) - dump (file, ssa_name (i)); - fprintf (file, "\n"); -} - /* Dump assert_info structure. */ void @@ -1457,133 +1220,22 @@ add_assert_info (vec &asserts, name, expr, op_symbol_code (comp_code), val); } -/* If NAME doesn't have an ASSERT_EXPR registered for asserting - 'EXPR COMP_CODE VAL' at a location that dominates block BB or - E->DEST, then register this location as a possible insertion point - for ASSERT_EXPR . - - BB, E and SI provide the exact insertion point for the new - ASSERT_EXPR. If BB is NULL, then the ASSERT_EXPR is to be inserted - on edge E. Otherwise, if E is NULL, the ASSERT_EXPR is inserted on - BB. If SI points to a COND_EXPR or a SWITCH_EXPR statement, then E - must not be NULL. */ +/* (COND_OP0 COND_CODE COND_OP1) is a predicate which uses NAME. + Extract a suitable test code and value and store them into *CODE_P and + *VAL_P so the predicate is normalized to NAME *CODE_P *VAL_P. -void -vrp_insert::register_new_assert_for (tree name, tree expr, - enum tree_code comp_code, - tree val, - basic_block bb, - edge e, - gimple_stmt_iterator si) -{ - assert_locus *n, *loc, *last_loc; - basic_block dest_bb; + If no extraction was possible, return FALSE, otherwise return TRUE. - gcc_checking_assert (bb == NULL || e == NULL); + If INVERT is true, then we invert the result stored into *CODE_P. */ - if (e == NULL) - gcc_checking_assert (gimple_code (gsi_stmt (si)) != GIMPLE_COND - && gimple_code (gsi_stmt (si)) != GIMPLE_SWITCH); - - /* Never build an assert comparing against an integer constant with - TREE_OVERFLOW set. This confuses our undefined overflow warning - machinery. */ - if (TREE_OVERFLOW_P (val)) - val = drop_tree_overflow (val); - - /* The new assertion A will be inserted at BB or E. We need to - determine if the new location is dominated by a previously - registered location for A. If we are doing an edge insertion, - assume that A will be inserted at E->DEST. Note that this is not - necessarily true. - - If E is a critical edge, it will be split. But even if E is - split, the new block will dominate the same set of blocks that - E->DEST dominates. - - The reverse, however, is not true, blocks dominated by E->DEST - will not be dominated by the new block created to split E. So, - if the insertion location is on a critical edge, we will not use - the new location to move another assertion previously registered - at a block dominated by E->DEST. */ - dest_bb = (bb) ? bb : e->dest; - - /* If NAME already has an ASSERT_EXPR registered for COMP_CODE and - VAL at a block dominating DEST_BB, then we don't need to insert a new - one. Similarly, if the same assertion already exists at a block - dominated by DEST_BB and the new location is not on a critical - edge, then update the existing location for the assertion (i.e., - move the assertion up in the dominance tree). - - Note, this is implemented as a simple linked list because there - should not be more than a handful of assertions registered per - name. If this becomes a performance problem, a table hashed by - COMP_CODE and VAL could be implemented. */ - loc = asserts_for[SSA_NAME_VERSION (name)]; - last_loc = loc; - while (loc) - { - if (loc->comp_code == comp_code - && (loc->val == val - || operand_equal_p (loc->val, val, 0)) - && (loc->expr == expr - || operand_equal_p (loc->expr, expr, 0))) - { - /* If E is not a critical edge and DEST_BB - dominates the existing location for the assertion, move - the assertion up in the dominance tree by updating its - location information. */ - if ((e == NULL || !EDGE_CRITICAL_P (e)) - && dominated_by_p (CDI_DOMINATORS, loc->bb, dest_bb)) - { - loc->bb = dest_bb; - loc->e = e; - loc->si = si; - return; - } - } - - /* Update the last node of the list and move to the next one. */ - last_loc = loc; - loc = loc->next; - } - - /* If we didn't find an assertion already registered for - NAME COMP_CODE VAL, add a new one at the end of the list of - assertions associated with NAME. */ - n = XNEW (struct assert_locus); - n->bb = dest_bb; - n->e = e; - n->si = si; - n->comp_code = comp_code; - n->val = val; - n->expr = expr; - n->next = NULL; - - if (last_loc) - last_loc->next = n; - else - asserts_for[SSA_NAME_VERSION (name)] = n; - - bitmap_set_bit (need_assert_for, SSA_NAME_VERSION (name)); -} - -/* (COND_OP0 COND_CODE COND_OP1) is a predicate which uses NAME. - Extract a suitable test code and value and store them into *CODE_P and - *VAL_P so the predicate is normalized to NAME *CODE_P *VAL_P. - - If no extraction was possible, return FALSE, otherwise return TRUE. - - If INVERT is true, then we invert the result stored into *CODE_P. */ - -static bool -extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code, - tree cond_op0, tree cond_op1, - bool invert, enum tree_code *code_p, - tree *val_p) -{ - enum tree_code comp_code; - tree val; +static bool +extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code, + tree cond_op0, tree cond_op1, + bool invert, enum tree_code *code_p, + tree *val_p) +{ + enum tree_code comp_code; + tree val; /* Otherwise, we have a comparison of the form NAME COMP VAL or VAL COMP NAME. */ @@ -2578,94 +2230,746 @@ register_edge_assert_for (tree name, edge e, } } -/* Finish found ASSERTS for E and register them at GSI. */ +/* Handle + _4 = x_3 & 31; + if (_4 != 0) + goto ; + else + goto ; + : + __builtin_unreachable (); + : + x_5 = ASSERT_EXPR ; + If x_3 has no other immediate uses (checked by caller), + var is the x_3 var from ASSERT_EXPR, we can clear low 5 bits + from the non-zero bitmask. */ void -vrp_insert::finish_register_edge_assert_for (edge e, gimple_stmt_iterator gsi, - vec &asserts) +maybe_set_nonzero_bits (edge e, tree var) { - for (unsigned i = 0; i < asserts.length (); ++i) - /* Only register an ASSERT_EXPR if NAME was found in the sub-graph - reachable from E. */ - if (live.live_on_edge_p (asserts[i].name, e)) - register_new_assert_for (asserts[i].name, asserts[i].expr, - asserts[i].comp_code, asserts[i].val, - NULL, e, gsi); -} + basic_block cond_bb = e->src; + gimple *stmt = last_stmt (cond_bb); + tree cst; + if (stmt == NULL + || gimple_code (stmt) != GIMPLE_COND + || gimple_cond_code (stmt) != ((e->flags & EDGE_TRUE_VALUE) + ? EQ_EXPR : NE_EXPR) + || TREE_CODE (gimple_cond_lhs (stmt)) != SSA_NAME + || !integer_zerop (gimple_cond_rhs (stmt))) + return; + stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt)); + if (!is_gimple_assign (stmt) + || gimple_assign_rhs_code (stmt) != BIT_AND_EXPR + || TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST) + return; + if (gimple_assign_rhs1 (stmt) != var) + { + gimple *stmt2; -/* Determine whether the outgoing edges of BB should receive an - ASSERT_EXPR for each of the operands of BB's LAST statement. - The last statement of BB must be a COND_EXPR. + if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME) + return; + stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)); + if (!gimple_assign_cast_p (stmt2) + || gimple_assign_rhs1 (stmt2) != var + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt2)) + || (TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt))) + != TYPE_PRECISION (TREE_TYPE (var)))) + return; + } + cst = gimple_assign_rhs2 (stmt); + set_nonzero_bits (var, wi::bit_and_not (get_nonzero_bits (var), + wi::to_wide (cst))); +} - If any of the sub-graphs rooted at BB have an interesting use of - the predicate operands, an assert location node is added to the - list of assertions for the corresponding operands. */ +/* Return true if STMT is interesting for VRP. */ -void -vrp_insert::find_conditional_asserts (basic_block bb, gcond *last) +bool +stmt_interesting_for_vrp (gimple *stmt) { - gimple_stmt_iterator bsi; - tree op; - edge_iterator ei; - edge e; - ssa_op_iter iter; - - bsi = gsi_for_stmt (last); - - /* Look for uses of the operands in each of the sub-graphs - rooted at BB. We need to check each of the outgoing edges - separately, so that we know what kind of ASSERT_EXPR to - insert. */ - FOR_EACH_EDGE (e, ei, bb->succs) + if (gimple_code (stmt) == GIMPLE_PHI) { - if (e->dest == bb) - continue; + tree res = gimple_phi_result (stmt); + return (!virtual_operand_p (res) + && (INTEGRAL_TYPE_P (TREE_TYPE (res)) + || POINTER_TYPE_P (TREE_TYPE (res)))); + } + else if (is_gimple_assign (stmt) || is_gimple_call (stmt)) + { + tree lhs = gimple_get_lhs (stmt); - /* Register the necessary assertions for each operand in the - conditional predicate. */ - auto_vec asserts; - FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE) - register_edge_assert_for (op, e, - gimple_cond_code (last), - gimple_cond_lhs (last), - gimple_cond_rhs (last), asserts); - finish_register_edge_assert_for (e, bsi, asserts); + /* In general, assignments with virtual operands are not useful + for deriving ranges, with the obvious exception of calls to + builtin functions. */ + if (lhs && TREE_CODE (lhs) == SSA_NAME + && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs))) + && (is_gimple_call (stmt) + || !gimple_vuse (stmt))) + return true; + else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt)) + switch (gimple_call_internal_fn (stmt)) + { + case IFN_ADD_OVERFLOW: + case IFN_SUB_OVERFLOW: + case IFN_MUL_OVERFLOW: + case IFN_ATOMIC_COMPARE_EXCHANGE: + /* These internal calls return _Complex integer type, + but are interesting to VRP nevertheless. */ + if (lhs && TREE_CODE (lhs) == SSA_NAME) + return true; + break; + default: + break; + } } + else if (gimple_code (stmt) == GIMPLE_COND + || gimple_code (stmt) == GIMPLE_SWITCH) + return true; + + return false; } -struct case_info -{ - tree expr; - basic_block bb; -}; -/* Compare two case labels sorting first by the destination bb index - and then by the case value. */ +/* Return the LHS of any ASSERT_EXPR where OP appears as the first + argument to the ASSERT_EXPR and in which the ASSERT_EXPR dominates + BB. If no such ASSERT_EXPR is found, return OP. */ -static int -compare_case_labels (const void *p1, const void *p2) +static tree +lhs_of_dominating_assert (tree op, basic_block bb, gimple *stmt) { - const struct case_info *ci1 = (const struct case_info *) p1; - const struct case_info *ci2 = (const struct case_info *) p2; - int idx1 = ci1->bb->index; - int idx2 = ci2->bb->index; + imm_use_iterator imm_iter; + gimple *use_stmt; + use_operand_p use_p; - if (idx1 < idx2) - return -1; - else if (idx1 == idx2) + if (TREE_CODE (op) == SSA_NAME) { - /* Make sure the default label is first in a group. */ - if (!CASE_LOW (ci1->expr)) - return -1; - else if (!CASE_LOW (ci2->expr)) - return 1; - else - return tree_int_cst_compare (CASE_LOW (ci1->expr), - CASE_LOW (ci2->expr)); - } - else + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op) + { + use_stmt = USE_STMT (use_p); + if (use_stmt != stmt + && gimple_assign_single_p (use_stmt) + && TREE_CODE (gimple_assign_rhs1 (use_stmt)) == ASSERT_EXPR + && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == op + && dominated_by_p (CDI_DOMINATORS, bb, gimple_bb (use_stmt))) + return gimple_assign_lhs (use_stmt); + } + } + return op; +} + +/* A hack. */ +static class vr_values *x_vr_values; + +/* Searches the case label vector VEC for the index *IDX of the CASE_LABEL + that includes the value VAL. The search is restricted to the range + [START_IDX, n - 1] where n is the size of VEC. + + If there is a CASE_LABEL for VAL, its index is placed in IDX and true is + returned. + + If there is no CASE_LABEL for VAL and there is one that is larger than VAL, + it is placed in IDX and false is returned. + + If VAL is larger than any CASE_LABEL, n is placed on IDX and false is + returned. */ + +bool +find_case_label_index (gswitch *stmt, size_t start_idx, tree val, size_t *idx) +{ + size_t n = gimple_switch_num_labels (stmt); + size_t low, high; + + /* Find case label for minimum of the value range or the next one. + At each iteration we are searching in [low, high - 1]. */ + + for (low = start_idx, high = n; high != low; ) + { + tree t; + int cmp; + /* Note that i != high, so we never ask for n. */ + size_t i = (high + low) / 2; + t = gimple_switch_label (stmt, i); + + /* Cache the result of comparing CASE_LOW and val. */ + cmp = tree_int_cst_compare (CASE_LOW (t), val); + + if (cmp == 0) + { + /* Ranges cannot be empty. */ + *idx = i; + return true; + } + else if (cmp > 0) + high = i; + else + { + low = i + 1; + if (CASE_HIGH (t) != NULL + && tree_int_cst_compare (CASE_HIGH (t), val) >= 0) + { + *idx = i; + return true; + } + } + } + + *idx = high; + return false; +} + +/* Searches the case label vector VEC for the range of CASE_LABELs that is used + for values between MIN and MAX. The first index is placed in MIN_IDX. The + last index is placed in MAX_IDX. If the range of CASE_LABELs is empty + then MAX_IDX < MIN_IDX. + Returns true if the default label is not needed. */ + +bool +find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx, + size_t *max_idx) +{ + size_t i, j; + bool min_take_default = !find_case_label_index (stmt, 1, min, &i); + bool max_take_default = !find_case_label_index (stmt, i, max, &j); + + if (i == j + && min_take_default + && max_take_default) + { + /* Only the default case label reached. + Return an empty range. */ + *min_idx = 1; + *max_idx = 0; + return false; + } + else + { + bool take_default = min_take_default || max_take_default; + tree low, high; + size_t k; + + if (max_take_default) + j--; + + /* If the case label range is continuous, we do not need + the default case label. Verify that. */ + high = CASE_LOW (gimple_switch_label (stmt, i)); + if (CASE_HIGH (gimple_switch_label (stmt, i))) + high = CASE_HIGH (gimple_switch_label (stmt, i)); + for (k = i + 1; k <= j; ++k) + { + low = CASE_LOW (gimple_switch_label (stmt, k)); + if (!integer_onep (int_const_binop (MINUS_EXPR, low, high))) + { + take_default = true; + break; + } + high = low; + if (CASE_HIGH (gimple_switch_label (stmt, k))) + high = CASE_HIGH (gimple_switch_label (stmt, k)); + } + + *min_idx = i; + *max_idx = j; + return !take_default; + } +} + +/* Given a SWITCH_STMT, return the case label that encompasses the + known possible values for the switch operand. RANGE_OF_OP is a + range for the known values of the switch operand. */ + +tree +find_case_label_range (gswitch *switch_stmt, const irange *range_of_op) +{ + if (range_of_op->undefined_p () + || range_of_op->varying_p () + || range_of_op->symbolic_p ()) + return NULL_TREE; + + size_t i, j; + tree op = gimple_switch_index (switch_stmt); + tree type = TREE_TYPE (op); + tree tmin = wide_int_to_tree (type, range_of_op->lower_bound ()); + tree tmax = wide_int_to_tree (type, range_of_op->upper_bound ()); + find_case_label_range (switch_stmt, tmin, tmax, &i, &j); + if (i == j) + { + /* Look for exactly one label that encompasses the range of + the operand. */ + tree label = gimple_switch_label (switch_stmt, i); + tree case_high + = CASE_HIGH (label) ? CASE_HIGH (label) : CASE_LOW (label); + int_range_max label_range (CASE_LOW (label), case_high); + if (!types_compatible_p (label_range.type (), range_of_op->type ())) + range_cast (label_range, range_of_op->type ()); + label_range.intersect (range_of_op); + if (label_range == *range_of_op) + return label; + } + else if (i > j) + { + /* If there are no labels at all, take the default. */ + return gimple_switch_label (switch_stmt, 0); + } + else + { + /* Otherwise, there are various labels that can encompass + the range of operand. In which case, see if the range of + the operand is entirely *outside* the bounds of all the + (non-default) case labels. If so, take the default. */ + unsigned n = gimple_switch_num_labels (switch_stmt); + tree min_label = gimple_switch_label (switch_stmt, 1); + tree max_label = gimple_switch_label (switch_stmt, n - 1); + tree case_high = CASE_HIGH (max_label); + if (!case_high) + case_high = CASE_LOW (max_label); + int_range_max label_range (CASE_LOW (min_label), case_high); + if (!types_compatible_p (label_range.type (), range_of_op->type ())) + range_cast (label_range, range_of_op->type ()); + label_range.intersect (range_of_op); + if (label_range.undefined_p ()) + return gimple_switch_label (switch_stmt, 0); + } + return NULL_TREE; +} + +struct case_info +{ + tree expr; + basic_block bb; +}; + +/* Location information for ASSERT_EXPRs. Each instance of this + structure describes an ASSERT_EXPR for an SSA name. Since a single + SSA name may have more than one assertion associated with it, these + locations are kept in a linked list attached to the corresponding + SSA name. */ +struct assert_locus +{ + /* Basic block where the assertion would be inserted. */ + basic_block bb; + + /* Some assertions need to be inserted on an edge (e.g., assertions + generated by COND_EXPRs). In those cases, BB will be NULL. */ + edge e; + + /* Pointer to the statement that generated this assertion. */ + gimple_stmt_iterator si; + + /* Predicate code for the ASSERT_EXPR. Must be COMPARISON_CLASS_P. */ + enum tree_code comp_code; + + /* Value being compared against. */ + tree val; + + /* Expression to compare. */ + tree expr; + + /* Next node in the linked list. */ + assert_locus *next; +}; + +/* Class to traverse the flowgraph looking for conditional jumps to + insert ASSERT_EXPR range expressions. These range expressions are + meant to provide information to optimizations that need to reason + in terms of value ranges. They will not be expanded into RTL. */ + +class vrp_asserts +{ +public: + vrp_asserts (struct function *fn) : fun (fn) { } + + void insert_range_assertions (); + + /* Convert range assertion expressions into the implied copies and + copy propagate away the copies. */ + void remove_range_assertions (); + + /* Dump all the registered assertions for all the names to FILE. */ + void dump (FILE *); + + /* Dump all the registered assertions for NAME to FILE. */ + void dump (FILE *file, tree name); + + /* Dump all the registered assertions for NAME to stderr. */ + void debug (tree name) + { + dump (stderr, name); + } + + /* Dump all the registered assertions for all the names to stderr. */ + void debug () + { + dump (stderr); + } + +private: + /* Set of SSA names found live during the RPO traversal of the function + for still active basic-blocks. */ + live_names live; + + /* Function to work on. */ + struct function *fun; + + /* If bit I is present, it means that SSA name N_i has a list of + assertions that should be inserted in the IL. */ + bitmap need_assert_for; + + /* Array of locations lists where to insert assertions. ASSERTS_FOR[I] + holds a list of ASSERT_LOCUS_T nodes that describe where + ASSERT_EXPRs for SSA name N_I should be inserted. */ + assert_locus **asserts_for; + + /* Finish found ASSERTS for E and register them at GSI. */ + void finish_register_edge_assert_for (edge e, gimple_stmt_iterator gsi, + vec &asserts); + + /* Determine whether the outgoing edges of BB should receive an + ASSERT_EXPR for each of the operands of BB's LAST statement. The + last statement of BB must be a SWITCH_EXPR. + + If any of the sub-graphs rooted at BB have an interesting use of + the predicate operands, an assert location node is added to the + list of assertions for the corresponding operands. */ + void find_switch_asserts (basic_block bb, gswitch *last); + + /* Do an RPO walk over the function computing SSA name liveness + on-the-fly and deciding on assert expressions to insert. */ + void find_assert_locations (); + + /* Traverse all the statements in block BB looking for statements that + may generate useful assertions for the SSA names in their operand. + See method implementation comentary for more information. */ + void find_assert_locations_in_bb (basic_block bb); + + /* Determine whether the outgoing edges of BB should receive an + ASSERT_EXPR for each of the operands of BB's LAST statement. + The last statement of BB must be a COND_EXPR. + + If any of the sub-graphs rooted at BB have an interesting use of + the predicate operands, an assert location node is added to the + list of assertions for the corresponding operands. */ + void find_conditional_asserts (basic_block bb, gcond *last); + + /* Process all the insertions registered for every name N_i registered + in NEED_ASSERT_FOR. The list of assertions to be inserted are + found in ASSERTS_FOR[i]. */ + void process_assert_insertions (); + + /* If NAME doesn't have an ASSERT_EXPR registered for asserting + 'EXPR COMP_CODE VAL' at a location that dominates block BB or + E->DEST, then register this location as a possible insertion point + for ASSERT_EXPR . + + BB, E and SI provide the exact insertion point for the new + ASSERT_EXPR. If BB is NULL, then the ASSERT_EXPR is to be inserted + on edge E. Otherwise, if E is NULL, the ASSERT_EXPR is inserted on + BB. If SI points to a COND_EXPR or a SWITCH_EXPR statement, then E + must not be NULL. */ + void register_new_assert_for (tree name, tree expr, + enum tree_code comp_code, + tree val, basic_block bb, + edge e, gimple_stmt_iterator si); + + /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, + create a new SSA name N and return the assertion assignment + 'N = ASSERT_EXPR '. */ + gimple *build_assert_expr_for (tree cond, tree v); + + /* Create an ASSERT_EXPR for NAME and insert it in the location + indicated by LOC. Return true if we made any edge insertions. */ + bool process_assert_insertions_for (tree name, assert_locus *loc); + + /* Qsort callback for sorting assert locations. */ + template static int compare_assert_loc (const void *, + const void *); + + /* Return false if EXPR is a predicate expression involving floating + point values. */ + bool fp_predicate (gimple *stmt) + { + GIMPLE_CHECK (stmt, GIMPLE_COND); + return FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))); + } + + bool all_imm_uses_in_stmt_or_feed_cond (tree var, gimple *stmt, + basic_block cond_bb); + + static int compare_case_labels (const void *, const void *); +}; + +/* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, + create a new SSA name N and return the assertion assignment + 'N = ASSERT_EXPR '. */ + +gimple * +vrp_asserts::build_assert_expr_for (tree cond, tree v) +{ + tree a; + gassign *assertion; + + gcc_assert (TREE_CODE (v) == SSA_NAME + && COMPARISON_CLASS_P (cond)); + + a = build2 (ASSERT_EXPR, TREE_TYPE (v), v, cond); + assertion = gimple_build_assign (NULL_TREE, a); + + /* The new ASSERT_EXPR, creates a new SSA name that replaces the + operand of the ASSERT_EXPR. Create it so the new name and the old one + are registered in the replacement table so that we can fix the SSA web + after adding all the ASSERT_EXPRs. */ + tree new_def = create_new_def_for (v, assertion, NULL); + /* Make sure we preserve abnormalness throughout an ASSERT_EXPR chain + given we have to be able to fully propagate those out to re-create + valid SSA when removing the asserts. */ + if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (v)) + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_def) = 1; + + return assertion; +} + +/* Dump all the registered assertions for NAME to FILE. */ + +void +vrp_asserts::dump (FILE *file, tree name) +{ + assert_locus *loc; + + fprintf (file, "Assertions to be inserted for "); + print_generic_expr (file, name); + fprintf (file, "\n"); + + loc = asserts_for[SSA_NAME_VERSION (name)]; + while (loc) + { + fprintf (file, "\t"); + print_gimple_stmt (file, gsi_stmt (loc->si), 0); + fprintf (file, "\n\tBB #%d", loc->bb->index); + if (loc->e) + { + fprintf (file, "\n\tEDGE %d->%d", loc->e->src->index, + loc->e->dest->index); + dump_edge_info (file, loc->e, dump_flags, 0); + } + fprintf (file, "\n\tPREDICATE: "); + print_generic_expr (file, loc->expr); + fprintf (file, " %s ", get_tree_code_name (loc->comp_code)); + print_generic_expr (file, loc->val); + fprintf (file, "\n\n"); + loc = loc->next; + } + + fprintf (file, "\n"); +} + +/* Dump all the registered assertions for all the names to FILE. */ + +void +vrp_asserts::dump (FILE *file) +{ + unsigned i; + bitmap_iterator bi; + + fprintf (file, "\nASSERT_EXPRs to be inserted\n\n"); + EXECUTE_IF_SET_IN_BITMAP (need_assert_for, 0, i, bi) + dump (file, ssa_name (i)); + fprintf (file, "\n"); +} + +/* If NAME doesn't have an ASSERT_EXPR registered for asserting + 'EXPR COMP_CODE VAL' at a location that dominates block BB or + E->DEST, then register this location as a possible insertion point + for ASSERT_EXPR . + + BB, E and SI provide the exact insertion point for the new + ASSERT_EXPR. If BB is NULL, then the ASSERT_EXPR is to be inserted + on edge E. Otherwise, if E is NULL, the ASSERT_EXPR is inserted on + BB. If SI points to a COND_EXPR or a SWITCH_EXPR statement, then E + must not be NULL. */ + +void +vrp_asserts::register_new_assert_for (tree name, tree expr, + enum tree_code comp_code, + tree val, + basic_block bb, + edge e, + gimple_stmt_iterator si) +{ + assert_locus *n, *loc, *last_loc; + basic_block dest_bb; + + gcc_checking_assert (bb == NULL || e == NULL); + + if (e == NULL) + gcc_checking_assert (gimple_code (gsi_stmt (si)) != GIMPLE_COND + && gimple_code (gsi_stmt (si)) != GIMPLE_SWITCH); + + /* Never build an assert comparing against an integer constant with + TREE_OVERFLOW set. This confuses our undefined overflow warning + machinery. */ + if (TREE_OVERFLOW_P (val)) + val = drop_tree_overflow (val); + + /* The new assertion A will be inserted at BB or E. We need to + determine if the new location is dominated by a previously + registered location for A. If we are doing an edge insertion, + assume that A will be inserted at E->DEST. Note that this is not + necessarily true. + + If E is a critical edge, it will be split. But even if E is + split, the new block will dominate the same set of blocks that + E->DEST dominates. + + The reverse, however, is not true, blocks dominated by E->DEST + will not be dominated by the new block created to split E. So, + if the insertion location is on a critical edge, we will not use + the new location to move another assertion previously registered + at a block dominated by E->DEST. */ + dest_bb = (bb) ? bb : e->dest; + + /* If NAME already has an ASSERT_EXPR registered for COMP_CODE and + VAL at a block dominating DEST_BB, then we don't need to insert a new + one. Similarly, if the same assertion already exists at a block + dominated by DEST_BB and the new location is not on a critical + edge, then update the existing location for the assertion (i.e., + move the assertion up in the dominance tree). + + Note, this is implemented as a simple linked list because there + should not be more than a handful of assertions registered per + name. If this becomes a performance problem, a table hashed by + COMP_CODE and VAL could be implemented. */ + loc = asserts_for[SSA_NAME_VERSION (name)]; + last_loc = loc; + while (loc) + { + if (loc->comp_code == comp_code + && (loc->val == val + || operand_equal_p (loc->val, val, 0)) + && (loc->expr == expr + || operand_equal_p (loc->expr, expr, 0))) + { + /* If E is not a critical edge and DEST_BB + dominates the existing location for the assertion, move + the assertion up in the dominance tree by updating its + location information. */ + if ((e == NULL || !EDGE_CRITICAL_P (e)) + && dominated_by_p (CDI_DOMINATORS, loc->bb, dest_bb)) + { + loc->bb = dest_bb; + loc->e = e; + loc->si = si; + return; + } + } + + /* Update the last node of the list and move to the next one. */ + last_loc = loc; + loc = loc->next; + } + + /* If we didn't find an assertion already registered for + NAME COMP_CODE VAL, add a new one at the end of the list of + assertions associated with NAME. */ + n = XNEW (struct assert_locus); + n->bb = dest_bb; + n->e = e; + n->si = si; + n->comp_code = comp_code; + n->val = val; + n->expr = expr; + n->next = NULL; + + if (last_loc) + last_loc->next = n; + else + asserts_for[SSA_NAME_VERSION (name)] = n; + + bitmap_set_bit (need_assert_for, SSA_NAME_VERSION (name)); +} + +/* Finish found ASSERTS for E and register them at GSI. */ + +void +vrp_asserts::finish_register_edge_assert_for (edge e, + gimple_stmt_iterator gsi, + vec &asserts) +{ + for (unsigned i = 0; i < asserts.length (); ++i) + /* Only register an ASSERT_EXPR if NAME was found in the sub-graph + reachable from E. */ + if (live.live_on_edge_p (asserts[i].name, e)) + register_new_assert_for (asserts[i].name, asserts[i].expr, + asserts[i].comp_code, asserts[i].val, + NULL, e, gsi); +} + +/* Determine whether the outgoing edges of BB should receive an + ASSERT_EXPR for each of the operands of BB's LAST statement. + The last statement of BB must be a COND_EXPR. + + If any of the sub-graphs rooted at BB have an interesting use of + the predicate operands, an assert location node is added to the + list of assertions for the corresponding operands. */ + +void +vrp_asserts::find_conditional_asserts (basic_block bb, gcond *last) +{ + gimple_stmt_iterator bsi; + tree op; + edge_iterator ei; + edge e; + ssa_op_iter iter; + + bsi = gsi_for_stmt (last); + + /* Look for uses of the operands in each of the sub-graphs + rooted at BB. We need to check each of the outgoing edges + separately, so that we know what kind of ASSERT_EXPR to + insert. */ + FOR_EACH_EDGE (e, ei, bb->succs) + { + if (e->dest == bb) + continue; + + /* Register the necessary assertions for each operand in the + conditional predicate. */ + auto_vec asserts; + FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE) + register_edge_assert_for (op, e, + gimple_cond_code (last), + gimple_cond_lhs (last), + gimple_cond_rhs (last), asserts); + finish_register_edge_assert_for (e, bsi, asserts); + } +} + +/* Compare two case labels sorting first by the destination bb index + and then by the case value. */ + +int +vrp_asserts::compare_case_labels (const void *p1, const void *p2) +{ + const struct case_info *ci1 = (const struct case_info *) p1; + const struct case_info *ci2 = (const struct case_info *) p2; + int idx1 = ci1->bb->index; + int idx2 = ci2->bb->index; + + if (idx1 < idx2) + return -1; + else if (idx1 == idx2) + { + /* Make sure the default label is first in a group. */ + if (!CASE_LOW (ci1->expr)) + return -1; + else if (!CASE_LOW (ci2->expr)) + return 1; + else + return tree_int_cst_compare (CASE_LOW (ci1->expr), + CASE_LOW (ci2->expr)); + } + else return 1; } @@ -2678,7 +2982,7 @@ compare_case_labels (const void *p1, const void *p2) list of assertions for the corresponding operands. */ void -vrp_insert::find_switch_asserts (basic_block bb, gswitch *last) +vrp_asserts::find_switch_asserts (basic_block bb, gswitch *last) { gimple_stmt_iterator bsi; tree op; @@ -2827,7 +3131,6 @@ vrp_insert::find_switch_asserts (basic_block bb, gswitch *last) } } - /* Traverse all the statements in block BB looking for statements that may generate useful assertions for the SSA names in their operand. If a statement produces a useful assertion A for name N_i, then the @@ -2888,7 +3191,7 @@ vrp_insert::find_switch_asserts (basic_block bb, gswitch *last) P_4 will receive an ASSERT_EXPR. */ void -vrp_insert::find_assert_locations_in_bb (basic_block bb) +vrp_asserts::find_assert_locations_in_bb (basic_block bb) { gimple *last; @@ -3008,7 +3311,7 @@ vrp_insert::find_assert_locations_in_bb (basic_block bb) on-the-fly and deciding on assert expressions to insert. */ void -vrp_insert::find_assert_locations (void) +vrp_asserts::find_assert_locations (void) { int *rpo = XNEWVEC (int, last_basic_block_for_fn (fun)); int *bb_rpo = XNEWVEC (int, last_basic_block_for_fn (fun)); @@ -3088,7 +3391,7 @@ vrp_insert::find_assert_locations (void) indicated by LOC. Return true if we made any edge insertions. */ bool -vrp_insert::process_assert_insertions_for (tree name, assert_locus *loc) +vrp_asserts::process_assert_insertions_for (tree name, assert_locus *loc) { /* Build the comparison expression NAME_i COMP_CODE VAL. */ gimple *stmt; @@ -3153,7 +3456,7 @@ vrp_insert::process_assert_insertions_for (tree name, assert_locus *loc) template int -vrp_insert::compare_assert_loc (const void *pa, const void *pb) +vrp_asserts::compare_assert_loc (const void *pa, const void *pb) { assert_locus * const a = *(assert_locus * const *)pa; assert_locus * const b = *(assert_locus * const *)pb; @@ -3221,7 +3524,7 @@ vrp_insert::compare_assert_loc (const void *pa, const void *pb) found in ASSERTS_FOR[i]. */ void -vrp_insert::process_assert_insertions () +vrp_asserts::process_assert_insertions () { unsigned i; bitmap_iterator bi; @@ -3314,7 +3617,6 @@ vrp_insert::process_assert_insertions () num_asserts); } - /* Traverse the flowgraph looking for conditional jumps to insert range expressions. These range expressions are meant to provide information to optimizations that need to reason in terms of value ranges. They @@ -3348,7 +3650,7 @@ vrp_insert::process_assert_insertions () definition of 'x'. */ void -vrp_insert::insert_range_assertions (void) +vrp_asserts::insert_range_assertions (void) { need_assert_for = BITMAP_ALLOC (NULL); asserts_for = XCNEWVEC (assert_locus *, num_ssa_names); @@ -3372,117 +3674,34 @@ vrp_insert::insert_range_assertions (void) BITMAP_FREE (need_assert_for); } -class vrp_prop : public ssa_propagation_engine -{ -public: - enum ssa_prop_result visit_stmt (gimple *, edge *, tree *) FINAL OVERRIDE; - enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE; - - struct function *fun; - - void vrp_initialize (struct function *); - void vrp_finalize (class vrp_folder *, bool); - - class vr_values vr_values; - -private: - /* Temporary delegator to minimize code churn. */ - const value_range_equiv *get_value_range (const_tree op) - { return vr_values.get_value_range (op); } - void set_def_to_varying (const_tree def) - { vr_values.set_def_to_varying (def); } - void set_defs_to_varying (gimple *stmt) - { vr_values.set_defs_to_varying (stmt); } - void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p, - tree *output_p, value_range_equiv *vr) - { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); } - bool update_value_range (const_tree op, value_range_equiv *vr) - { return vr_values.update_value_range (op, vr); } - void extract_range_basic (value_range_equiv *vr, gimple *stmt) - { vr_values.extract_range_basic (vr, stmt); } - void extract_range_from_phi_node (gphi *phi, value_range_equiv *vr) - { vr_values.extract_range_from_phi_node (phi, vr); } -}; - /* Return true if all imm uses of VAR are either in STMT, or feed (optionally through a chain of single imm uses) GIMPLE_COND in basic block COND_BB. */ - -static bool -all_imm_uses_in_stmt_or_feed_cond (tree var, gimple *stmt, basic_block cond_bb) -{ - use_operand_p use_p, use2_p; - imm_use_iterator iter; - - FOR_EACH_IMM_USE_FAST (use_p, iter, var) - if (USE_STMT (use_p) != stmt) - { - gimple *use_stmt = USE_STMT (use_p), *use_stmt2; - if (is_gimple_debug (use_stmt)) - continue; - while (is_gimple_assign (use_stmt) - && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME - && single_imm_use (gimple_assign_lhs (use_stmt), - &use2_p, &use_stmt2)) - use_stmt = use_stmt2; - if (gimple_code (use_stmt) != GIMPLE_COND - || gimple_bb (use_stmt) != cond_bb) - return false; - } - return true; -} - -/* Handle - _4 = x_3 & 31; - if (_4 != 0) - goto ; - else - goto ; - : - __builtin_unreachable (); - : - x_5 = ASSERT_EXPR ; - If x_3 has no other immediate uses (checked by caller), - var is the x_3 var from ASSERT_EXPR, we can clear low 5 bits - from the non-zero bitmask. */ - -void -maybe_set_nonzero_bits (edge e, tree var) -{ - basic_block cond_bb = e->src; - gimple *stmt = last_stmt (cond_bb); - tree cst; - - if (stmt == NULL - || gimple_code (stmt) != GIMPLE_COND - || gimple_cond_code (stmt) != ((e->flags & EDGE_TRUE_VALUE) - ? EQ_EXPR : NE_EXPR) - || TREE_CODE (gimple_cond_lhs (stmt)) != SSA_NAME - || !integer_zerop (gimple_cond_rhs (stmt))) - return; - - stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt)); - if (!is_gimple_assign (stmt) - || gimple_assign_rhs_code (stmt) != BIT_AND_EXPR - || TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST) - return; - if (gimple_assign_rhs1 (stmt) != var) - { - gimple *stmt2; - - if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME) - return; - stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)); - if (!gimple_assign_cast_p (stmt2) - || gimple_assign_rhs1 (stmt2) != var - || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt2)) - || (TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt))) - != TYPE_PRECISION (TREE_TYPE (var)))) - return; - } - cst = gimple_assign_rhs2 (stmt); - set_nonzero_bits (var, wi::bit_and_not (get_nonzero_bits (var), - wi::to_wide (cst))); + +bool +vrp_asserts::all_imm_uses_in_stmt_or_feed_cond (tree var, + gimple *stmt, + basic_block cond_bb) +{ + use_operand_p use_p, use2_p; + imm_use_iterator iter; + + FOR_EACH_IMM_USE_FAST (use_p, iter, var) + if (USE_STMT (use_p) != stmt) + { + gimple *use_stmt = USE_STMT (use_p), *use_stmt2; + if (is_gimple_debug (use_stmt)) + continue; + while (is_gimple_assign (use_stmt) + && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME + && single_imm_use (gimple_assign_lhs (use_stmt), + &use2_p, &use_stmt2)) + use_stmt = use_stmt2; + if (gimple_code (use_stmt) != GIMPLE_COND + || gimple_bb (use_stmt) != cond_bb) + return false; + } + return true; } /* Convert range assertion expressions into the implied copies and @@ -3510,7 +3729,7 @@ maybe_set_nonzero_bits (edge e, tree var) multiple ranges to be associated with one SSA_NAME. */ void -vrp_insert::remove_range_assertions () +vrp_asserts::remove_range_assertions () { basic_block bb; gimple_stmt_iterator si; @@ -3595,270 +3814,163 @@ vrp_insert::remove_range_assertions () } } -/* Return true if STMT is interesting for VRP. */ - -bool -stmt_interesting_for_vrp (gimple *stmt) -{ - if (gimple_code (stmt) == GIMPLE_PHI) - { - tree res = gimple_phi_result (stmt); - return (!virtual_operand_p (res) - && (INTEGRAL_TYPE_P (TREE_TYPE (res)) - || POINTER_TYPE_P (TREE_TYPE (res)))); - } - else if (is_gimple_assign (stmt) || is_gimple_call (stmt)) - { - tree lhs = gimple_get_lhs (stmt); - - /* In general, assignments with virtual operands are not useful - for deriving ranges, with the obvious exception of calls to - builtin functions. */ - if (lhs && TREE_CODE (lhs) == SSA_NAME - && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) - || POINTER_TYPE_P (TREE_TYPE (lhs))) - && (is_gimple_call (stmt) - || !gimple_vuse (stmt))) - return true; - else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt)) - switch (gimple_call_internal_fn (stmt)) - { - case IFN_ADD_OVERFLOW: - case IFN_SUB_OVERFLOW: - case IFN_MUL_OVERFLOW: - case IFN_ATOMIC_COMPARE_EXCHANGE: - /* These internal calls return _Complex integer type, - but are interesting to VRP nevertheless. */ - if (lhs && TREE_CODE (lhs) == SSA_NAME) - return true; - break; - default: - break; - } - } - else if (gimple_code (stmt) == GIMPLE_COND - || gimple_code (stmt) == GIMPLE_SWITCH) - return true; - - return false; -} - -/* Initialization required by ssa_propagate engine. */ - -void -vrp_prop::vrp_initialize (struct function *fn) +class vrp_folder : public substitute_and_fold_engine { - basic_block bb; - fun = fn; + public: + vrp_folder (vr_values *v) + : substitute_and_fold_engine (/* Fold all stmts. */ true), + m_vr_values (v), simplifier (v) + { } + bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; - FOR_EACH_BB_FN (bb, fun) + tree value_of_expr (tree name, gimple *stmt) OVERRIDE { - for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); - gsi_next (&si)) - { - gphi *phi = si.phi (); - if (!stmt_interesting_for_vrp (phi)) - { - tree lhs = PHI_RESULT (phi); - set_def_to_varying (lhs); - prop_set_simulate_again (phi, false); - } - else - prop_set_simulate_again (phi, true); - } - - for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); - gsi_next (&si)) - { - gimple *stmt = gsi_stmt (si); - - /* If the statement is a control insn, then we do not - want to avoid simulating the statement once. Failure - to do so means that those edges will never get added. */ - if (stmt_ends_bb_p (stmt)) - prop_set_simulate_again (stmt, true); - else if (!stmt_interesting_for_vrp (stmt)) - { - set_defs_to_varying (stmt); - prop_set_simulate_again (stmt, false); - } - else - prop_set_simulate_again (stmt, true); - } + return m_vr_values->value_of_expr (name, stmt); } -} - -/* Searches the case label vector VEC for the index *IDX of the CASE_LABEL - that includes the value VAL. The search is restricted to the range - [START_IDX, n - 1] where n is the size of VEC. - - If there is a CASE_LABEL for VAL, its index is placed in IDX and true is - returned. - - If there is no CASE_LABEL for VAL and there is one that is larger than VAL, - it is placed in IDX and false is returned. - - If VAL is larger than any CASE_LABEL, n is placed on IDX and false is - returned. */ - -bool -find_case_label_index (gswitch *stmt, size_t start_idx, tree val, size_t *idx) -{ - size_t n = gimple_switch_num_labels (stmt); - size_t low, high; - - /* Find case label for minimum of the value range or the next one. - At each iteration we are searching in [low, high - 1]. */ - - for (low = start_idx, high = n; high != low; ) - { - tree t; - int cmp; - /* Note that i != high, so we never ask for n. */ - size_t i = (high + low) / 2; - t = gimple_switch_label (stmt, i); - - /* Cache the result of comparing CASE_LOW and val. */ - cmp = tree_int_cst_compare (CASE_LOW (t), val); + class vr_values *m_vr_values; - if (cmp == 0) - { - /* Ranges cannot be empty. */ - *idx = i; - return true; - } - else if (cmp > 0) - high = i; - else - { - low = i + 1; - if (CASE_HIGH (t) != NULL - && tree_int_cst_compare (CASE_HIGH (t), val) >= 0) - { - *idx = i; - return true; - } - } - } +private: + bool fold_predicate_in (gimple_stmt_iterator *); + /* Delegators. */ + tree vrp_evaluate_conditional (tree_code code, tree op0, + tree op1, gimple *stmt) + { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); } + bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) + { return simplifier.simplify (gsi); } - *idx = high; - return false; -} + simplify_using_ranges simplifier; +}; -/* Searches the case label vector VEC for the range of CASE_LABELs that is used - for values between MIN and MAX. The first index is placed in MIN_IDX. The - last index is placed in MAX_IDX. If the range of CASE_LABELs is empty - then MAX_IDX < MIN_IDX. - Returns true if the default label is not needed. */ +/* If the statement pointed by SI has a predicate whose value can be + computed using the value range information computed by VRP, compute + its value and return true. Otherwise, return false. */ bool -find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx, - size_t *max_idx) +vrp_folder::fold_predicate_in (gimple_stmt_iterator *si) { - size_t i, j; - bool min_take_default = !find_case_label_index (stmt, 1, min, &i); - bool max_take_default = !find_case_label_index (stmt, i, max, &j); + bool assignment_p = false; + tree val; + gimple *stmt = gsi_stmt (*si); - if (i == j - && min_take_default - && max_take_default) + if (is_gimple_assign (stmt) + && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) { - /* Only the default case label reached. - Return an empty range. */ - *min_idx = 1; - *max_idx = 0; - return false; + assignment_p = true; + val = vrp_evaluate_conditional (gimple_assign_rhs_code (stmt), + gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt), + stmt); } + else if (gcond *cond_stmt = dyn_cast (stmt)) + val = vrp_evaluate_conditional (gimple_cond_code (cond_stmt), + gimple_cond_lhs (cond_stmt), + gimple_cond_rhs (cond_stmt), + stmt); else + return false; + + if (val) { - bool take_default = min_take_default || max_take_default; - tree low, high; - size_t k; + if (assignment_p) + val = fold_convert (gimple_expr_type (stmt), val); - if (max_take_default) - j--; + if (dump_file) + { + fprintf (dump_file, "Folding predicate "); + print_gimple_expr (dump_file, stmt, 0); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, val); + fprintf (dump_file, "\n"); + } - /* If the case label range is continuous, we do not need - the default case label. Verify that. */ - high = CASE_LOW (gimple_switch_label (stmt, i)); - if (CASE_HIGH (gimple_switch_label (stmt, i))) - high = CASE_HIGH (gimple_switch_label (stmt, i)); - for (k = i + 1; k <= j; ++k) + if (is_gimple_assign (stmt)) + gimple_assign_set_rhs_from_tree (si, val); + else { - low = CASE_LOW (gimple_switch_label (stmt, k)); - if (!integer_onep (int_const_binop (MINUS_EXPR, low, high))) - { - take_default = true; - break; - } - high = low; - if (CASE_HIGH (gimple_switch_label (stmt, k))) - high = CASE_HIGH (gimple_switch_label (stmt, k)); + gcc_assert (gimple_code (stmt) == GIMPLE_COND); + gcond *cond_stmt = as_a (stmt); + if (integer_zerop (val)) + gimple_cond_make_false (cond_stmt); + else if (integer_onep (val)) + gimple_cond_make_true (cond_stmt); + else + gcc_unreachable (); } - *min_idx = i; - *max_idx = j; - return !take_default; + return true; } + + return false; } -/* Given a SWITCH_STMT, return the case label that encompasses the - known possible values for the switch operand. RANGE_OF_OP is a - range for the known values of the switch operand. */ +/* Callback for substitute_and_fold folding the stmt at *SI. */ -tree -find_case_label_range (gswitch *switch_stmt, const irange *range_of_op) +bool +vrp_folder::fold_stmt (gimple_stmt_iterator *si) { - if (range_of_op->undefined_p () - || range_of_op->varying_p () - || range_of_op->symbolic_p ()) - return NULL_TREE; + if (fold_predicate_in (si)) + return true; - size_t i, j; - tree op = gimple_switch_index (switch_stmt); - tree type = TREE_TYPE (op); - tree tmin = wide_int_to_tree (type, range_of_op->lower_bound ()); - tree tmax = wide_int_to_tree (type, range_of_op->upper_bound ()); - find_case_label_range (switch_stmt, tmin, tmax, &i, &j); - if (i == j) - { - /* Look for exactly one label that encompasses the range of - the operand. */ - tree label = gimple_switch_label (switch_stmt, i); - tree case_high - = CASE_HIGH (label) ? CASE_HIGH (label) : CASE_LOW (label); - int_range_max label_range (CASE_LOW (label), case_high); - if (!types_compatible_p (label_range.type (), range_of_op->type ())) - range_cast (label_range, range_of_op->type ()); - label_range.intersect (range_of_op); - if (label_range == *range_of_op) - return label; - } - else if (i > j) - { - /* If there are no labels at all, take the default. */ - return gimple_switch_label (switch_stmt, 0); - } - else + return simplify_stmt_using_ranges (si); +} + +class vrp_prop : public ssa_propagation_engine +{ +public: + enum ssa_prop_result visit_stmt (gimple *, edge *, tree *) FINAL OVERRIDE; + enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE; + + struct function *fun; + + void initialize (struct function *); + void finalize (); + + class vr_values vr_values; +}; + +/* Initialization required by ssa_propagate engine. */ + +void +vrp_prop::initialize (struct function *fn) +{ + basic_block bb; + fun = fn; + + FOR_EACH_BB_FN (bb, fun) { - /* Otherwise, there are various labels that can encompass - the range of operand. In which case, see if the range of - the operand is entirely *outside* the bounds of all the - (non-default) case labels. If so, take the default. */ - unsigned n = gimple_switch_num_labels (switch_stmt); - tree min_label = gimple_switch_label (switch_stmt, 1); - tree max_label = gimple_switch_label (switch_stmt, n - 1); - tree case_high = CASE_HIGH (max_label); - if (!case_high) - case_high = CASE_LOW (max_label); - int_range_max label_range (CASE_LOW (min_label), case_high); - if (!types_compatible_p (label_range.type (), range_of_op->type ())) - range_cast (label_range, range_of_op->type ()); - label_range.intersect (range_of_op); - if (label_range.undefined_p ()) - return gimple_switch_label (switch_stmt, 0); + for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); + gsi_next (&si)) + { + gphi *phi = si.phi (); + if (!stmt_interesting_for_vrp (phi)) + { + tree lhs = PHI_RESULT (phi); + vr_values.set_def_to_varying (lhs); + prop_set_simulate_again (phi, false); + } + else + prop_set_simulate_again (phi, true); + } + + for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); + gsi_next (&si)) + { + gimple *stmt = gsi_stmt (si); + + /* If the statement is a control insn, then we do not + want to avoid simulating the statement once. Failure + to do so means that those edges will never get added. */ + if (stmt_ends_bb_p (stmt)) + prop_set_simulate_again (stmt, true); + else if (!stmt_interesting_for_vrp (stmt)) + { + vr_values.set_defs_to_varying (stmt); + prop_set_simulate_again (stmt, false); + } + else + prop_set_simulate_again (stmt, true); + } } - return NULL_TREE; } /* Evaluate statement STMT. If the statement produces a useful range, @@ -3875,11 +3987,11 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) { tree lhs = gimple_get_lhs (stmt); value_range_equiv vr; - extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr); + vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr); if (*output_p) { - if (update_value_range (*output_p, &vr)) + if (vr_values.update_value_range (*output_p, &vr)) { if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -3914,7 +4026,7 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) use_operand_p use_p; enum ssa_prop_result res = SSA_PROP_VARYING; - set_def_to_varying (lhs); + vr_values.set_def_to_varying (lhs); FOR_EACH_IMM_USE_FAST (use_p, iter, lhs) { @@ -3944,8 +4056,9 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) {REAL,IMAG}PART_EXPR uses at all, return SSA_PROP_VARYING. */ value_range_equiv new_vr; - extract_range_basic (&new_vr, use_stmt); - const value_range_equiv *old_vr = get_value_range (use_lhs); + vr_values.extract_range_basic (&new_vr, use_stmt); + const value_range_equiv *old_vr + = vr_values.get_value_range (use_lhs); if (!old_vr->equal_p (new_vr, /*ignore_equivs=*/false)) res = SSA_PROP_INTERESTING; else @@ -3963,248 +4076,88 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) break; default: break; - } - - /* All other statements produce nothing of interest for VRP, so mark - their outputs varying and prevent further simulation. */ - set_defs_to_varying (stmt); - - return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING; -} - -/* Visit all arguments for PHI node PHI that flow through executable - edges. If a valid value range can be derived from all the incoming - value ranges, set a new range for the LHS of PHI. */ - -enum ssa_prop_result -vrp_prop::visit_phi (gphi *phi) -{ - tree lhs = PHI_RESULT (phi); - value_range_equiv vr_result; - extract_range_from_phi_node (phi, &vr_result); - if (update_value_range (lhs, &vr_result)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Found new range for "); - print_generic_expr (dump_file, lhs); - fprintf (dump_file, ": "); - dump_value_range (dump_file, &vr_result); - fprintf (dump_file, "\n"); - } - - if (vr_result.varying_p ()) - return SSA_PROP_VARYING; - - return SSA_PROP_INTERESTING; - } - - /* Nothing changed, don't add outgoing edges. */ - return SSA_PROP_NOT_INTERESTING; -} - -class vrp_folder : public substitute_and_fold_engine -{ - public: - vrp_folder (vr_values *v) - : substitute_and_fold_engine (/* Fold all stmts. */ true), - m_vr_values (v), simplifier (v) - { } - bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; - - tree value_of_expr (tree name, gimple *stmt) OVERRIDE - { - return m_vr_values->value_of_expr (name, stmt); - } - class vr_values *m_vr_values; - -private: - bool fold_predicate_in (gimple_stmt_iterator *); - /* Delegators. */ - tree vrp_evaluate_conditional (tree_code code, tree op0, - tree op1, gimple *stmt) - { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); } - bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) - { return simplifier.simplify (gsi); } - - simplify_using_ranges simplifier; -}; - -/* If the statement pointed by SI has a predicate whose value can be - computed using the value range information computed by VRP, compute - its value and return true. Otherwise, return false. */ - -bool -vrp_folder::fold_predicate_in (gimple_stmt_iterator *si) -{ - bool assignment_p = false; - tree val; - gimple *stmt = gsi_stmt (*si); - - if (is_gimple_assign (stmt) - && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) - { - assignment_p = true; - val = vrp_evaluate_conditional (gimple_assign_rhs_code (stmt), - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - stmt); - } - else if (gcond *cond_stmt = dyn_cast (stmt)) - val = vrp_evaluate_conditional (gimple_cond_code (cond_stmt), - gimple_cond_lhs (cond_stmt), - gimple_cond_rhs (cond_stmt), - stmt); - else - return false; - - if (val) - { - if (assignment_p) - val = fold_convert (gimple_expr_type (stmt), val); - - if (dump_file) - { - fprintf (dump_file, "Folding predicate "); - print_gimple_expr (dump_file, stmt, 0); - fprintf (dump_file, " to "); - print_generic_expr (dump_file, val); - fprintf (dump_file, "\n"); - } - - if (is_gimple_assign (stmt)) - gimple_assign_set_rhs_from_tree (si, val); - else - { - gcc_assert (gimple_code (stmt) == GIMPLE_COND); - gcond *cond_stmt = as_a (stmt); - if (integer_zerop (val)) - gimple_cond_make_false (cond_stmt); - else if (integer_onep (val)) - gimple_cond_make_true (cond_stmt); - else - gcc_unreachable (); - } - - return true; - } - - return false; -} - -/* Callback for substitute_and_fold folding the stmt at *SI. */ - -bool -vrp_folder::fold_stmt (gimple_stmt_iterator *si) -{ - if (fold_predicate_in (si)) - return true; + } - return simplify_stmt_using_ranges (si); + /* All other statements produce nothing of interest for VRP, so mark + their outputs varying and prevent further simulation. */ + vr_values.set_defs_to_varying (stmt); + + return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING; } -/* Return the LHS of any ASSERT_EXPR where OP appears as the first - argument to the ASSERT_EXPR and in which the ASSERT_EXPR dominates - BB. If no such ASSERT_EXPR is found, return OP. */ +/* Visit all arguments for PHI node PHI that flow through executable + edges. If a valid value range can be derived from all the incoming + value ranges, set a new range for the LHS of PHI. */ -static tree -lhs_of_dominating_assert (tree op, basic_block bb, gimple *stmt) +enum ssa_prop_result +vrp_prop::visit_phi (gphi *phi) { - imm_use_iterator imm_iter; - gimple *use_stmt; - use_operand_p use_p; - - if (TREE_CODE (op) == SSA_NAME) + tree lhs = PHI_RESULT (phi); + value_range_equiv vr_result; + vr_values.extract_range_from_phi_node (phi, &vr_result); + if (vr_values.update_value_range (lhs, &vr_result)) { - FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op) + if (dump_file && (dump_flags & TDF_DETAILS)) { - use_stmt = USE_STMT (use_p); - if (use_stmt != stmt - && gimple_assign_single_p (use_stmt) - && TREE_CODE (gimple_assign_rhs1 (use_stmt)) == ASSERT_EXPR - && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == op - && dominated_by_p (CDI_DOMINATORS, bb, gimple_bb (use_stmt))) - return gimple_assign_lhs (use_stmt); + fprintf (dump_file, "Found new range for "); + print_generic_expr (dump_file, lhs); + fprintf (dump_file, ": "); + dump_value_range (dump_file, &vr_result); + fprintf (dump_file, "\n"); } - } - return op; -} -/* A hack. */ -static class vr_values *x_vr_values; + if (vr_result.varying_p ()) + return SSA_PROP_VARYING; -/* A trivial wrapper so that we can present the generic jump threading - code with a simple API for simplifying statements. STMT is the - statement we want to simplify, WITHIN_STMT provides the location - for any overflow warnings. + return SSA_PROP_INTERESTING; + } - ?? This should be cleaned up. There's a virtually identical copy - of this function in tree-ssa-dom.c. */ + /* Nothing changed, don't add outgoing edges. */ + return SSA_PROP_NOT_INTERESTING; +} -static tree -simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt, - class avail_exprs_stack *avail_exprs_stack ATTRIBUTE_UNUSED, - basic_block bb) -{ - /* First see if the conditional is in the hash table. */ - tree cached_lhs = avail_exprs_stack->lookup_avail_expr (stmt, false, true); - if (cached_lhs && is_gimple_min_invariant (cached_lhs)) - return cached_lhs; +/* Traverse all the blocks folding conditionals with known ranges. */ - vr_values *vr_values = x_vr_values; - if (gcond *cond_stmt = dyn_cast (stmt)) - { - tree op0 = gimple_cond_lhs (cond_stmt); - op0 = lhs_of_dominating_assert (op0, bb, stmt); +void +vrp_prop::finalize () +{ + size_t i; - tree op1 = gimple_cond_rhs (cond_stmt); - op1 = lhs_of_dominating_assert (op1, bb, stmt); + /* We have completed propagating through the lattice. */ + vr_values.set_lattice_propagation_complete (); - simplify_using_ranges simplifier (vr_values); - return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt), - op0, op1, within_stmt); + if (dump_file) + { + fprintf (dump_file, "\nValue ranges after VRP:\n\n"); + vr_values.dump_all_value_ranges (dump_file); + fprintf (dump_file, "\n"); } - if (gswitch *switch_stmt = dyn_cast (stmt)) + /* Set value range to non pointer SSA_NAMEs. */ + for (i = 0; i < num_ssa_names; i++) { - tree op = gimple_switch_index (switch_stmt); - if (TREE_CODE (op) != SSA_NAME) - return NULL_TREE; - - op = lhs_of_dominating_assert (op, bb, stmt); + tree name = ssa_name (i); + if (!name) + continue; - const value_range_equiv *vr = vr_values->get_value_range (op); - return find_case_label_range (switch_stmt, vr); - } + const value_range_equiv *vr = vr_values.get_value_range (name); + if (!name || !vr->constant_p ()) + continue; - if (gassign *assign_stmt = dyn_cast (stmt)) - { - tree lhs = gimple_assign_lhs (assign_stmt); - if (TREE_CODE (lhs) == SSA_NAME - && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) - || POINTER_TYPE_P (TREE_TYPE (lhs))) - && stmt_interesting_for_vrp (stmt)) - { - edge dummy_e; - tree dummy_tree; - value_range_equiv new_vr; - vr_values->extract_range_from_stmt (stmt, &dummy_e, - &dummy_tree, &new_vr); - tree singleton; - if (new_vr.singleton_p (&singleton)) - return singleton; - } + if (POINTER_TYPE_P (TREE_TYPE (name)) + && range_includes_zero_p (vr) == 0) + set_ptr_nonnull (name); + else if (!POINTER_TYPE_P (TREE_TYPE (name))) + set_range_info (name, *vr); } - - return NULL_TREE; } -class vrp_dom_walker : public dom_walker +class vrp_jump_threader : public dom_walker { public: - vrp_dom_walker (cdi_direction direction, - class const_and_copies *const_and_copies, - class avail_exprs_stack *avail_exprs_stack) + vrp_jump_threader (cdi_direction direction, + class const_and_copies *const_and_copies, + class avail_exprs_stack *avail_exprs_stack) : dom_walker (direction, REACHABLE_BLOCKS), m_const_and_copies (const_and_copies), m_avail_exprs_stack (avail_exprs_stack), @@ -4216,11 +4169,13 @@ public: class vr_values *vr_values; private: + static tree simplify_stmt (gimple *stmt, gimple *within_stmt, + avail_exprs_stack *, basic_block); + class const_and_copies *m_const_and_copies; class avail_exprs_stack *m_avail_exprs_stack; gcond *m_dummy_cond; - }; /* Called before processing dominator children of BB. We want to look @@ -4231,7 +4186,7 @@ private: to significantly increase the jump threads we discover. */ edge -vrp_dom_walker::before_dom_children (basic_block bb) +vrp_jump_threader::before_dom_children (basic_block bb) { gimple_stmt_iterator gsi; @@ -4263,10 +4218,77 @@ vrp_dom_walker::before_dom_children (basic_block bb) return NULL; } +/* A trivial wrapper so that we can present the generic jump threading + code with a simple API for simplifying statements. STMT is the + statement we want to simplify, WITHIN_STMT provides the location + for any overflow warnings. + + ?? This should be cleaned up. There's a virtually identical copy + of this function in tree-ssa-dom.c. */ + +tree +vrp_jump_threader::simplify_stmt (gimple *stmt, + gimple *within_stmt, + avail_exprs_stack *avail_exprs_stack, + basic_block bb) +{ + /* First see if the conditional is in the hash table. */ + tree cached_lhs = avail_exprs_stack->lookup_avail_expr (stmt, false, true); + if (cached_lhs && is_gimple_min_invariant (cached_lhs)) + return cached_lhs; + + class vr_values *vr_values = x_vr_values; + if (gcond *cond_stmt = dyn_cast (stmt)) + { + tree op0 = gimple_cond_lhs (cond_stmt); + op0 = lhs_of_dominating_assert (op0, bb, stmt); + + tree op1 = gimple_cond_rhs (cond_stmt); + op1 = lhs_of_dominating_assert (op1, bb, stmt); + + simplify_using_ranges simplifier (vr_values); + return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt), + op0, op1, within_stmt); + } + + if (gswitch *switch_stmt = dyn_cast (stmt)) + { + tree op = gimple_switch_index (switch_stmt); + if (TREE_CODE (op) != SSA_NAME) + return NULL_TREE; + + op = lhs_of_dominating_assert (op, bb, stmt); + + const value_range_equiv *vr = vr_values->get_value_range (op); + return find_case_label_range (switch_stmt, vr); + } + + if (gassign *assign_stmt = dyn_cast (stmt)) + { + tree lhs = gimple_assign_lhs (assign_stmt); + if (TREE_CODE (lhs) == SSA_NAME + && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs))) + && stmt_interesting_for_vrp (stmt)) + { + edge dummy_e; + tree dummy_tree; + value_range_equiv new_vr; + vr_values->extract_range_from_stmt (stmt, &dummy_e, + &dummy_tree, &new_vr); + tree singleton; + if (new_vr.singleton_p (&singleton)) + return singleton; + } + } + + return NULL_TREE; +} + /* Called after processing dominator children of BB. This is where we actually call into the threader. */ void -vrp_dom_walker::after_dom_children (basic_block bb) +vrp_jump_threader::after_dom_children (basic_block bb) { if (!m_dummy_cond) m_dummy_cond = gimple_build_cond (NE_EXPR, @@ -4276,7 +4298,7 @@ vrp_dom_walker::after_dom_children (basic_block bb) x_vr_values = vr_values; thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies, m_avail_exprs_stack, NULL, - simplify_stmt_for_jump_threading); + simplify_stmt); x_vr_values = NULL; m_avail_exprs_stack->pop_to_marker (); @@ -4327,7 +4349,7 @@ identify_jump_threads (struct function *fun, class vr_values *vr_values) avail_exprs_stack *avail_exprs_stack = new class avail_exprs_stack (avail_exprs); - vrp_dom_walker walker (CDI_DOMINATORS, equiv_stack, avail_exprs_stack); + vrp_jump_threader walker (CDI_DOMINATORS, equiv_stack, avail_exprs_stack); walker.vr_values = vr_values; walker.walk (fun->cfg->x_entry_block_ptr); @@ -4339,62 +4361,6 @@ identify_jump_threads (struct function *fun, class vr_values *vr_values) delete avail_exprs_stack; } -/* Traverse all the blocks folding conditionals with known ranges. */ - -void -vrp_prop::vrp_finalize (vrp_folder *folder, bool warn_array_bounds_p) -{ - size_t i; - - /* We have completed propagating through the lattice. */ - vr_values.set_lattice_propagation_complete (); - - if (dump_file) - { - fprintf (dump_file, "\nValue ranges after VRP:\n\n"); - vr_values.dump_all_value_ranges (dump_file); - fprintf (dump_file, "\n"); - } - - /* Set value range to non pointer SSA_NAMEs. */ - for (i = 0; i < num_ssa_names; i++) - { - tree name = ssa_name (i); - if (!name) - continue; - - const value_range_equiv *vr = get_value_range (name); - if (!name || !vr->constant_p ()) - continue; - - if (POINTER_TYPE_P (TREE_TYPE (name)) - && range_includes_zero_p (vr) == 0) - set_ptr_nonnull (name); - else if (!POINTER_TYPE_P (TREE_TYPE (name))) - set_range_info (name, *vr); - } - - /* If we're checking array refs, we want to merge information on - the executability of each edge between vrp_folder and the - check_array_bounds_dom_walker: each can clear the - EDGE_EXECUTABLE flag on edges, in different ways. - - Hence, if we're going to call check_all_array_refs, set - the flag on every edge now, rather than in - check_array_bounds_dom_walker's ctor; vrp_folder may clear - it from some edges. */ - if (warn_array_bounds && warn_array_bounds_p) - set_all_edges_as_executable (fun); - - folder->substitute_and_fold (); - - if (warn_array_bounds && warn_array_bounds_p) - { - array_bounds_checker array_checker (fun, &vr_values); - array_checker.check (); - } -} - /* STMT is a conditional at the end of a basic block. If the conditional is of the form SSA_NAME op constant and the SSA_NAME @@ -4511,7 +4477,7 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) /* ??? This ends up using stale EDGE_DFS_BACK for liveness computation. Inserting assertions may split edges which will invalidate EDGE_DFS_BACK. */ - vrp_insert assert_engine (fun); + vrp_asserts assert_engine (fun); assert_engine.insert_range_assertions (); threadedge_initialize_values (); @@ -4520,12 +4486,33 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) mark_dfs_back_edges (); class vrp_prop vrp_prop; - vrp_prop.vrp_initialize (fun); + vrp_prop.initialize (fun); vrp_prop.ssa_propagate (); + /* Instantiate the folder here, so that edge cleanups happen at the end of this function. */ vrp_folder folder (&vrp_prop.vr_values); - vrp_prop.vrp_finalize (&folder, warn_array_bounds_p); + vrp_prop.finalize (); + + /* If we're checking array refs, we want to merge information on + the executability of each edge between vrp_folder and the + check_array_bounds_dom_walker: each can clear the + EDGE_EXECUTABLE flag on edges, in different ways. + + Hence, if we're going to call check_all_array_refs, set + the flag on every edge now, rather than in + check_array_bounds_dom_walker's ctor; vrp_folder may clear + it from some edges. */ + if (warn_array_bounds && warn_array_bounds_p) + set_all_edges_as_executable (fun); + + folder.substitute_and_fold (); + + if (warn_array_bounds && warn_array_bounds_p) + { + array_bounds_checker array_checker (fun, &vrp_prop.vr_values); + array_checker.check (); + } /* We must identify jump threading opportunities before we release the datastructures built by VRP. */ -- cgit v1.1 From 7cc52bc85e90ed71e67c443f14137f2fcf6adf3c Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 11 Nov 2020 20:10:42 +0100 Subject: Refactor VRP threading code into vrp_jump_threader class. gcc/ChangeLog: * tree-vrp.c (identify_jump_threads): Refactor to.. (vrp_jump_threader::vrp_jump_threader): ...here (vrp_jump_threader::~vrp_jump_threader): ...and here. (vrp_jump_threader::after_dom_children): Rename vr_values to m_vr_values. (execute_vrp): Use vrp_jump_threader. --- gcc/tree-vrp.c | 144 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index d3816ab..6b77c35 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -4152,32 +4152,87 @@ vrp_prop::finalize () } } +/* Blocks which have more than one predecessor and more than + one successor present jump threading opportunities, i.e., + when the block is reached from a specific predecessor, we + may be able to determine which of the outgoing edges will + be traversed. When this optimization applies, we are able + to avoid conditionals at runtime and we may expose secondary + optimization opportunities. + + This class is effectively a driver for the generic jump + threading code. It basically just presents the generic code + with edges that may be suitable for jump threading. + + Unlike DOM, we do not iterate VRP if jump threading was successful. + While iterating may expose new opportunities for VRP, it is expected + those opportunities would be very limited and the compile time cost + to expose those opportunities would be significant. + + As jump threading opportunities are discovered, they are registered + for later realization. */ + class vrp_jump_threader : public dom_walker { public: - vrp_jump_threader (cdi_direction direction, - class const_and_copies *const_and_copies, - class avail_exprs_stack *avail_exprs_stack) - : dom_walker (direction, REACHABLE_BLOCKS), - m_const_and_copies (const_and_copies), - m_avail_exprs_stack (avail_exprs_stack), - m_dummy_cond (NULL) {} - - virtual edge before_dom_children (basic_block); - virtual void after_dom_children (basic_block); + vrp_jump_threader (struct function *, vr_values *); + ~vrp_jump_threader (); - class vr_values *vr_values; + void thread_jumps () + { + walk (m_fun->cfg->x_entry_block_ptr); + } private: static tree simplify_stmt (gimple *stmt, gimple *within_stmt, avail_exprs_stack *, basic_block); + virtual edge before_dom_children (basic_block); + virtual void after_dom_children (basic_block); - class const_and_copies *m_const_and_copies; - class avail_exprs_stack *m_avail_exprs_stack; - + function *m_fun; + vr_values *m_vr_values; + const_and_copies *m_const_and_copies; + avail_exprs_stack *m_avail_exprs_stack; + hash_table *m_avail_exprs; gcond *m_dummy_cond; }; +vrp_jump_threader::vrp_jump_threader (struct function *fun, vr_values *v) + : dom_walker (CDI_DOMINATORS, REACHABLE_BLOCKS) +{ + /* Ugh. When substituting values earlier in this pass we can wipe + the dominance information. So rebuild the dominator information + as we need it within the jump threading code. */ + calculate_dominance_info (CDI_DOMINATORS); + + /* We do not allow VRP information to be used for jump threading + across a back edge in the CFG. Otherwise it becomes too + difficult to avoid eliminating loop exit tests. Of course + EDGE_DFS_BACK is not accurate at this time so we have to + recompute it. */ + mark_dfs_back_edges (); + + /* Allocate our unwinder stack to unwind any temporary equivalences + that might be recorded. */ + m_const_and_copies = new const_and_copies (); + + m_dummy_cond = NULL; + m_fun = fun; + m_vr_values = v; + m_avail_exprs = new hash_table (1024); + m_avail_exprs_stack = new avail_exprs_stack (m_avail_exprs); +} + +vrp_jump_threader::~vrp_jump_threader () +{ + /* We do not actually update the CFG or SSA graphs at this point as + ASSERT_EXPRs are still in the IL and cfg cleanup code does not + yet handle ASSERT_EXPRs gracefully. */ + delete m_const_and_copies; + delete m_avail_exprs; + delete m_avail_exprs_stack; +} + /* Called before processing dominator children of BB. We want to look at ASSERT_EXPRs and record information from them in the appropriate tables. @@ -4295,7 +4350,7 @@ vrp_jump_threader::after_dom_children (basic_block bb) integer_zero_node, integer_zero_node, NULL, NULL); - x_vr_values = vr_values; + x_vr_values = m_vr_values; thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies, m_avail_exprs_stack, NULL, simplify_stmt); @@ -4305,62 +4360,6 @@ vrp_jump_threader::after_dom_children (basic_block bb) m_const_and_copies->pop_to_marker (); } -/* Blocks which have more than one predecessor and more than - one successor present jump threading opportunities, i.e., - when the block is reached from a specific predecessor, we - may be able to determine which of the outgoing edges will - be traversed. When this optimization applies, we are able - to avoid conditionals at runtime and we may expose secondary - optimization opportunities. - - This routine is effectively a driver for the generic jump - threading code. It basically just presents the generic code - with edges that may be suitable for jump threading. - - Unlike DOM, we do not iterate VRP if jump threading was successful. - While iterating may expose new opportunities for VRP, it is expected - those opportunities would be very limited and the compile time cost - to expose those opportunities would be significant. - - As jump threading opportunities are discovered, they are registered - for later realization. */ - -static void -identify_jump_threads (struct function *fun, class vr_values *vr_values) -{ - /* Ugh. When substituting values earlier in this pass we can - wipe the dominance information. So rebuild the dominator - information as we need it within the jump threading code. */ - calculate_dominance_info (CDI_DOMINATORS); - - /* We do not allow VRP information to be used for jump threading - across a back edge in the CFG. Otherwise it becomes too - difficult to avoid eliminating loop exit tests. Of course - EDGE_DFS_BACK is not accurate at this time so we have to - recompute it. */ - mark_dfs_back_edges (); - - /* Allocate our unwinder stack to unwind any temporary equivalences - that might be recorded. */ - const_and_copies *equiv_stack = new const_and_copies (); - - hash_table *avail_exprs - = new hash_table (1024); - avail_exprs_stack *avail_exprs_stack - = new class avail_exprs_stack (avail_exprs); - - vrp_jump_threader walker (CDI_DOMINATORS, equiv_stack, avail_exprs_stack); - walker.vr_values = vr_values; - walker.walk (fun->cfg->x_entry_block_ptr); - - /* We do not actually update the CFG or SSA graphs at this point as - ASSERT_EXPRs are still in the IL and cfg cleanup code does not yet - handle ASSERT_EXPRs gracefully. */ - delete equiv_stack; - delete avail_exprs; - delete avail_exprs_stack; -} - /* STMT is a conditional at the end of a basic block. If the conditional is of the form SSA_NAME op constant and the SSA_NAME @@ -4516,7 +4515,8 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) /* We must identify jump threading opportunities before we release the datastructures built by VRP. */ - identify_jump_threads (fun, &vrp_prop.vr_values); + vrp_jump_threader threader (fun, &vrp_prop.vr_values); + threader.thread_jumps (); /* A comparison of an SSA_NAME against a constant where the SSA_NAME was set by a type conversion can often be rewritten to use the -- cgit v1.1 From 022b99bcba5a3516d4de732f156cbd684c8e812d Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 11 Nov 2020 20:48:34 +0100 Subject: Move vrp_prop before vrp_folder. gcc/ChangeLog: * tree-vrp.c (class vrp_prop): Move entire class... (class vrp_folder): ...before here. --- gcc/tree-vrp.c | 200 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 100 insertions(+), 100 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 6b77c35..15267e3 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -3814,106 +3814,6 @@ vrp_asserts::remove_range_assertions () } } -class vrp_folder : public substitute_and_fold_engine -{ - public: - vrp_folder (vr_values *v) - : substitute_and_fold_engine (/* Fold all stmts. */ true), - m_vr_values (v), simplifier (v) - { } - bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; - - tree value_of_expr (tree name, gimple *stmt) OVERRIDE - { - return m_vr_values->value_of_expr (name, stmt); - } - class vr_values *m_vr_values; - -private: - bool fold_predicate_in (gimple_stmt_iterator *); - /* Delegators. */ - tree vrp_evaluate_conditional (tree_code code, tree op0, - tree op1, gimple *stmt) - { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); } - bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) - { return simplifier.simplify (gsi); } - - simplify_using_ranges simplifier; -}; - -/* If the statement pointed by SI has a predicate whose value can be - computed using the value range information computed by VRP, compute - its value and return true. Otherwise, return false. */ - -bool -vrp_folder::fold_predicate_in (gimple_stmt_iterator *si) -{ - bool assignment_p = false; - tree val; - gimple *stmt = gsi_stmt (*si); - - if (is_gimple_assign (stmt) - && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) - { - assignment_p = true; - val = vrp_evaluate_conditional (gimple_assign_rhs_code (stmt), - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - stmt); - } - else if (gcond *cond_stmt = dyn_cast (stmt)) - val = vrp_evaluate_conditional (gimple_cond_code (cond_stmt), - gimple_cond_lhs (cond_stmt), - gimple_cond_rhs (cond_stmt), - stmt); - else - return false; - - if (val) - { - if (assignment_p) - val = fold_convert (gimple_expr_type (stmt), val); - - if (dump_file) - { - fprintf (dump_file, "Folding predicate "); - print_gimple_expr (dump_file, stmt, 0); - fprintf (dump_file, " to "); - print_generic_expr (dump_file, val); - fprintf (dump_file, "\n"); - } - - if (is_gimple_assign (stmt)) - gimple_assign_set_rhs_from_tree (si, val); - else - { - gcc_assert (gimple_code (stmt) == GIMPLE_COND); - gcond *cond_stmt = as_a (stmt); - if (integer_zerop (val)) - gimple_cond_make_false (cond_stmt); - else if (integer_onep (val)) - gimple_cond_make_true (cond_stmt); - else - gcc_unreachable (); - } - - return true; - } - - return false; -} - -/* Callback for substitute_and_fold folding the stmt at *SI. */ - -bool -vrp_folder::fold_stmt (gimple_stmt_iterator *si) -{ - if (fold_predicate_in (si)) - return true; - - return simplify_stmt_using_ranges (si); -} - class vrp_prop : public ssa_propagation_engine { public: @@ -4152,6 +4052,106 @@ vrp_prop::finalize () } } +class vrp_folder : public substitute_and_fold_engine +{ + public: + vrp_folder (vr_values *v) + : substitute_and_fold_engine (/* Fold all stmts. */ true), + m_vr_values (v), simplifier (v) + { } + bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; + + tree value_of_expr (tree name, gimple *stmt) OVERRIDE + { + return m_vr_values->value_of_expr (name, stmt); + } + class vr_values *m_vr_values; + +private: + bool fold_predicate_in (gimple_stmt_iterator *); + /* Delegators. */ + tree vrp_evaluate_conditional (tree_code code, tree op0, + tree op1, gimple *stmt) + { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); } + bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) + { return simplifier.simplify (gsi); } + + simplify_using_ranges simplifier; +}; + +/* If the statement pointed by SI has a predicate whose value can be + computed using the value range information computed by VRP, compute + its value and return true. Otherwise, return false. */ + +bool +vrp_folder::fold_predicate_in (gimple_stmt_iterator *si) +{ + bool assignment_p = false; + tree val; + gimple *stmt = gsi_stmt (*si); + + if (is_gimple_assign (stmt) + && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) + { + assignment_p = true; + val = vrp_evaluate_conditional (gimple_assign_rhs_code (stmt), + gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt), + stmt); + } + else if (gcond *cond_stmt = dyn_cast (stmt)) + val = vrp_evaluate_conditional (gimple_cond_code (cond_stmt), + gimple_cond_lhs (cond_stmt), + gimple_cond_rhs (cond_stmt), + stmt); + else + return false; + + if (val) + { + if (assignment_p) + val = fold_convert (gimple_expr_type (stmt), val); + + if (dump_file) + { + fprintf (dump_file, "Folding predicate "); + print_gimple_expr (dump_file, stmt, 0); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, val); + fprintf (dump_file, "\n"); + } + + if (is_gimple_assign (stmt)) + gimple_assign_set_rhs_from_tree (si, val); + else + { + gcc_assert (gimple_code (stmt) == GIMPLE_COND); + gcond *cond_stmt = as_a (stmt); + if (integer_zerop (val)) + gimple_cond_make_false (cond_stmt); + else if (integer_onep (val)) + gimple_cond_make_true (cond_stmt); + else + gcc_unreachable (); + } + + return true; + } + + return false; +} + +/* Callback for substitute_and_fold folding the stmt at *SI. */ + +bool +vrp_folder::fold_stmt (gimple_stmt_iterator *si) +{ + if (fold_predicate_in (si)) + return true; + + return simplify_stmt_using_ranges (si); +} + /* Blocks which have more than one predecessor and more than one successor present jump threading opportunities, i.e., when the block is reached from a specific predecessor, we -- cgit v1.1 From 40c4eb67f563ec42e98b30dddacfece562f22fc8 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 11 Nov 2020 21:04:58 +0100 Subject: Move vr_values out of vrp_prop into execute_vrp so it can be shared. vr_values is being shared among the propagator and the folder and passed around. I've pulled it out from the propagator so it can be passed around to each, instead of being publicly accessible from the propagator. gcc/ChangeLog: * tree-vrp.c (class vrp_prop): Rename vr_values to m_vr_values. (vrp_prop::vrp_prop): New. (vrp_prop::initialize): Rename vr_values to m_vr_values. (vrp_prop::visit_stmt): Same. (vrp_prop::visit_phi): Same. (vrp_prop::finalize): Same. (execute_vrp): Instantiate vrp_vr_values and pass it to folder and propagator. --- gcc/tree-vrp.c | 53 +++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 15267e3..81bbaef 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -3817,15 +3817,19 @@ vrp_asserts::remove_range_assertions () class vrp_prop : public ssa_propagation_engine { public: - enum ssa_prop_result visit_stmt (gimple *, edge *, tree *) FINAL OVERRIDE; - enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE; - - struct function *fun; + vrp_prop (vr_values *v) + : ssa_propagation_engine (), + m_vr_values (v) { } void initialize (struct function *); void finalize (); - class vr_values vr_values; + enum ssa_prop_result visit_stmt (gimple *, edge *, tree *) FINAL OVERRIDE; + enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE; + +private: + struct function *fun; + vr_values *m_vr_values; }; /* Initialization required by ssa_propagate engine. */ @@ -3845,7 +3849,7 @@ vrp_prop::initialize (struct function *fn) if (!stmt_interesting_for_vrp (phi)) { tree lhs = PHI_RESULT (phi); - vr_values.set_def_to_varying (lhs); + m_vr_values->set_def_to_varying (lhs); prop_set_simulate_again (phi, false); } else @@ -3864,7 +3868,7 @@ vrp_prop::initialize (struct function *fn) prop_set_simulate_again (stmt, true); else if (!stmt_interesting_for_vrp (stmt)) { - vr_values.set_defs_to_varying (stmt); + m_vr_values->set_defs_to_varying (stmt); prop_set_simulate_again (stmt, false); } else @@ -3887,11 +3891,11 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) { tree lhs = gimple_get_lhs (stmt); value_range_equiv vr; - vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr); + m_vr_values->extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr); if (*output_p) { - if (vr_values.update_value_range (*output_p, &vr)) + if (m_vr_values->update_value_range (*output_p, &vr)) { if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -3926,7 +3930,7 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) use_operand_p use_p; enum ssa_prop_result res = SSA_PROP_VARYING; - vr_values.set_def_to_varying (lhs); + m_vr_values->set_def_to_varying (lhs); FOR_EACH_IMM_USE_FAST (use_p, iter, lhs) { @@ -3956,9 +3960,9 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) {REAL,IMAG}PART_EXPR uses at all, return SSA_PROP_VARYING. */ value_range_equiv new_vr; - vr_values.extract_range_basic (&new_vr, use_stmt); + m_vr_values->extract_range_basic (&new_vr, use_stmt); const value_range_equiv *old_vr - = vr_values.get_value_range (use_lhs); + = m_vr_values->get_value_range (use_lhs); if (!old_vr->equal_p (new_vr, /*ignore_equivs=*/false)) res = SSA_PROP_INTERESTING; else @@ -3980,7 +3984,7 @@ vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p) /* All other statements produce nothing of interest for VRP, so mark their outputs varying and prevent further simulation. */ - vr_values.set_defs_to_varying (stmt); + m_vr_values->set_defs_to_varying (stmt); return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING; } @@ -3994,8 +3998,8 @@ vrp_prop::visit_phi (gphi *phi) { tree lhs = PHI_RESULT (phi); value_range_equiv vr_result; - vr_values.extract_range_from_phi_node (phi, &vr_result); - if (vr_values.update_value_range (lhs, &vr_result)) + m_vr_values->extract_range_from_phi_node (phi, &vr_result); + if (m_vr_values->update_value_range (lhs, &vr_result)) { if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -4024,12 +4028,12 @@ vrp_prop::finalize () size_t i; /* We have completed propagating through the lattice. */ - vr_values.set_lattice_propagation_complete (); + m_vr_values->set_lattice_propagation_complete (); if (dump_file) { fprintf (dump_file, "\nValue ranges after VRP:\n\n"); - vr_values.dump_all_value_ranges (dump_file); + m_vr_values->dump_all_value_ranges (dump_file); fprintf (dump_file, "\n"); } @@ -4040,7 +4044,7 @@ vrp_prop::finalize () if (!name) continue; - const value_range_equiv *vr = vr_values.get_value_range (name); + const value_range_equiv *vr = m_vr_values->get_value_range (name); if (!name || !vr->constant_p ()) continue; @@ -4468,7 +4472,6 @@ vrp_simplify_cond_using_ranges (vr_values *query, gcond *stmt) static unsigned int execute_vrp (struct function *fun, bool warn_array_bounds_p) { - loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); scev_initialize (); @@ -4484,13 +4487,15 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) /* For visiting PHI nodes we need EDGE_DFS_BACK computed. */ mark_dfs_back_edges (); - class vrp_prop vrp_prop; + vr_values vrp_vr_values; + + class vrp_prop vrp_prop (&vrp_vr_values); vrp_prop.initialize (fun); vrp_prop.ssa_propagate (); /* Instantiate the folder here, so that edge cleanups happen at the end of this function. */ - vrp_folder folder (&vrp_prop.vr_values); + vrp_folder folder (&vrp_vr_values); vrp_prop.finalize (); /* If we're checking array refs, we want to merge information on @@ -4509,13 +4514,13 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) if (warn_array_bounds && warn_array_bounds_p) { - array_bounds_checker array_checker (fun, &vrp_prop.vr_values); + array_bounds_checker array_checker (fun, &vrp_vr_values); array_checker.check (); } /* We must identify jump threading opportunities before we release the datastructures built by VRP. */ - vrp_jump_threader threader (fun, &vrp_prop.vr_values); + vrp_jump_threader threader (fun, &vrp_vr_values); threader.thread_jumps (); /* A comparison of an SSA_NAME against a constant where the SSA_NAME @@ -4530,7 +4535,7 @@ execute_vrp (struct function *fun, bool warn_array_bounds_p) { gimple *last = last_stmt (bb); if (last && gimple_code (last) == GIMPLE_COND) - vrp_simplify_cond_using_ranges (&vrp_prop.vr_values, + vrp_simplify_cond_using_ranges (&vrp_vr_values, as_a (last)); } -- cgit v1.1 From 82990836679f1972141a2f93666bd6d39323a435 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 11 Nov 2020 21:09:16 +0100 Subject: Inline delegators in vrp_folder. gcc/ChangeLog: * tree-vrp.c (class vrp_folder): Make visit_stmt, visit_phi, and m_vr_values private. (vrp_folder::vrp_evaluate_conditional): Remove. (vrp_folder::vrp_simplify_stmt_using_ranges): Remove. (vrp_folder::fold_predicate_in): Inline vrp_evaluate_conditional and vrp_simplify_stmt_using_ranges. (vrp_folder::fold_stmt): Same. --- gcc/tree-vrp.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 81bbaef..54ce017 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -3824,10 +3824,10 @@ public: void initialize (struct function *); void finalize (); +private: enum ssa_prop_result visit_stmt (gimple *, edge *, tree *) FINAL OVERRIDE; enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE; -private: struct function *fun; vr_values *m_vr_values; }; @@ -4063,23 +4063,16 @@ class vrp_folder : public substitute_and_fold_engine : substitute_and_fold_engine (/* Fold all stmts. */ true), m_vr_values (v), simplifier (v) { } - bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; +private: tree value_of_expr (tree name, gimple *stmt) OVERRIDE { return m_vr_values->value_of_expr (name, stmt); } - class vr_values *m_vr_values; - -private: + bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; bool fold_predicate_in (gimple_stmt_iterator *); - /* Delegators. */ - tree vrp_evaluate_conditional (tree_code code, tree op0, - tree op1, gimple *stmt) - { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); } - bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) - { return simplifier.simplify (gsi); } + vr_values *m_vr_values; simplify_using_ranges simplifier; }; @@ -4098,16 +4091,16 @@ vrp_folder::fold_predicate_in (gimple_stmt_iterator *si) && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) { assignment_p = true; - val = vrp_evaluate_conditional (gimple_assign_rhs_code (stmt), - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), - stmt); + val = simplifier.vrp_evaluate_conditional (gimple_assign_rhs_code (stmt), + gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt), + stmt); } else if (gcond *cond_stmt = dyn_cast (stmt)) - val = vrp_evaluate_conditional (gimple_cond_code (cond_stmt), - gimple_cond_lhs (cond_stmt), - gimple_cond_rhs (cond_stmt), - stmt); + val = simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt), + gimple_cond_lhs (cond_stmt), + gimple_cond_rhs (cond_stmt), + stmt); else return false; @@ -4153,7 +4146,7 @@ vrp_folder::fold_stmt (gimple_stmt_iterator *si) if (fold_predicate_in (si)) return true; - return simplify_stmt_using_ranges (si); + return simplifier.simplify (si); } /* Blocks which have more than one predecessor and more than -- cgit v1.1 From 4852c3266ec0887316b9fbbb106b8540e3e948d6 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 13 Nov 2020 11:33:22 +0100 Subject: remove almost all users of gimple_expr_code This replaces the old-school gimple_expr_code with more selective functions throughout the compiler, in all cases making the code shorter or more clear. 2020-11-13 Richard Biener * cfgexpand.c (gimple_assign_rhs_to_tree): Use gimple_assign_rhs_class. (expand_gimple_stmt_1): Likewise. * gimplify-me.c (gimple_regimplify_operands): Use gimple_assign_single_p. * ipa-icf-gimple.c (func_checker::compare_gimple_assign): Remove redundant compare. (func_checker::compare_gimple_cond): Use gimple_cond_code. * tree-ssa-tail-merge.c (gimple_equal_p): Likewise. * predict.c (predict_loops): Use gimple_assign_rhs_code. --- gcc/cfgexpand.c | 7 +++---- gcc/gimplify-me.c | 12 ++++-------- gcc/ipa-icf-gimple.c | 10 ++-------- gcc/predict.c | 2 +- gcc/tree-ssa-tail-merge.c | 4 ++-- 5 files changed, 12 insertions(+), 23 deletions(-) (limited to 'gcc') diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index b2d8685..1b7bdbc 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -103,7 +103,7 @@ tree gimple_assign_rhs_to_tree (gimple *stmt) { tree t; - switch (get_gimple_rhs_class (gimple_expr_code (stmt))) + switch (gimple_assign_rhs_class (stmt)) { case GIMPLE_TERNARY_RHS: t = build3 (gimple_assign_rhs_code (stmt), @@ -3741,11 +3741,10 @@ expand_gimple_stmt_1 (gimple *stmt) of binary assigns must be a gimple reg. */ if (TREE_CODE (lhs) != SSA_NAME - || get_gimple_rhs_class (gimple_expr_code (stmt)) - == GIMPLE_SINGLE_RHS) + || gimple_assign_rhs_class (assign_stmt) == GIMPLE_SINGLE_RHS) { tree rhs = gimple_assign_rhs1 (assign_stmt); - gcc_assert (get_gimple_rhs_class (gimple_expr_code (stmt)) + gcc_assert (gimple_assign_rhs_class (assign_stmt) == GIMPLE_SINGLE_RHS); if (gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (rhs) /* Do not put locations on possibly shared trees. */ diff --git a/gcc/gimplify-me.c b/gcc/gimplify-me.c index 47148fb..ee84c8b 100644 --- a/gcc/gimplify-me.c +++ b/gcc/gimplify-me.c @@ -230,10 +230,8 @@ gimple_regimplify_operands (gimple *stmt, gimple_stmt_iterator *gsi_p) if (i == 1 && (is_gimple_call (stmt) || is_gimple_assign (stmt))) gimplify_expr (&op, &pre, NULL, is_gimple_lvalue, fb_lvalue); else if (i == 2 - && is_gimple_assign (stmt) - && num_ops == 2 - && get_gimple_rhs_class (gimple_expr_code (stmt)) - == GIMPLE_SINGLE_RHS) + && gimple_assign_single_p (stmt) + && num_ops == 2) gimplify_expr (&op, &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); @@ -255,10 +253,8 @@ gimple_regimplify_operands (gimple *stmt, gimple_stmt_iterator *gsi_p) { bool need_temp = false; - if (is_gimple_assign (stmt) - && num_ops == 2 - && get_gimple_rhs_class (gimple_expr_code (stmt)) - == GIMPLE_SINGLE_RHS) + if (gimple_assign_single_p (stmt) + && num_ops == 2) gimplify_expr (gimple_assign_rhs1_ptr (stmt), &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index d5423a7..b755d7e 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -610,12 +610,6 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2) tree_code code1, code2; unsigned i; - code1 = gimple_expr_code (s1); - code2 = gimple_expr_code (s2); - - if (code1 != code2) - return false; - code1 = gimple_assign_rhs_code (s1); code2 = gimple_assign_rhs_code (s2); @@ -652,8 +646,8 @@ func_checker::compare_gimple_cond (gimple *s1, gimple *s2) tree t1, t2; tree_code code1, code2; - code1 = gimple_expr_code (s1); - code2 = gimple_expr_code (s2); + code1 = gimple_cond_code (s1); + code2 = gimple_cond_code (s2); if (code1 != code2) return false; diff --git a/gcc/predict.c b/gcc/predict.c index 361c401..3acbb86 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -2204,7 +2204,7 @@ predict_loops (void) { gimple *call_stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (stmt)); if (gimple_code (call_stmt) == GIMPLE_ASSIGN - && gimple_expr_code (call_stmt) == NOP_EXPR + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (call_stmt)) && TREE_CODE (gimple_assign_rhs1 (call_stmt)) == SSA_NAME) call_stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (call_stmt)); if (gimple_call_internal_p (call_stmt, IFN_BUILTIN_EXPECT) diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index 7361e0b..a4879fe 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -1189,8 +1189,8 @@ gimple_equal_p (same_succ *same_succ, gimple *s1, gimple *s2) if (!gimple_operand_equal_value_p (t1, t2)) return false; - code1 = gimple_expr_code (s1); - code2 = gimple_expr_code (s2); + code1 = gimple_cond_code (s1); + code2 = gimple_cond_code (s2); inv_cond = (bitmap_bit_p (same_succ->inverse, bb1->index) != bitmap_bit_p (same_succ->inverse, bb2->index)); if (inv_cond) -- cgit v1.1 From 3fe07cdec8c79bce53ea5aeb8e607df6eb5c8c2c Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 25 Oct 2020 07:49:16 +0000 Subject: C-family, Objective-C [1/3] : Implement Wobjc-root-class [PR77404]. This warning catches the case that the user has left the superclass specification from a class interface. Root classes are, of course, permitted and an attribute is added to mark these so that the diagnostic is suppressed. The warning and attribute spellings have been kept in sync with the language reference implementation (clang). The diagnostic location information present in the objective-c interface and class definitions is relatively poor. This patch adds a location for the class name to the interface and makes use of it in existing warnings. Part 1 is the changes to code and added tests. Many entries in the testsuite make use of root classes so there are a large number of mechanical changes there adding "-Wno-objc-root-class" to the options. The test changes are parts 2 (objective-c) and 3 (objective-c++) in the patch series. gcc/c-family/ChangeLog: PR objc/77404 * c-attribs.c (handle_objc_root_class_attribute): New * c-objc.h (objc_start_class_interface): Add a location value for the position of the class name. * c.opt: Add Wobjc-root-class. * stub-objc.c (objc_start_class_interface): Add a location value for the position of the class name. gcc/c/ChangeLog: PR objc/77404 * c-parser.c (c_parser_objc_class_definition): Pass the location of the class name to the interface declaration. gcc/cp/ChangeLog: PR objc/77404 * parser.c (cp_parser_objc_class_interface): Pass the location of the class name to the interface declaration. gcc/objc/ChangeLog: PR objc/77404 * objc-act.c (objc_start_class_interface): Accept the location of the class name, use it in existing diagnostic. (start_class): Accept obj_root_class type attributes. Warn when the interface for an implementation does not contain a super class (unless the diagnostic is suppressed by the the command line flag or the objc_root_class type attribute). gcc/testsuite/ChangeLog: PR objc/77404 * objc.dg/attributes/root-class-01.m: New test. * objc.dg/root-class-00.m: New test. * obj-c++.dg/attributes/root-class-01.mm: New test. * obj-c++.dg/root-class-00.mm: New test. gcc/ChangeLog: PR objc/77404 * doc/extend.texi: Document the objc_root_class attribute. * doc/invoke.texi: Document -Wobjc-root-class. --- gcc/c-family/c-attribs.c | 19 +++++++++++++++++++ gcc/c-family/c-objc.h | 2 +- gcc/c-family/c.opt | 5 +++++ gcc/c-family/stub-objc.c | 1 + gcc/c/c-parser.c | 3 ++- gcc/cp/parser.c | 3 ++- gcc/doc/extend.texi | 6 ++++++ gcc/doc/invoke.texi | 9 ++++++++- gcc/objc/objc-act.c | 12 ++++++++++-- gcc/testsuite/obj-c++.dg/attributes/root-class-01.mm | 11 +++++++++++ gcc/testsuite/obj-c++.dg/root-class-00.mm | 10 ++++++++++ gcc/testsuite/objc.dg/attributes/root-class-01.m | 11 +++++++++++ gcc/testsuite/objc.dg/root-class-00.m | 10 ++++++++++ 13 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/attributes/root-class-01.mm create mode 100644 gcc/testsuite/obj-c++.dg/root-class-00.mm create mode 100644 gcc/testsuite/objc.dg/attributes/root-class-01.m create mode 100644 gcc/testsuite/objc.dg/root-class-00.m (limited to 'gcc') diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index f168082..24bcd70 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -158,6 +158,7 @@ static tree handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *); static tree handle_copy_attribute (tree *, tree, tree, int, bool *); static tree handle_nsobject_attribute (tree *, tree, tree, int, bool *); +static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -513,6 +514,8 @@ const struct attribute_spec c_common_attribute_table[] = /* Attributes used by Objective-C. */ { "NSObject", 0, 0, true, false, false, false, handle_nsobject_attribute, NULL }, + { "objc_root_class", 0, 0, true, false, false, false, + handle_objc_root_class_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -5163,6 +5166,22 @@ handle_nsobject_attribute (tree *node, tree name, tree args, return NULL_TREE; } +/* Handle a "objc_root_class" attributes; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_objc_root_class_attribute (tree */*node*/, tree name, tree /*args*/, + int /*flags*/, bool *no_add_attrs) +{ + /* This has no meaning outside Objective-C. */ + if (!c_dialect_objc()) + warning (OPT_Wattributes, "%qE is only applicable to Objective-C" + " class interfaces, attribute ignored", name); + + *no_add_attrs = true; + return NULL_TREE; +} + /* Attempt to partially validate a single attribute ATTR as if it were to be applied to an entity OPER. */ diff --git a/gcc/c-family/c-objc.h b/gcc/c-family/c-objc.h index 6e96731..9414aec 100644 --- a/gcc/c-family/c-objc.h +++ b/gcc/c-family/c-objc.h @@ -124,7 +124,7 @@ extern tree objc_get_protocol_qualified_type (tree, tree); extern tree objc_get_class_reference (tree); extern tree objc_get_class_ivars (tree); extern bool objc_detect_field_duplicates (bool); -extern void objc_start_class_interface (tree, tree, tree, tree); +extern void objc_start_class_interface (tree, location_t, tree, tree, tree); extern void objc_start_category_interface (tree, tree, tree, tree); extern void objc_start_protocol (tree, tree, tree); extern void objc_continue_interface (void); diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index fe16357..a008363 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1002,6 +1002,11 @@ Enum(cpp_normalize_level) String(id) Value(normalized_identifier_C) EnumValue Enum(cpp_normalize_level) String(nfc) Value(normalized_C) +Wobjc-root-class +ObjC ObjC++ Var(warn_objc_root_class) Warning Init(1) +Warn if a class interface has no superclass. Root classes may use an attribute +to suppress this warning. + Wold-style-cast C++ ObjC++ Var(warn_old_style_cast) Warning Warn if a C-style cast is used in a program. diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c index 2f53557..26941aa 100644 --- a/gcc/c-family/stub-objc.c +++ b/gcc/c-family/stub-objc.c @@ -137,6 +137,7 @@ objc_set_method_opt (bool ARG_UNUSED (optional)) void objc_start_class_interface (tree ARG_UNUSED (name), + location_t /*name_loc*/, tree ARG_UNUSED (super), tree ARG_UNUSED (protos), tree ARG_UNUSED (attribs)) diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 377914c..f4c4cf7 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10801,6 +10801,7 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes) return; } id1 = c_parser_peek_token (parser)->value; + location_t loc1 = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { @@ -10860,7 +10861,7 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes) tree proto = NULL_TREE; if (c_parser_next_token_is (parser, CPP_LESS)) proto = c_parser_objc_protocol_refs (parser); - objc_start_class_interface (id1, superclass, proto, attributes); + objc_start_class_interface (id1, loc1, superclass, proto, attributes); } else objc_start_class_implementation (id1, superclass); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index efcdce0..6b0447e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -33574,6 +33574,7 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes) bool is_class_extension; cp_lexer_consume_token (parser->lexer); /* Eat '@interface'. */ + location_t nam_loc = cp_lexer_peek_token (parser->lexer)->location; name = cp_parser_identifier (parser); if (name == error_mark_node) { @@ -33593,7 +33594,7 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes) objc_start_category_interface (name, categ, protos, attributes); else { - objc_start_class_interface (name, super, protos, attributes); + objc_start_class_interface (name, nam_loc, super, protos, attributes); /* Handle instance variable declarations, if any. */ cp_parser_objc_class_ivars (parser); objc_continue_interface (); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 420a14b..c353eb4 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8518,6 +8518,12 @@ and caught in another, the class must have default visibility. Otherwise the two shared objects are unable to use the same typeinfo node and exception handling will break. +@item objc_root_class @r{(Objective-C and Objective-C++ only)} +@cindex @code{objc_root_class} type attribute +This attribute marks a class as being a root class, and thus allows +the compiler to elide any warnings about a missing superclass and to +make additional checks for mandatory methods as needed. + @end table To specify multiple attributes, separate them by commas within the diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 69bf1fa..85f7969 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -276,7 +276,7 @@ Objective-C and Objective-C++ Dialects}. -fzero-link @gol -gen-decls @gol -Wassign-intercept -Wno-property-assign-default @gol --Wno-protocol -Wselector @gol +-Wno-protocol -Wobjc-root-class -Wselector @gol -Wstrict-selector-match @gol -Wundeclared-selector} @@ -4348,6 +4348,13 @@ from the superclass. If you use the @option{-Wno-protocol} option, then methods inherited from the superclass are considered to be implemented, and no warning is issued for them. +@item -Wobjc-root-class @r{(Objective-C and Objective-C++ only)} +@opindex Wobjc-root-class +Warn if a class interface lacks a superclass. Most classes will inherit +from @code{NSObject} (or @code{Object}) for example. When declaring +classes intended to be root classes, the warning can be suppressed by +marking their interfaces with @code{__attribute__((objc_root_class))}. + @item -Wselector @r{(Objective-C and Objective-C++ only)} @opindex Wselector @opindex Wno-selector diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index b9ed32d..e410386 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -571,11 +571,11 @@ lookup_protocol_in_reflist (tree rproto_list, tree lproto) } void -objc_start_class_interface (tree klass, tree super_class, +objc_start_class_interface (tree klass, location_t name_loc, tree super_class, tree protos, tree attributes) { if (flag_objc1_only && attributes) - error_at (input_location, "class attributes are not available in Objective-C 1.0"); + error_at (name_loc, "class attributes are not available in Objective-C 1.0"); objc_interface_context = objc_ivar_context @@ -7014,6 +7014,12 @@ start_class (enum tree_code code, tree class_name, tree super_name, CLASS_SUPER_NAME (objc_implementation_context) = CLASS_SUPER_NAME (implementation_template); } + + if (!CLASS_SUPER_NAME (objc_implementation_context) + && !lookup_attribute ("objc_root_class", + TYPE_ATTRIBUTES (implementation_template))) + warning (OPT_Wobjc_root_class, "class %qE defined without" + " specifying a base class", class_name); break; case CLASS_INTERFACE_TYPE: @@ -7044,6 +7050,8 @@ start_class (enum tree_code code, tree class_name, tree super_name, TREE_DEPRECATED (klass) = 1; else if (is_attribute_p ("objc_exception", name)) CLASS_HAS_EXCEPTION_ATTR (klass) = 1; + else if (is_attribute_p ("objc_root_class", name)) + ; else if (is_attribute_p ("visibility", name)) ; else diff --git a/gcc/testsuite/obj-c++.dg/attributes/root-class-01.mm b/gcc/testsuite/obj-c++.dg/attributes/root-class-01.mm new file mode 100644 index 0000000..84da94a --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/root-class-01.mm @@ -0,0 +1,11 @@ +/* Test Wobjc-root-class warning is suppressed by the objc_root_class attr. + Note that we don't issue a warning unless the TU contains an implementation + for the class. This should compile without warning. */ +/* { dg-additional-options "-fsyntax-only " } */ + +__attribute__((objc_root_class)) +@interface ARootObject +@end + +@implementation ARootObject +@end diff --git a/gcc/testsuite/obj-c++.dg/root-class-00.mm b/gcc/testsuite/obj-c++.dg/root-class-00.mm new file mode 100644 index 0000000..f951b0d --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/root-class-00.mm @@ -0,0 +1,10 @@ +/* Test Wobjc-root-class. + Note that we don't issue a warning unless the TU contains an implementation + for the class. */ +/* { dg-additional-options "-fsyntax-only " } */ + +@interface ARootObject +@end + +@implementation ARootObject /* { dg-warning {class 'ARootObject' defined without specifying a base class} } */ +@end diff --git a/gcc/testsuite/objc.dg/attributes/root-class-01.m b/gcc/testsuite/objc.dg/attributes/root-class-01.m new file mode 100644 index 0000000..84da94a --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/root-class-01.m @@ -0,0 +1,11 @@ +/* Test Wobjc-root-class warning is suppressed by the objc_root_class attr. + Note that we don't issue a warning unless the TU contains an implementation + for the class. This should compile without warning. */ +/* { dg-additional-options "-fsyntax-only " } */ + +__attribute__((objc_root_class)) +@interface ARootObject +@end + +@implementation ARootObject +@end diff --git a/gcc/testsuite/objc.dg/root-class-00.m b/gcc/testsuite/objc.dg/root-class-00.m new file mode 100644 index 0000000..1f73f73 --- /dev/null +++ b/gcc/testsuite/objc.dg/root-class-00.m @@ -0,0 +1,10 @@ +/* Test Wobjc-root-class. + Note that we don't issue a warning unless the TU contains an implementation + for the class. */ +/* { dg-additional-options "-fsyntax-only " } */ + +@interface ARootObject +@end + +@implementation ARootObject +@end /* { dg-warning {class 'ARootObject' defined without specifying a base class} } */ -- cgit v1.1 From d35fbf7f7673b5c72ee61720f1a209d4e798152f Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 12 Nov 2020 13:11:11 +0000 Subject: Objective-C [2/3] : Implement Wobjc-root-class [PR77404]. Add "Wno-objc-root-class" to tests in the Objective-C suite where needed. gcc/testsuite/ChangeLog: PR objc/77404 * objc.dg/anon-1.m: Add Wno-objc-root-class. * objc.dg/attributes/class-attribute-1.m: Likewise. * objc.dg/attributes/class-attribute-2.m: Likewise. * objc.dg/attributes/class-attribute-3.m: Likewise. * objc.dg/attributes/method-deprecated-1.m: Likewise. * objc.dg/attributes/method-deprecated-2.m: Likewise. * objc.dg/attributes/method-deprecated-3.m: Likewise. * objc.dg/attributes/method-format-1.m: Likewise. * objc.dg/attributes/method-nonnull-1.m: Likewise. * objc.dg/attributes/method-noreturn-1.m: Likewise. * objc.dg/attributes/method-sentinel-1.m: Likewise. * objc.dg/attributes/nsobject-01.m: Likewise. * objc.dg/attributes/objc-exception-1.m: Likewise. * objc.dg/attributes/parameter-attribute-1.m: Likewise. * objc.dg/attributes/parameter-attribute-2.m: Likewise. * objc.dg/attributes/proto-attribute-1.m: Likewise. * objc.dg/attributes/proto-attribute-2.m: Likewise. * objc.dg/attributes/proto-attribute-3.m: Likewise. * objc.dg/attributes/proto-attribute-4.m: Likewise. * objc.dg/bitfield-2.m: Likewise. * objc.dg/break-in-ifstmt.m: Likewise. * objc.dg/class-1.m: Likewise. * objc.dg/class-extension-1.m: Likewise. * objc.dg/class-extension-2.m: Likewise. * objc.dg/class-extension-3.m: Likewise. * objc.dg/class-extension-4.m: Likewise. * objc.dg/class-protocol-1.m: Likewise. * objc.dg/comp-types-7.m: Likewise. * objc.dg/demangle-1.m: Likewise. * objc.dg/duplicate-class-1.m: Likewise. * objc.dg/encode-6-next.m: Likewise. * objc.dg/encode-6.m: Likewise. * objc.dg/enhanced-proto-2.m: Likewise. * objc.dg/exceptions-1.m: Likewise. * objc.dg/exceptions-3.m: Likewise. * objc.dg/exceptions-4.m: Likewise. * objc.dg/exceptions-5.m: Likewise. * objc.dg/fobjc-std-1.m: Likewise. * objc.dg/foreach-2.m: Likewise. * objc.dg/foreach-4.m: Likewise. * objc.dg/foreach-5.m: Likewise. * objc.dg/fsyntax-only.m: Likewise. * objc.dg/gnu-api-2-class-meta.m: Likewise. * objc.dg/gnu-api-2-class.m: Likewise. * objc.dg/gnu-api-2-ivar.m: Likewise. * objc.dg/gnu-api-2-method.m: Likewise. * objc.dg/gnu-api-2-objc.m: Likewise. * objc.dg/gnu-api-2-objc_msg_lookup.m: Likewise. * objc.dg/gnu-api-2-object.m: Likewise. * objc.dg/gnu-api-2-property.m: Likewise. * objc.dg/gnu-api-2-protocol.m: Likewise. * objc.dg/gnu-api-2-resolve-method.m: Likewise. * objc.dg/gnu-api-2-sel.m: Likewise. * objc.dg/incomplete-type-1.m: Likewise. * objc.dg/instancetype-0.m: Likewise. * objc.dg/invalid-method-2.m: Likewise. * objc.dg/ivar-invalid-type-1.m: Likewise. * objc.dg/ivar-problem-1.m: Likewise. * objc.dg/ivar-scope-1.m: Likewise. * objc.dg/ivar-scope-2.m: Likewise. * objc.dg/ivar-scope-4.m: Likewise. * objc.dg/ivar-visibility-1.m: Likewise. * objc.dg/ivar-visibility-2.m: Likewise. * objc.dg/ivar-visibility-3.m: Likewise. * objc.dg/ivar-visibility-4.m: Likewise. * objc.dg/local-decl-1.m: Likewise. * objc.dg/lto/lto.exp: Likewise. * objc.dg/lto/trivial-1_0.m: Likewise. * objc.dg/method-1.m: Likewise. * objc.dg/method-12.m: Likewise. * objc.dg/method-13.m: Likewise. * objc.dg/method-14.m: Likewise. * objc.dg/missing-proto-3.m: Likewise. * objc.dg/next-runtime-1.m: Likewise. * objc.dg/objc-foreach-1.m: Likewise. * objc.dg/objc-foreach-2.m: Likewise. * objc.dg/objc-foreach-3.m: Likewise. * objc.dg/objc-nofilename-1.m: Likewise. * objc.dg/param-1.m: Likewise. * objc.dg/pch/pch.exp: Likewise. * objc.dg/plugin/diagnostic-test-expressions-1.m: Likewise. * objc.dg/pr23709.m: Likewise. * objc.dg/private-1.m: Likewise. * objc.dg/private-2.m: Likewise. * objc.dg/property/property.exp: Likewise. * objc.dg/proto-hier-1.m: Likewise. * objc.dg/proto-hier-2.m: Likewise. * objc.dg/proto-lossage-1.m: Likewise. * objc.dg/proto-lossage-5.m: Likewise. * objc.dg/proto-qual-1.m: Likewise. * objc.dg/protocol-inheritance-1.m: Likewise. * objc.dg/protocol-inheritance-2.m: Likewise. * objc.dg/protocol-optional-1.m: Likewise. * objc.dg/selector-1.m: Likewise. * objc.dg/selector-2.m: Likewise. * objc.dg/selector-3.m: Likewise. * objc.dg/selector-4.m: Likewise. * objc.dg/shadow-1.m: Likewise. * objc.dg/shadow-2.m: Likewise. * objc.dg/special/load-category-1.m: Likewise. * objc.dg/special/load-category-2.m: Likewise. * objc.dg/special/load-category-3.m: Likewise. * objc.dg/special/special.exp: Likewise. * objc.dg/special/unclaimed-category-1.h: Likewise. * objc.dg/special/unclaimed-category-1.m: Likewise. * objc.dg/stabs-1.m: Likewise. * objc.dg/strings/strings.exp: Likewise. * objc.dg/stubify-1.m: Likewise. * objc.dg/stubify-2.m: Likewise. * objc.dg/super-class-2.m: Likewise. * objc.dg/super-dealloc-1.m: Likewise. * objc.dg/super-dealloc-2.m: Likewise. * objc.dg/sync-3.m: Likewise. * objc.dg/threedotthree-abi-1.m: Likewise. * objc.dg/torture/dg-torture.exp: Likewise. * objc.dg/torture/strings/strings.exp: Likewise. * objc.dg/try-catch-11.m: Likewise. * objc.dg/try-catch-12.m: Likewise. * objc.dg/type-size-2.m: Likewise. * objc.dg/type-size-3.m: Likewise. * objc.dg/type-size-4.m: Likewise. * objc.dg/type-size-5.m: Likewise. * objc.dg/undeclared-selector.m: Likewise. * objc.dg/volatile-1.m: Likewise. --- gcc/testsuite/objc.dg/anon-1.m | 1 + gcc/testsuite/objc.dg/attributes/class-attribute-1.m | 1 + gcc/testsuite/objc.dg/attributes/class-attribute-2.m | 1 + gcc/testsuite/objc.dg/attributes/class-attribute-3.m | 1 + gcc/testsuite/objc.dg/attributes/method-deprecated-1.m | 1 + gcc/testsuite/objc.dg/attributes/method-deprecated-2.m | 1 + gcc/testsuite/objc.dg/attributes/method-deprecated-3.m | 1 + gcc/testsuite/objc.dg/attributes/method-format-1.m | 1 + gcc/testsuite/objc.dg/attributes/method-nonnull-1.m | 1 + gcc/testsuite/objc.dg/attributes/method-noreturn-1.m | 1 + gcc/testsuite/objc.dg/attributes/method-sentinel-1.m | 1 + gcc/testsuite/objc.dg/attributes/nsobject-01.m | 1 + gcc/testsuite/objc.dg/attributes/objc-exception-1.m | 1 + gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m | 1 + gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m | 1 + gcc/testsuite/objc.dg/attributes/proto-attribute-1.m | 1 + gcc/testsuite/objc.dg/attributes/proto-attribute-2.m | 1 + gcc/testsuite/objc.dg/attributes/proto-attribute-3.m | 1 + gcc/testsuite/objc.dg/attributes/proto-attribute-4.m | 1 + gcc/testsuite/objc.dg/bitfield-2.m | 1 + gcc/testsuite/objc.dg/break-in-ifstmt.m | 1 + gcc/testsuite/objc.dg/class-1.m | 4 ++++ gcc/testsuite/objc.dg/class-extension-1.m | 1 + gcc/testsuite/objc.dg/class-extension-2.m | 1 + gcc/testsuite/objc.dg/class-extension-3.m | 1 + gcc/testsuite/objc.dg/class-extension-4.m | 1 + gcc/testsuite/objc.dg/class-protocol-1.m | 1 + gcc/testsuite/objc.dg/comp-types-7.m | 1 + gcc/testsuite/objc.dg/demangle-1.m | 1 + gcc/testsuite/objc.dg/duplicate-class-1.m | 1 + gcc/testsuite/objc.dg/encode-6-next.m | 1 + gcc/testsuite/objc.dg/encode-6.m | 1 + gcc/testsuite/objc.dg/enhanced-proto-2.m | 1 + gcc/testsuite/objc.dg/exceptions-1.m | 1 + gcc/testsuite/objc.dg/exceptions-3.m | 1 + gcc/testsuite/objc.dg/exceptions-4.m | 1 + gcc/testsuite/objc.dg/exceptions-5.m | 1 + gcc/testsuite/objc.dg/fobjc-std-1.m | 5 +++-- gcc/testsuite/objc.dg/foreach-2.m | 1 + gcc/testsuite/objc.dg/foreach-4.m | 1 + gcc/testsuite/objc.dg/foreach-5.m | 1 + gcc/testsuite/objc.dg/fsyntax-only.m | 3 +++ gcc/testsuite/objc.dg/gnu-api-2-class-meta.m | 4 +--- gcc/testsuite/objc.dg/gnu-api-2-class.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-ivar.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-method.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-objc.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-object.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-property.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-protocol.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m | 1 + gcc/testsuite/objc.dg/gnu-api-2-sel.m | 1 + gcc/testsuite/objc.dg/incomplete-type-1.m | 3 +++ gcc/testsuite/objc.dg/instancetype-0.m | 3 +++ gcc/testsuite/objc.dg/invalid-method-2.m | 3 +++ gcc/testsuite/objc.dg/ivar-invalid-type-1.m | 3 +++ gcc/testsuite/objc.dg/ivar-problem-1.m | 6 ++++++ gcc/testsuite/objc.dg/ivar-scope-1.m | 3 +++ gcc/testsuite/objc.dg/ivar-scope-2.m | 3 +++ gcc/testsuite/objc.dg/ivar-scope-4.m | 3 ++- gcc/testsuite/objc.dg/ivar-visibility-1.m | 1 + gcc/testsuite/objc.dg/ivar-visibility-2.m | 2 +- gcc/testsuite/objc.dg/ivar-visibility-3.m | 2 +- gcc/testsuite/objc.dg/ivar-visibility-4.m | 2 +- gcc/testsuite/objc.dg/local-decl-1.m | 1 + gcc/testsuite/objc.dg/lto/lto.exp | 16 ++++++++-------- gcc/testsuite/objc.dg/lto/trivial-1_0.m | 4 ++-- gcc/testsuite/objc.dg/method-1.m | 1 + gcc/testsuite/objc.dg/method-12.m | 1 + gcc/testsuite/objc.dg/method-13.m | 1 + gcc/testsuite/objc.dg/method-14.m | 1 + gcc/testsuite/objc.dg/missing-proto-3.m | 3 ++- gcc/testsuite/objc.dg/next-runtime-1.m | 1 + gcc/testsuite/objc.dg/objc-foreach-1.m | 1 + gcc/testsuite/objc.dg/objc-foreach-2.m | 1 + gcc/testsuite/objc.dg/objc-foreach-3.m | 1 + gcc/testsuite/objc.dg/objc-nofilename-1.m | 1 + gcc/testsuite/objc.dg/param-1.m | 1 + gcc/testsuite/objc.dg/pch/pch.exp | 4 ++-- .../objc.dg/plugin/diagnostic-test-expressions-1.m | 2 +- gcc/testsuite/objc.dg/pr23709.m | 1 + gcc/testsuite/objc.dg/private-1.m | 1 + gcc/testsuite/objc.dg/private-2.m | 1 + gcc/testsuite/objc.dg/property/property.exp | 4 ++-- gcc/testsuite/objc.dg/proto-hier-1.m | 1 + gcc/testsuite/objc.dg/proto-hier-2.m | 1 + gcc/testsuite/objc.dg/proto-lossage-1.m | 1 + gcc/testsuite/objc.dg/proto-lossage-5.m | 1 + gcc/testsuite/objc.dg/proto-qual-1.m | 1 + gcc/testsuite/objc.dg/protocol-inheritance-1.m | 1 + gcc/testsuite/objc.dg/protocol-inheritance-2.m | 1 + gcc/testsuite/objc.dg/protocol-optional-1.m | 1 + gcc/testsuite/objc.dg/selector-1.m | 1 + gcc/testsuite/objc.dg/selector-2.m | 1 + gcc/testsuite/objc.dg/selector-3.m | 1 + gcc/testsuite/objc.dg/selector-4.m | 1 + gcc/testsuite/objc.dg/shadow-1.m | 1 + gcc/testsuite/objc.dg/shadow-2.m | 1 + gcc/testsuite/objc.dg/special/load-category-1.m | 1 + gcc/testsuite/objc.dg/special/load-category-2.m | 1 + gcc/testsuite/objc.dg/special/load-category-3.m | 1 + gcc/testsuite/objc.dg/special/special.exp | 8 ++++++++ gcc/testsuite/objc.dg/special/unclaimed-category-1.h | 1 + gcc/testsuite/objc.dg/special/unclaimed-category-1.m | 1 + gcc/testsuite/objc.dg/stabs-1.m | 1 + gcc/testsuite/objc.dg/strings/strings.exp | 4 ++-- gcc/testsuite/objc.dg/stubify-1.m | 1 + gcc/testsuite/objc.dg/stubify-2.m | 1 + gcc/testsuite/objc.dg/super-class-2.m | 1 + gcc/testsuite/objc.dg/super-dealloc-1.m | 1 + gcc/testsuite/objc.dg/super-dealloc-2.m | 1 + gcc/testsuite/objc.dg/sync-3.m | 1 + gcc/testsuite/objc.dg/threedotthree-abi-1.m | 1 + gcc/testsuite/objc.dg/torture/dg-torture.exp | 4 ++-- gcc/testsuite/objc.dg/torture/strings/strings.exp | 4 ++-- gcc/testsuite/objc.dg/try-catch-11.m | 1 + gcc/testsuite/objc.dg/try-catch-12.m | 1 + gcc/testsuite/objc.dg/type-size-2.m | 1 + gcc/testsuite/objc.dg/type-size-3.m | 1 + gcc/testsuite/objc.dg/type-size-4.m | 1 + gcc/testsuite/objc.dg/type-size-5.m | 1 + gcc/testsuite/objc.dg/undeclared-selector.m | 1 + gcc/testsuite/objc.dg/volatile-1.m | 3 ++- 124 files changed, 171 insertions(+), 32 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/objc.dg/anon-1.m b/gcc/testsuite/objc.dg/anon-1.m index 5f10f7d..5dab3fa 100644 --- a/gcc/testsuite/objc.dg/anon-1.m +++ b/gcc/testsuite/objc.dg/anon-1.m @@ -1,5 +1,6 @@ /* Test for graceful handling of anonymous ivars. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Foo { unsigned char : 1; diff --git a/gcc/testsuite/objc.dg/attributes/class-attribute-1.m b/gcc/testsuite/objc.dg/attributes/class-attribute-1.m index 3444760..93e5d7f 100644 --- a/gcc/testsuite/objc.dg/attributes/class-attribute-1.m +++ b/gcc/testsuite/objc.dg/attributes/class-attribute-1.m @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test deprecate attribute with an @interface declaration. */ diff --git a/gcc/testsuite/objc.dg/attributes/class-attribute-2.m b/gcc/testsuite/objc.dg/attributes/class-attribute-2.m index 2e1bacb..f8137ff 100644 --- a/gcc/testsuite/objc.dg/attributes/class-attribute-2.m +++ b/gcc/testsuite/objc.dg/attributes/class-attribute-2.m @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/class-attribute-3.m b/gcc/testsuite/objc.dg/attributes/class-attribute-3.m index 6cc5d4e..7c3b3b0 100644 --- a/gcc/testsuite/objc.dg/attributes/class-attribute-3.m +++ b/gcc/testsuite/objc.dg/attributes/class-attribute-3.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that you get a warning when an unknown class attribute is ignored. */ diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m index 8343856..68e8373 100644 --- a/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-1.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m index 1e5d87f..8fb0e15 100644 --- a/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-2.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m b/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m index 5c715a2..efa2d34 100644 --- a/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m +++ b/gcc/testsuite/objc.dg/attributes/method-deprecated-3.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/method-format-1.m b/gcc/testsuite/objc.dg/attributes/method-format-1.m index 9ff34f9..d3bb997 100644 --- a/gcc/testsuite/objc.dg/attributes/method-format-1.m +++ b/gcc/testsuite/objc.dg/attributes/method-format-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ /* { dg-options "-Wall" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m b/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m index fe5f885..a3bfd9b 100644 --- a/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m +++ b/gcc/testsuite/objc.dg/attributes/method-nonnull-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , May 2011. */ /* { dg-do compile } */ /* { dg-options "-Wall" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m b/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m index a83048b..413a0be 100644 --- a/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m +++ b/gcc/testsuite/objc.dg/attributes/method-noreturn-1.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m b/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m index e2abb1e..f89c981 100644 --- a/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m +++ b/gcc/testsuite/objc.dg/attributes/method-sentinel-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ /* { dg-options "-Wall" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/attributes/nsobject-01.m b/gcc/testsuite/objc.dg/attributes/nsobject-01.m index 5b56849..1f33150 100644 --- a/gcc/testsuite/objc.dg/attributes/nsobject-01.m +++ b/gcc/testsuite/objc.dg/attributes/nsobject-01.m @@ -1,5 +1,6 @@ /* Test handling of the NSObject attribute. */ /* { dg-additional-options "-fsyntax-only " } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct AnObj * __attribute__ ((NSObject)) AnObjRef; typedef struct AnObj * __attribute__ ((__NSObject__)) AnotherObjRef; diff --git a/gcc/testsuite/objc.dg/attributes/objc-exception-1.m b/gcc/testsuite/objc.dg/attributes/objc-exception-1.m index e7f6f85..19e5ade 100644 --- a/gcc/testsuite/objc.dg/attributes/objc-exception-1.m +++ b/gcc/testsuite/objc.dg/attributes/objc-exception-1.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , February 2011. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that the 'objc_exception' attribute is accepted for @interfaces, but not for anything else. */ diff --git a/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m b/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m index 8263df6..d6ebaf2 100644 --- a/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m +++ b/gcc/testsuite/objc.dg/attributes/parameter-attribute-1.m @@ -1,6 +1,7 @@ /* Test __attribute__((unused)) for an Objective-C method parameter. */ /* { dg-do compile } */ /* { dg-options "-Wunused-parameter" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m b/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m index 99c5a30..637846d 100644 --- a/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m +++ b/gcc/testsuite/objc.dg/attributes/parameter-attribute-2.m @@ -1,5 +1,6 @@ /* Test that we get warnings for unrecognized attributes. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m index a852a7a..03726dc 100644 --- a/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-1.m @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m index b23b81d..6a73d24 100644 --- a/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-2.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test deprecate attribute with a forward declarations of @protocol. */ diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m index 2be286e..ad6d0c8 100644 --- a/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-3.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test deprecate attribute with normal @protocol declarations. */ diff --git a/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m b/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m index 226fd68..8d34ebd 100644 --- a/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m +++ b/gcc/testsuite/objc.dg/attributes/proto-attribute-4.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that you get a warning when an unknown protocol attribute is ignored. */ diff --git a/gcc/testsuite/objc.dg/bitfield-2.m b/gcc/testsuite/objc.dg/bitfield-2.m index 7e8147a..b28c81e 100644 --- a/gcc/testsuite/objc.dg/bitfield-2.m +++ b/gcc/testsuite/objc.dg/bitfield-2.m @@ -4,6 +4,7 @@ /* { dg-options "-fsigned-char" } */ /* { dg-do run { target *-*-darwin* } } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/objc.dg/break-in-ifstmt.m b/gcc/testsuite/objc.dg/break-in-ifstmt.m index 8968494..6176832 100644 --- a/gcc/testsuite/objc.dg/break-in-ifstmt.m +++ b/gcc/testsuite/objc.dg/break-in-ifstmt.m @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface foo - (void) test; diff --git a/gcc/testsuite/objc.dg/class-1.m b/gcc/testsuite/objc.dg/class-1.m index 0504937..64383f2 100644 --- a/gcc/testsuite/objc.dg/class-1.m +++ b/gcc/testsuite/objc.dg/class-1.m @@ -1,5 +1,6 @@ /* Redeclarations of class names. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef int foo; /* { dg-line foo_def } */ @@ -8,6 +9,9 @@ typedef int foo; /* { dg-line foo_def } */ typedef int bar; /* { dg-line bar_def } */ +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface bar @end /* { dg-error "redeclared as different kind of symbol" } */ /* { dg-error "previous declaration of" "" { target *-*-* } bar_def } */ diff --git a/gcc/testsuite/objc.dg/class-extension-1.m b/gcc/testsuite/objc.dg/class-extension-1.m index 5c89a98..9d6658a 100644 --- a/gcc/testsuite/objc.dg/class-extension-1.m +++ b/gcc/testsuite/objc.dg/class-extension-1.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* This test tests the basic of class extensions. */ diff --git a/gcc/testsuite/objc.dg/class-extension-2.m b/gcc/testsuite/objc.dg/class-extension-2.m index 7f55b60..293facb1 100644 --- a/gcc/testsuite/objc.dg/class-extension-2.m +++ b/gcc/testsuite/objc.dg/class-extension-2.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* This test tests class extensions and protocols. */ diff --git a/gcc/testsuite/objc.dg/class-extension-3.m b/gcc/testsuite/objc.dg/class-extension-3.m index 69e5705..51fe5ee 100644 --- a/gcc/testsuite/objc.dg/class-extension-3.m +++ b/gcc/testsuite/objc.dg/class-extension-3.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* This test tests warnings on class extensions. */ diff --git a/gcc/testsuite/objc.dg/class-extension-4.m b/gcc/testsuite/objc.dg/class-extension-4.m index 692a0fc..5d367d4 100644 --- a/gcc/testsuite/objc.dg/class-extension-4.m +++ b/gcc/testsuite/objc.dg/class-extension-4.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* This test tests you can not declare a class extension after the class @implementation. */ diff --git a/gcc/testsuite/objc.dg/class-protocol-1.m b/gcc/testsuite/objc.dg/class-protocol-1.m index 59c8f82..34680c2 100644 --- a/gcc/testsuite/objc.dg/class-protocol-1.m +++ b/gcc/testsuite/objc.dg/class-protocol-1.m @@ -1,6 +1,7 @@ /* Check Class types */ /* Author: David Ayers */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include "../objc-obj-c++-shared/runtime.h" diff --git a/gcc/testsuite/objc.dg/comp-types-7.m b/gcc/testsuite/objc.dg/comp-types-7.m index 526934f..6b796f0 100644 --- a/gcc/testsuite/objc.dg/comp-types-7.m +++ b/gcc/testsuite/objc.dg/comp-types-7.m @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* We used to ICE because we removed the cast to List_linked* in -[ListIndex_linked next]. */ diff --git a/gcc/testsuite/objc.dg/demangle-1.m b/gcc/testsuite/objc.dg/demangle-1.m index 42b79a9..61e79a6 100644 --- a/gcc/testsuite/objc.dg/demangle-1.m +++ b/gcc/testsuite/objc.dg/demangle-1.m @@ -1,6 +1,7 @@ /* Test demangling an Objective-C method. */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/duplicate-class-1.m b/gcc/testsuite/objc.dg/duplicate-class-1.m index 30a18ff..7992ebf 100644 --- a/gcc/testsuite/objc.dg/duplicate-class-1.m +++ b/gcc/testsuite/objc.dg/duplicate-class-1.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that a duplicated @implementation for the same class does not crash the compiler. */ diff --git a/gcc/testsuite/objc.dg/encode-6-next.m b/gcc/testsuite/objc.dg/encode-6-next.m index c3d9226..18ee15d 100644 --- a/gcc/testsuite/objc.dg/encode-6-next.m +++ b/gcc/testsuite/objc.dg/encode-6-next.m @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski */ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ struct Cxx { const struct Cxx *next; diff --git a/gcc/testsuite/objc.dg/encode-6.m b/gcc/testsuite/objc.dg/encode-6.m index 291a41e..9e9e492 100644 --- a/gcc/testsuite/objc.dg/encode-6.m +++ b/gcc/testsuite/objc.dg/encode-6.m @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski */ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ struct Cxx { const struct Cxx *next; diff --git a/gcc/testsuite/objc.dg/enhanced-proto-2.m b/gcc/testsuite/objc.dg/enhanced-proto-2.m index c196b51..ca99445 100644 --- a/gcc/testsuite/objc.dg/enhanced-proto-2.m +++ b/gcc/testsuite/objc.dg/enhanced-proto-2.m @@ -1,5 +1,6 @@ /* Test use of @optional/@required keywords in @protocol class. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @protocol MyProto1 @optional diff --git a/gcc/testsuite/objc.dg/exceptions-1.m b/gcc/testsuite/objc.dg/exceptions-1.m index 0f3b7e8..1e86177 100644 --- a/gcc/testsuite/objc.dg/exceptions-1.m +++ b/gcc/testsuite/objc.dg/exceptions-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* This test checks the syntax @catch (...) which catches any exceptions. At the moment, @catch (...) is identical to @catch (id diff --git a/gcc/testsuite/objc.dg/exceptions-3.m b/gcc/testsuite/objc.dg/exceptions-3.m index 69a6494..bedaf53 100644 --- a/gcc/testsuite/objc.dg/exceptions-3.m +++ b/gcc/testsuite/objc.dg/exceptions-3.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that the compiler is checking the argument of @catch(), and produce errors when invalid types are used. */ diff --git a/gcc/testsuite/objc.dg/exceptions-4.m b/gcc/testsuite/objc.dg/exceptions-4.m index bbdb741..5d77ffa 100644 --- a/gcc/testsuite/objc.dg/exceptions-4.m +++ b/gcc/testsuite/objc.dg/exceptions-4.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test warnings when parsing syntax errors in @catch(). */ diff --git a/gcc/testsuite/objc.dg/exceptions-5.m b/gcc/testsuite/objc.dg/exceptions-5.m index 55ef0f3..31796bc 100644 --- a/gcc/testsuite/objc.dg/exceptions-5.m +++ b/gcc/testsuite/objc.dg/exceptions-5.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that you can use an unnamed argument with @catch. This test is the same as exceptions-3.m, but with no name for @catch arguments. */ diff --git a/gcc/testsuite/objc.dg/fobjc-std-1.m b/gcc/testsuite/objc.dg/fobjc-std-1.m index 9a15b8a..729f65c 100644 --- a/gcc/testsuite/objc.dg/fobjc-std-1.m +++ b/gcc/testsuite/objc.dg/fobjc-std-1.m @@ -1,6 +1,7 @@ /* Test warnings when using -fobjc-std=objc1. */ /* { dg-do compile } */ /* { dg-options "-fobjc-std=objc1" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include @@ -29,8 +30,8 @@ @end __attribute__ ((deprecated)) -@interface MyRootClass2 -{ /* { dg-error "class attributes are not available in Objective.C 1.0" } */ +@interface MyRootClass2 /* { dg-error "class attributes are not available in Objective.C 1.0" } */ +{ Class isa; } @end diff --git a/gcc/testsuite/objc.dg/foreach-2.m b/gcc/testsuite/objc.dg/foreach-2.m index 93bc902..ccce557 100644 --- a/gcc/testsuite/objc.dg/foreach-2.m +++ b/gcc/testsuite/objc.dg/foreach-2.m @@ -6,6 +6,7 @@ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ /* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ /* { dg-additional-sources "../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include "../objc-obj-c++-shared/TestsuiteObject.m" #ifndef __NEXT_RUNTIME__ diff --git a/gcc/testsuite/objc.dg/foreach-4.m b/gcc/testsuite/objc.dg/foreach-4.m index faee73b..2365609 100644 --- a/gcc/testsuite/objc.dg/foreach-4.m +++ b/gcc/testsuite/objc.dg/foreach-4.m @@ -6,6 +6,7 @@ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ /* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ /* { dg-additional-sources "../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #import "../objc-obj-c++-shared/TestsuiteObject.m" #ifndef __NEXT_RUNTIME__ diff --git a/gcc/testsuite/objc.dg/foreach-5.m b/gcc/testsuite/objc.dg/foreach-5.m index dce26fa..1bcb10b 100644 --- a/gcc/testsuite/objc.dg/foreach-5.m +++ b/gcc/testsuite/objc.dg/foreach-5.m @@ -6,6 +6,7 @@ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ /* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ /* { dg-additional-sources "../objc-obj-c++-shared/nsconstantstring-class-impl.m" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #import "../objc-obj-c++-shared/TestsuiteObject.m" #ifndef __NEXT_RUNTIME__ diff --git a/gcc/testsuite/objc.dg/fsyntax-only.m b/gcc/testsuite/objc.dg/fsyntax-only.m index 54a879e..70ea8ac 100644 --- a/gcc/testsuite/objc.dg/fsyntax-only.m +++ b/gcc/testsuite/objc.dg/fsyntax-only.m @@ -2,6 +2,9 @@ /* { dg-do compile } */ /* { dg-options "-fsyntax-only" } */ +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface foo -(void) my_method:(int) i with:(int) j; @end diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m b/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m index 3a85b16..6c1c76a 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m @@ -20,6 +20,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ /* To get the modern GNU Objective-C Runtime API, you include @@ -29,9 +30,6 @@ #include #include -#if __has_attribute(objc_root_class) -__attribute__((objc_root_class)) -#endif @interface MyRootClass { Class isa; } + alloc; diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class.m b/gcc/testsuite/objc.dg/gnu-api-2-class.m index eade0dc..d11dae0 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-class.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-class.m @@ -7,6 +7,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ /* To get the modern GNU Objective-C Runtime API, you include diff --git a/gcc/testsuite/objc.dg/gnu-api-2-ivar.m b/gcc/testsuite/objc.dg/gnu-api-2-ivar.m index 19ac004..072d265 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-ivar.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-ivar.m @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-method.m b/gcc/testsuite/objc.dg/gnu-api-2-method.m index 0c4fe4f..ea1da8d 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-method.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-method.m @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-objc.m b/gcc/testsuite/objc.dg/gnu-api-2-objc.m index 1b4ce8e..e9ec5d7 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-objc.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-objc.m @@ -9,6 +9,7 @@ systems that don't have the V2 APis). XFAILing the run is not useful since it will XPASS on the sub-set that works. */ /* { dg-skip-if "Incompatible" { *-*-darwin* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m b/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m index 5751f3f..d417225 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-objc_msg_lookup.m @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-object.m b/gcc/testsuite/objc.dg/gnu-api-2-object.m index 3d4d444..20c4342 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-object.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-object.m @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-property.m b/gcc/testsuite/objc.dg/gnu-api-2-property.m index 12c0d8b9..0ef4d79 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-property.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-property.m @@ -4,6 +4,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-protocol.m b/gcc/testsuite/objc.dg/gnu-api-2-protocol.m index a34d74c..682adcd 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-protocol.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-protocol.m @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m b/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m index a387709..6eaa3dd 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-resolve-method.m @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/gnu-api-2-sel.m b/gcc/testsuite/objc.dg/gnu-api-2-sel.m index b71fdfa..bc581be 100644 --- a/gcc/testsuite/objc.dg/gnu-api-2-sel.m +++ b/gcc/testsuite/objc.dg/gnu-api-2-sel.m @@ -4,6 +4,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/objc.dg/incomplete-type-1.m b/gcc/testsuite/objc.dg/incomplete-type-1.m index f1e875f..60d0d8a 100644 --- a/gcc/testsuite/objc.dg/incomplete-type-1.m +++ b/gcc/testsuite/objc.dg/incomplete-type-1.m @@ -6,6 +6,9 @@ enum type1; struct type2; +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyObject - (void) method1: (enum type1)argument; - (void) method2: (struct type2)argument; diff --git a/gcc/testsuite/objc.dg/instancetype-0.m b/gcc/testsuite/objc.dg/instancetype-0.m index 32cafdf..dc27926 100644 --- a/gcc/testsuite/objc.dg/instancetype-0.m +++ b/gcc/testsuite/objc.dg/instancetype-0.m @@ -6,6 +6,9 @@ extern id class_createInstance (id, int); extern id class_getSuperclass (id); +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyObject { Class isa; diff --git a/gcc/testsuite/objc.dg/invalid-method-2.m b/gcc/testsuite/objc.dg/invalid-method-2.m index cb18de9..0a4bd63 100644 --- a/gcc/testsuite/objc.dg/invalid-method-2.m +++ b/gcc/testsuite/objc.dg/invalid-method-2.m @@ -3,6 +3,9 @@ /* Test that using an invalid type in a method declaration produces a friendly error without a compiler crash. */ +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyClass @end diff --git a/gcc/testsuite/objc.dg/ivar-invalid-type-1.m b/gcc/testsuite/objc.dg/ivar-invalid-type-1.m index 3e7785d..98bf36e 100644 --- a/gcc/testsuite/objc.dg/ivar-invalid-type-1.m +++ b/gcc/testsuite/objc.dg/ivar-invalid-type-1.m @@ -1,6 +1,9 @@ /* { dg-do compile } */ #include +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyRootClass { Class isa; diff --git a/gcc/testsuite/objc.dg/ivar-problem-1.m b/gcc/testsuite/objc.dg/ivar-problem-1.m index 4a87768..0d5bb66 100644 --- a/gcc/testsuite/objc.dg/ivar-problem-1.m +++ b/gcc/testsuite/objc.dg/ivar-problem-1.m @@ -10,6 +10,9 @@ #include #include +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyRootClass1 { Class isa; @@ -36,6 +39,9 @@ @end +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyRootClass2 { Class isa; diff --git a/gcc/testsuite/objc.dg/ivar-scope-1.m b/gcc/testsuite/objc.dg/ivar-scope-1.m index 34443a4..64d275b 100644 --- a/gcc/testsuite/objc.dg/ivar-scope-1.m +++ b/gcc/testsuite/objc.dg/ivar-scope-1.m @@ -3,6 +3,9 @@ /* { dg-do compile } */ #include +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyClass { int someivar; diff --git a/gcc/testsuite/objc.dg/ivar-scope-2.m b/gcc/testsuite/objc.dg/ivar-scope-2.m index ff795d0..1149d73 100644 --- a/gcc/testsuite/objc.dg/ivar-scope-2.m +++ b/gcc/testsuite/objc.dg/ivar-scope-2.m @@ -4,6 +4,9 @@ /* { dg-additional-options "-fno-local-ivars" } */ #include +#if defined(__has_attribute) && __has_attribute(objc_root_class) +__attribute__((objc_root_class)) +#endif @interface MyClass { int someivar; diff --git a/gcc/testsuite/objc.dg/ivar-scope-4.m b/gcc/testsuite/objc.dg/ivar-scope-4.m index 5fc29f9..df1c892 100644 --- a/gcc/testsuite/objc.dg/ivar-scope-4.m +++ b/gcc/testsuite/objc.dg/ivar-scope-4.m @@ -1,7 +1,8 @@ /* Test instance variable scope. */ /* Author: Dimitris Papavasiliou . */ /* { dg-do run } */ -/* { dg-additional-options "-Wno-shadow-ivar -fno-local-ivars" } */ +/* { dg-additional-options "-Wno-shadow-ivar -fno-local-ivars -Wno-objc-root-class" } */ + #include "../objc-obj-c++-shared/runtime.h" #include diff --git a/gcc/testsuite/objc.dg/ivar-visibility-1.m b/gcc/testsuite/objc.dg/ivar-visibility-1.m index 5a22259..79d791e 100644 --- a/gcc/testsuite/objc.dg/ivar-visibility-1.m +++ b/gcc/testsuite/objc.dg/ivar-visibility-1.m @@ -1,6 +1,7 @@ /* Test instance variable visibility. */ /* Author: Dimitris Papavasiliou . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include @interface MySuperClass diff --git a/gcc/testsuite/objc.dg/ivar-visibility-2.m b/gcc/testsuite/objc.dg/ivar-visibility-2.m index eb41c8f..6ddcb5b 100644 --- a/gcc/testsuite/objc.dg/ivar-visibility-2.m +++ b/gcc/testsuite/objc.dg/ivar-visibility-2.m @@ -1,7 +1,7 @@ /* Test instance variable visibility. */ /* Author: Dimitris Papavasiliou . */ /* { dg-do compile } */ -/* { dg-additional-options "-fivar-visibility=protected" } */ +/* { dg-additional-options "-fivar-visibility=protected -Wno-objc-root-class" } */ #include @interface MySuperClass diff --git a/gcc/testsuite/objc.dg/ivar-visibility-3.m b/gcc/testsuite/objc.dg/ivar-visibility-3.m index ecc6f99..6403503 100644 --- a/gcc/testsuite/objc.dg/ivar-visibility-3.m +++ b/gcc/testsuite/objc.dg/ivar-visibility-3.m @@ -1,7 +1,7 @@ /* Test instance variable visibility. */ /* Author: Dimitris Papavasiliou . */ /* { dg-do compile } */ -/* { dg-additional-options "-fivar-visibility=private" } */ +/* { dg-additional-options "-fivar-visibility=private -Wno-objc-root-class" } */ #include @interface MySuperClass diff --git a/gcc/testsuite/objc.dg/ivar-visibility-4.m b/gcc/testsuite/objc.dg/ivar-visibility-4.m index adfeb44..abd802b 100644 --- a/gcc/testsuite/objc.dg/ivar-visibility-4.m +++ b/gcc/testsuite/objc.dg/ivar-visibility-4.m @@ -1,7 +1,7 @@ /* Test instance variable visibility. */ /* Author: Dimitris Papavasiliou . */ /* { dg-do compile } */ -/* { dg-additional-options "-fivar-visibility=public" } */ +/* { dg-additional-options "-fivar-visibility=public -Wno-objc-root-class" } */ #include @interface MySuperClass diff --git a/gcc/testsuite/objc.dg/local-decl-1.m b/gcc/testsuite/objc.dg/local-decl-1.m index 4a4bfdf..8356a8c 100644 --- a/gcc/testsuite/objc.dg/local-decl-1.m +++ b/gcc/testsuite/objc.dg/local-decl-1.m @@ -1,6 +1,7 @@ /* Test for hiding of ivars by local variables. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Sprite { int a; diff --git a/gcc/testsuite/objc.dg/lto/lto.exp b/gcc/testsuite/objc.dg/lto/lto.exp index e563ecb..8a362d6 100644 --- a/gcc/testsuite/objc.dg/lto/lto.exp +++ b/gcc/testsuite/objc.dg/lto/lto.exp @@ -41,10 +41,10 @@ if { ![check_effective_target_lto] } { global LTO_OPTIONS set LTO_OPTIONS [list \ - {-O0 -flto -fgnu-runtime} \ - {-O2 -flto -fgnu-runtime} \ - {-O0 -flto -flto-partition=none -fgnu-runtime} \ - {-O2 -flto -flto-partition=none -fgnu-runtime} \ + {-O0 -flto -fgnu-runtime -Wno-objc-root-class} \ + {-O2 -flto -fgnu-runtime -Wno-objc-root-class } \ + {-O0 -flto -flto-partition=none -fgnu-runtime -Wno-objc-root-class} \ + {-O2 -flto -flto-partition=none -fgnu-runtime -Wno-objc-root-class} \ ] objc_init @@ -67,10 +67,10 @@ foreach src $tests { # darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { set LTO_OPTIONS [list \ - {-O0 -flto -fnext-runtime} \ - {-O2 -flto -fnext-runtime} \ - {-O0 -flto -flto-partition=none -fnext-runtime} \ - {-O2 -flto -flto-partition=none -fnext-runtime} \ + {-O0 -flto -fnext-runtime -Wno-objc-root-class} \ + {-O2 -flto -fnext-runtime -Wno-objc-root-class} \ + {-O0 -flto -flto-partition=none -fnext-runtime -Wno-objc-root-class} \ + {-O2 -flto -flto-partition=none -fnext-runtime -Wno-objc-root-class} \ ] foreach src $tests { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/objc.dg/lto/trivial-1_0.m b/gcc/testsuite/objc.dg/lto/trivial-1_0.m index ba1b1aa..ca07fa4 100644 --- a/gcc/testsuite/objc.dg/lto/trivial-1_0.m +++ b/gcc/testsuite/objc.dg/lto/trivial-1_0.m @@ -1,5 +1,5 @@ /* { dg-lto-do run } */ -/* { dg-skip-if "" { "*-*-darwin*" && lp64 } } */ + extern int printf (char *,...) ; typedef struct objc_class *Class; @@ -7,7 +7,7 @@ typedef struct objc_class *Class; struct objc_class { Class isa; /* other stuff... */ -} ; +}; @interface myRootObject { @public diff --git a/gcc/testsuite/objc.dg/method-1.m b/gcc/testsuite/objc.dg/method-1.m index 194c64f..bd23493 100644 --- a/gcc/testsuite/objc.dg/method-1.m +++ b/gcc/testsuite/objc.dg/method-1.m @@ -1,5 +1,6 @@ /* Tests of duplication. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface class1 - (int) meth1; /* { dg-message "previous declaration" } */ diff --git a/gcc/testsuite/objc.dg/method-12.m b/gcc/testsuite/objc.dg/method-12.m index 411caac..b69a84f 100644 --- a/gcc/testsuite/objc.dg/method-12.m +++ b/gcc/testsuite/objc.dg/method-12.m @@ -1,5 +1,6 @@ /* Contributed by Igor Seleznev . */ /* This used to be broken. */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/method-13.m b/gcc/testsuite/objc.dg/method-13.m index 592038b..3e0fde5 100644 --- a/gcc/testsuite/objc.dg/method-13.m +++ b/gcc/testsuite/objc.dg/method-13.m @@ -4,6 +4,7 @@ /* Author: Ziemowit Laski . */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include "../objc-obj-c++-shared/runtime.h" diff --git a/gcc/testsuite/objc.dg/method-14.m b/gcc/testsuite/objc.dg/method-14.m index 9698225..bc3ee12 100644 --- a/gcc/testsuite/objc.dg/method-14.m +++ b/gcc/testsuite/objc.dg/method-14.m @@ -2,6 +2,7 @@ used as method selectors. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Foo - (void)insertNewButtonImage:(Foo *)newButtonImage in:(Foo *)buttonCell; diff --git a/gcc/testsuite/objc.dg/missing-proto-3.m b/gcc/testsuite/objc.dg/missing-proto-3.m index 05e1a25..77aa3a3 100644 --- a/gcc/testsuite/objc.dg/missing-proto-3.m +++ b/gcc/testsuite/objc.dg/missing-proto-3.m @@ -2,7 +2,8 @@ In addition to not crashing :-), the compiler should properly handle valid protocol references, even when they're mixed with invalid ones. */ /* { dg-do compile } */ - +/* { dg-additional-options "-Wno-objc-root-class" } */ + #include @protocol DefinedProtocol diff --git a/gcc/testsuite/objc.dg/next-runtime-1.m b/gcc/testsuite/objc.dg/next-runtime-1.m index c76b616..2ce798b 100644 --- a/gcc/testsuite/objc.dg/next-runtime-1.m +++ b/gcc/testsuite/objc.dg/next-runtime-1.m @@ -7,6 +7,7 @@ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-skip-if "" { *-*-* } { "-fobjc-abi-version=1" } { "" } } */ /* { dg-options "-fobjc-abi-version=0" { target { *-*-darwin* && { ! lp64 } } } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface FooBar - (void)boo; diff --git a/gcc/testsuite/objc.dg/objc-foreach-1.m b/gcc/testsuite/objc.dg/objc-foreach-1.m index 81f5dae..e4c958c 100644 --- a/gcc/testsuite/objc.dg/objc-foreach-1.m +++ b/gcc/testsuite/objc.dg/objc-foreach-1.m @@ -1,5 +1,6 @@ /* Syntax check for the new foreach statement. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_class *Class; diff --git a/gcc/testsuite/objc.dg/objc-foreach-2.m b/gcc/testsuite/objc.dg/objc-foreach-2.m index a01f004..0f79089 100644 --- a/gcc/testsuite/objc.dg/objc-foreach-2.m +++ b/gcc/testsuite/objc.dg/objc-foreach-2.m @@ -1,5 +1,6 @@ /* Syntax check for the new foreach statement. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_class *Class; diff --git a/gcc/testsuite/objc.dg/objc-foreach-3.m b/gcc/testsuite/objc.dg/objc-foreach-3.m index 922db39..b551ae3 100644 --- a/gcc/testsuite/objc.dg/objc-foreach-3.m +++ b/gcc/testsuite/objc.dg/objc-foreach-3.m @@ -1,6 +1,7 @@ /* Syntax check for the new foreach statement. Use of declaration in loop-header without requiring c99 mode. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_class *Class; diff --git a/gcc/testsuite/objc.dg/objc-nofilename-1.m b/gcc/testsuite/objc.dg/objc-nofilename-1.m index 21e0c53..3ddaa64 100644 --- a/gcc/testsuite/objc.dg/objc-nofilename-1.m +++ b/gcc/testsuite/objc.dg/objc-nofilename-1.m @@ -1,5 +1,6 @@ /* Test to make sure that file name does not appear in the binary. */ /* { dg-do compile { target *-*-darwin* } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/param-1.m b/gcc/testsuite/objc.dg/param-1.m index 9dbf6e3..8e77811 100644 --- a/gcc/testsuite/objc.dg/param-1.m +++ b/gcc/testsuite/objc.dg/param-1.m @@ -1,6 +1,7 @@ /* Test if compiler detects object as an parameter to a method or not. It is not valid. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface foo @end diff --git a/gcc/testsuite/objc.dg/pch/pch.exp b/gcc/testsuite/objc.dg/pch/pch.exp index 2da3d96..54c3e42 100644 --- a/gcc/testsuite/objc.dg/pch/pch.exp +++ b/gcc/testsuite/objc.dg/pch/pch.exp @@ -41,7 +41,7 @@ foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.m]] { # unlikely to make any difference to PCH. However, we do want to # add -O0 -g, since users who want PCH usually want debugging and quick # compiles. - dg-flags-pch $subdir $test "-fgnu-runtime" $mytorture ".h" + dg-flags-pch $subdir $test "-fgnu-runtime -Wno-objc-root-class" $mytorture ".h" } if [istarget "*-*-darwin*" ] { @@ -52,7 +52,7 @@ if [istarget "*-*-darwin*" ] { # unlikely to make any difference to PCH. However, we do want to # add -O0 -g, since users who want PCH usually want debugging and quick # compiles. - dg-flags-pch $subdir $test "-fnext-runtime" $mytorture ".h" + dg-flags-pch $subdir $test "-fnext-runtime -Wno-objc-root-class" $mytorture ".h" } } diff --git a/gcc/testsuite/objc.dg/plugin/diagnostic-test-expressions-1.m b/gcc/testsuite/objc.dg/plugin/diagnostic-test-expressions-1.m index 23a9302..7070b37 100644 --- a/gcc/testsuite/objc.dg/plugin/diagnostic-test-expressions-1.m +++ b/gcc/testsuite/objc.dg/plugin/diagnostic-test-expressions-1.m @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdiagnostics-show-caret" } */ +/* { dg-options "-O -fdiagnostics-show-caret -Wno-objc-root-class" } */ /* This file is similar to diagnostic-test-expressions-1.c (see the notes in that file); this file adds test diff --git a/gcc/testsuite/objc.dg/pr23709.m b/gcc/testsuite/objc.dg/pr23709.m index 7ff9b60..2bdcca5 100644 --- a/gcc/testsuite/objc.dg/pr23709.m +++ b/gcc/testsuite/objc.dg/pr23709.m @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface A +(void)method: (int)parameter {} /* { dg-error "expected" } */ diff --git a/gcc/testsuite/objc.dg/private-1.m b/gcc/testsuite/objc.dg/private-1.m index 7540fc5..5bd29e5 100644 --- a/gcc/testsuite/objc.dg/private-1.m +++ b/gcc/testsuite/objc.dg/private-1.m @@ -1,6 +1,7 @@ /* Test errors for accessing @private and @protected variables. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include @interface MySuperClass diff --git a/gcc/testsuite/objc.dg/private-2.m b/gcc/testsuite/objc.dg/private-2.m index eff376a..d0646f5 100644 --- a/gcc/testsuite/objc.dg/private-2.m +++ b/gcc/testsuite/objc.dg/private-2.m @@ -1,6 +1,7 @@ /* Test warnings for shadowing instance variables. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include @interface MySuperClass diff --git a/gcc/testsuite/objc.dg/property/property.exp b/gcc/testsuite/objc.dg/property/property.exp index 47ffcdf..1c203db 100644 --- a/gcc/testsuite/objc.dg/property/property.exp +++ b/gcc/testsuite/objc.dg/property/property.exp @@ -31,12 +31,12 @@ dg-init set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] # Main loop. -dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS +dg-runtest $tests "-fgnu-runtime -Wno-objc-root-class" $DEFAULT_CFLAGS # Darwin targets can also run code with the NeXT runtime. # but Properties are not supported by the runtime lib before Darwin 9. if [istarget "*-*-darwin\[9123\]*" ] { - dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS + dg-runtest $tests "-fnext-runtime -Wno-objc-root-class" $DEFAULT_CFLAGS } # All done. diff --git a/gcc/testsuite/objc.dg/proto-hier-1.m b/gcc/testsuite/objc.dg/proto-hier-1.m index 0f409fc..648a4d4 100644 --- a/gcc/testsuite/objc.dg/proto-hier-1.m +++ b/gcc/testsuite/objc.dg/proto-hier-1.m @@ -1,6 +1,7 @@ /* Test for handling of protocol hierarchies. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* One-line substitute for objc/objc.h */ typedef struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/objc.dg/proto-hier-2.m b/gcc/testsuite/objc.dg/proto-hier-2.m index 819cf4a..6b3f803 100644 --- a/gcc/testsuite/objc.dg/proto-hier-2.m +++ b/gcc/testsuite/objc.dg/proto-hier-2.m @@ -1,6 +1,7 @@ /* Test protocol warning. */ /* Contributed by Devang Patel . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/objc.dg/proto-lossage-1.m b/gcc/testsuite/objc.dg/proto-lossage-1.m index 2f7eb98..4564a94 100644 --- a/gcc/testsuite/objc.dg/proto-lossage-1.m +++ b/gcc/testsuite/objc.dg/proto-lossage-1.m @@ -2,6 +2,7 @@ may be lost, leading to superfluous warnings. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* One-line substitute for objc/objc.h */ typedef struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/objc.dg/proto-lossage-5.m b/gcc/testsuite/objc.dg/proto-lossage-5.m index 35c0956..a18b357 100644 --- a/gcc/testsuite/objc.dg/proto-lossage-5.m +++ b/gcc/testsuite/objc.dg/proto-lossage-5.m @@ -1,5 +1,6 @@ /* Do not lose references to forward-declared protocols. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @class MyBaseClass; @class MyClassThatFails; @protocol _MyProtocol; diff --git a/gcc/testsuite/objc.dg/proto-qual-1.m b/gcc/testsuite/objc.dg/proto-qual-1.m index 40eb0f9..6e90872 100644 --- a/gcc/testsuite/objc.dg/proto-qual-1.m +++ b/gcc/testsuite/objc.dg/proto-qual-1.m @@ -3,6 +3,7 @@ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include "../objc-obj-c++-shared/runtime.h" #include diff --git a/gcc/testsuite/objc.dg/protocol-inheritance-1.m b/gcc/testsuite/objc.dg/protocol-inheritance-1.m index 5241b29..5367a98 100644 --- a/gcc/testsuite/objc.dg/protocol-inheritance-1.m +++ b/gcc/testsuite/objc.dg/protocol-inheritance-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ /* { dg-options "-Wno-protocol" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/protocol-inheritance-2.m b/gcc/testsuite/objc.dg/protocol-inheritance-2.m index 74c9174..9776a40 100644 --- a/gcc/testsuite/objc.dg/protocol-inheritance-2.m +++ b/gcc/testsuite/objc.dg/protocol-inheritance-2.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/protocol-optional-1.m b/gcc/testsuite/objc.dg/protocol-optional-1.m index bc4a3d0..29fe72e 100644 --- a/gcc/testsuite/objc.dg/protocol-optional-1.m +++ b/gcc/testsuite/objc.dg/protocol-optional-1.m @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/selector-1.m b/gcc/testsuite/objc.dg/selector-1.m index f0781b6..5ff15a2 100644 --- a/gcc/testsuite/objc.dg/selector-1.m +++ b/gcc/testsuite/objc.dg/selector-1.m @@ -3,6 +3,7 @@ /* { dg-options "-Wselector" } */ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { struct objc_class *class_pointer; } *id; typedef struct objc_selector *SEL; diff --git a/gcc/testsuite/objc.dg/selector-2.m b/gcc/testsuite/objc.dg/selector-2.m index 6cad2ff..5042104 100644 --- a/gcc/testsuite/objc.dg/selector-2.m +++ b/gcc/testsuite/objc.dg/selector-2.m @@ -1,6 +1,7 @@ /* Test that we don't ICE when issuing a -Wselector warning. */ /* { dg-options "-Wselector" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/selector-3.m b/gcc/testsuite/objc.dg/selector-3.m index c0c5f3d..94838cd3 100644 --- a/gcc/testsuite/objc.dg/selector-3.m +++ b/gcc/testsuite/objc.dg/selector-3.m @@ -3,6 +3,7 @@ /* { dg-options "-Wselector" } */ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { struct objc_class *class_pointer; } *id; typedef const struct objc_selector *SEL; diff --git a/gcc/testsuite/objc.dg/selector-4.m b/gcc/testsuite/objc.dg/selector-4.m index d34f8c8..2a4947e 100644 --- a/gcc/testsuite/objc.dg/selector-4.m +++ b/gcc/testsuite/objc.dg/selector-4.m @@ -3,6 +3,7 @@ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Int1 + (int)and_eq:(int)arg1 and:(int)arg2; diff --git a/gcc/testsuite/objc.dg/shadow-1.m b/gcc/testsuite/objc.dg/shadow-1.m index 739a0d0..d18fd6e 100644 --- a/gcc/testsuite/objc.dg/shadow-1.m +++ b/gcc/testsuite/objc.dg/shadow-1.m @@ -2,6 +2,7 @@ /* Author: Dimitris Papavasiliou . */ /* { dg-do compile } */ /* { dg-additional-options "-Wno-shadow-ivar" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include @interface MyClass diff --git a/gcc/testsuite/objc.dg/shadow-2.m b/gcc/testsuite/objc.dg/shadow-2.m index 16261b9..26447fe 100644 --- a/gcc/testsuite/objc.dg/shadow-2.m +++ b/gcc/testsuite/objc.dg/shadow-2.m @@ -2,6 +2,7 @@ /* Author: Dimitris Papavasiliou . */ /* { dg-do compile } */ /* { dg-additional-options "-Wno-shadow" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include @interface MyClass diff --git a/gcc/testsuite/objc.dg/special/load-category-1.m b/gcc/testsuite/objc.dg/special/load-category-1.m index cb22143..b72d070 100644 --- a/gcc/testsuite/objc.dg/special/load-category-1.m +++ b/gcc/testsuite/objc.dg/special/load-category-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/special/load-category-2.m b/gcc/testsuite/objc.dg/special/load-category-2.m index 7dc74595..2706351 100644 --- a/gcc/testsuite/objc.dg/special/load-category-2.m +++ b/gcc/testsuite/objc.dg/special/load-category-2.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/special/load-category-3.m b/gcc/testsuite/objc.dg/special/load-category-3.m index b89d8f1..215e463 100644 --- a/gcc/testsuite/objc.dg/special/load-category-3.m +++ b/gcc/testsuite/objc.dg/special/load-category-3.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* This test is identical to load-category-2, but the classes and categories are created in inverted order in the modules, to test diff --git a/gcc/testsuite/objc.dg/special/special.exp b/gcc/testsuite/objc.dg/special/special.exp index d770e2a..f561d38 100644 --- a/gcc/testsuite/objc.dg/special/special.exp +++ b/gcc/testsuite/objc.dg/special/special.exp @@ -39,6 +39,7 @@ dg-init # for all systems we point to the libobjc includes and use the -fgnu-runtime set add_flags "additional_flags=-I${srcdir}/../../libobjc" lappend add_flags "additional_flags=-fgnu-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/unclaimed-category-1a.m" "unclaimed-category-1a.o" object $add_flags ] if ![string match "" $lines] then { fail "unclaimed-category-1a.o" @@ -50,6 +51,7 @@ if ![string match "" $lines] then { if [istarget "*-*-darwin*" ] { set add_flags "" lappend add_flags "additional_flags=-fnext-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/unclaimed-category-1a.m" "unclaimed-category-1a.o" object $add_flags ] if ![string match "" $lines] then { fail "unclaimed-category-1a.o" @@ -66,6 +68,7 @@ if ![string match "" $lines] then { # and load-category-1a.m, link them together, and execute the result. set add_flags "additional_flags=-I${srcdir}/../../libobjc" lappend add_flags "additional_flags=-fgnu-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/load-category-1a.m" "load-category-1a.o" object $add_flags ] if ![string match "" $lines] then { fail "load-category-1a.o" @@ -77,6 +80,7 @@ if ![string match "" $lines] then { if [istarget "*-*-darwin*" ] { set add_flags "" lappend add_flags "additional_flags=-fnext-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/load-category-1a.m" "load-category-1a.o" object $add_flags ] if ![string match "" $lines] then { fail "load-category-1a.o" @@ -93,6 +97,7 @@ if ![string match "" $lines] then { # and load-category-2a.m, link them together, and execute the result. set add_flags "additional_flags=-I${srcdir}/../../libobjc" lappend add_flags "additional_flags=-fgnu-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/load-category-2a.m" "load-category-2a.o" object $add_flags ] if ![string match "" $lines] then { fail "load-category-2a.o" @@ -104,6 +109,7 @@ if ![string match "" $lines] then { if [istarget "*-*-darwin*" ] { set add_flags "" lappend add_flags "additional_flags=-fnext-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/load-category-2a.m" "load-category-2a.o" object $add_flags ] if ![string match "" $lines] then { fail "load-category-2a.o" @@ -120,6 +126,7 @@ if ![string match "" $lines] then { # and load-category-3a.m, link them together, and execute the result. set add_flags "additional_flags=-I${srcdir}/../../libobjc" lappend add_flags "additional_flags=-fgnu-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/load-category-3a.m" "load-category-3a.o" object $add_flags ] if ![string match "" $lines] then { fail "load-category-3a.o" @@ -131,6 +138,7 @@ if ![string match "" $lines] then { if [istarget "*-*-darwin*" ] { set add_flags "" lappend add_flags "additional_flags=-fnext-runtime" +lappend add_flags "additional_flags=-Wno-objc-root-class" set lines [objc_target_compile "$srcdir/$subdir/load-category-3a.m" "load-category-3a.o" object $add_flags ] if ![string match "" $lines] then { fail "load-category-3a.o" diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h index a32024d..cb5812e 100644 --- a/gcc/testsuite/objc.dg/special/unclaimed-category-1.h +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.h @@ -1,4 +1,5 @@ /* Contributed by Nicola Pero - Fri Dec 14 08:36:00 GMT 2001 */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test loading unclaimed categories - categories of a class defined separately from the class itself. */ diff --git a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m index 7b434b4..a8e422d 100644 --- a/gcc/testsuite/objc.dg/special/unclaimed-category-1.m +++ b/gcc/testsuite/objc.dg/special/unclaimed-category-1.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero - Fri Dec 14 08:36:00 GMT 2001 */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include "../../objc-obj-c++-shared/runtime.h" diff --git a/gcc/testsuite/objc.dg/stabs-1.m b/gcc/testsuite/objc.dg/stabs-1.m index 452993e..b97e4d6 100644 --- a/gcc/testsuite/objc.dg/stabs-1.m +++ b/gcc/testsuite/objc.dg/stabs-1.m @@ -3,6 +3,7 @@ /* { dg-do compile { target stabs } } */ /* { dg-options "-gstabs" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface MyClass + newWithArg: arg; diff --git a/gcc/testsuite/objc.dg/strings/strings.exp b/gcc/testsuite/objc.dg/strings/strings.exp index 41da5cb..6042d3c 100644 --- a/gcc/testsuite/objc.dg/strings/strings.exp +++ b/gcc/testsuite/objc.dg/strings/strings.exp @@ -35,11 +35,11 @@ dg-init set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] # Main loop. -dg-runtest $tests "-fgnu-runtime" $DEFAULT_CFLAGS +dg-runtest $tests "-fgnu-runtime -Wno-objc-root-class" $DEFAULT_CFLAGS # darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { - dg-runtest $tests "-fnext-runtime" $DEFAULT_CFLAGS + dg-runtest $tests "-fnext-runtime -Wno-objc-root-class" $DEFAULT_CFLAGS } # All done. diff --git a/gcc/testsuite/objc.dg/stubify-1.m b/gcc/testsuite/objc.dg/stubify-1.m index 641595c..4043492 100644 --- a/gcc/testsuite/objc.dg/stubify-1.m +++ b/gcc/testsuite/objc.dg/stubify-1.m @@ -5,6 +5,7 @@ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-require-effective-target ilp32 } */ /* { dg-options "-Os -mdynamic-no-pic -mmacosx-version-min=10.4 -msymbol-stubs" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { } *id ; int x = 41 ; diff --git a/gcc/testsuite/objc.dg/stubify-2.m b/gcc/testsuite/objc.dg/stubify-2.m index 904ac44..3e9097e 100644 --- a/gcc/testsuite/objc.dg/stubify-2.m +++ b/gcc/testsuite/objc.dg/stubify-2.m @@ -5,6 +5,7 @@ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-require-effective-target ilp32 } */ /* { dg-options "-mdynamic-no-pic -fdump-rtl-jump -mmacosx-version-min=10.4 -msymbol-stubs" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { } *id ; int x = 41 ; diff --git a/gcc/testsuite/objc.dg/super-class-2.m b/gcc/testsuite/objc.dg/super-class-2.m index 144ea81..63792fd 100644 --- a/gcc/testsuite/objc.dg/super-class-2.m +++ b/gcc/testsuite/objc.dg/super-class-2.m @@ -1,6 +1,7 @@ /* Test calling super from within a category class method. */ /* Author: Ziemowit Laski */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct objc_object { struct objc_class *isa; } *id; diff --git a/gcc/testsuite/objc.dg/super-dealloc-1.m b/gcc/testsuite/objc.dg/super-dealloc-1.m index 0ab177b..035de05 100644 --- a/gcc/testsuite/objc.dg/super-dealloc-1.m +++ b/gcc/testsuite/objc.dg/super-dealloc-1.m @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Foo { void *isa; diff --git a/gcc/testsuite/objc.dg/super-dealloc-2.m b/gcc/testsuite/objc.dg/super-dealloc-2.m index 80dcf49..5d588c5 100644 --- a/gcc/testsuite/objc.dg/super-dealloc-2.m +++ b/gcc/testsuite/objc.dg/super-dealloc-2.m @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Foo { void *isa; diff --git a/gcc/testsuite/objc.dg/sync-3.m b/gcc/testsuite/objc.dg/sync-3.m index 5cee890..6ef72a1 100644 --- a/gcc/testsuite/objc.dg/sync-3.m +++ b/gcc/testsuite/objc.dg/sync-3.m @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that the compiler is checking the argument of @synchronized(), and produce errors when invalid types are used. */ diff --git a/gcc/testsuite/objc.dg/threedotthree-abi-1.m b/gcc/testsuite/objc.dg/threedotthree-abi-1.m index 53154d3..8c22850 100644 --- a/gcc/testsuite/objc.dg/threedotthree-abi-1.m +++ b/gcc/testsuite/objc.dg/threedotthree-abi-1.m @@ -3,6 +3,7 @@ /* { dg-do run { target *-*-darwin* } } */ /* { dg-require-effective-target ilp32 } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/objc.dg/torture/dg-torture.exp b/gcc/testsuite/objc.dg/torture/dg-torture.exp index 28c2359..11f50fc 100644 --- a/gcc/testsuite/objc.dg/torture/dg-torture.exp +++ b/gcc/testsuite/objc.dg/torture/dg-torture.exp @@ -7,11 +7,11 @@ dg-init # Gather a list of all tests. set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] -objc-dg-runtest $tests "" "-fgnu-runtime" +objc-dg-runtest $tests "" "-fgnu-runtime -Wno-objc-root-class" # darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { - objc-dg-runtest $tests "" "-fnext-runtime" + objc-dg-runtest $tests "" "-fnext-runtime -Wno-objc-root-class" } dg-finish diff --git a/gcc/testsuite/objc.dg/torture/strings/strings.exp b/gcc/testsuite/objc.dg/torture/strings/strings.exp index 64e53c6..3e2b3b0 100644 --- a/gcc/testsuite/objc.dg/torture/strings/strings.exp +++ b/gcc/testsuite/objc.dg/torture/strings/strings.exp @@ -24,11 +24,11 @@ dg-init # Gather a list of all tests. set tests [lsort [glob -nocomplain $srcdir/$subdir/*.m]] -objc-dg-runtest $tests "" "-fgnu-runtime" +objc-dg-runtest $tests "" "-fgnu-runtime -Wno-objc-root-class" # Darwin targets also test with the NeXT runtime. if [istarget "*-*-darwin*" ] { - objc-dg-runtest $tests "" "-fnext-runtime" + objc-dg-runtest $tests "" "-fnext-runtime -Wno-objc-root-class" } dg-finish diff --git a/gcc/testsuite/objc.dg/try-catch-11.m b/gcc/testsuite/objc.dg/try-catch-11.m index e08f321..c792c83 100644 --- a/gcc/testsuite/objc.dg/try-catch-11.m +++ b/gcc/testsuite/objc.dg/try-catch-11.m @@ -4,6 +4,7 @@ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef volatile int IOSharedLockData; diff --git a/gcc/testsuite/objc.dg/try-catch-12.m b/gcc/testsuite/objc.dg/try-catch-12.m index ce26b32..6c9afc2 100644 --- a/gcc/testsuite/objc.dg/try-catch-12.m +++ b/gcc/testsuite/objc.dg/try-catch-12.m @@ -4,6 +4,7 @@ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface TestMyTests - (void) testSpoon; diff --git a/gcc/testsuite/objc.dg/type-size-2.m b/gcc/testsuite/objc.dg/type-size-2.m index d02a8af..64444cfe 100644 --- a/gcc/testsuite/objc.dg/type-size-2.m +++ b/gcc/testsuite/objc.dg/type-size-2.m @@ -4,6 +4,7 @@ /* Contributed by Ziemowit Laski . */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include "../objc-obj-c++-shared/runtime.h" #include diff --git a/gcc/testsuite/objc.dg/type-size-3.m b/gcc/testsuite/objc.dg/type-size-3.m index bc66b0b..3f65516 100644 --- a/gcc/testsuite/objc.dg/type-size-3.m +++ b/gcc/testsuite/objc.dg/type-size-3.m @@ -1,6 +1,7 @@ /* Reject ivars that use flexible array members. */ /* Contributed by Nicola Pero */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct { diff --git a/gcc/testsuite/objc.dg/type-size-4.m b/gcc/testsuite/objc.dg/type-size-4.m index 7e26da3..f10ed5b 100644 --- a/gcc/testsuite/objc.dg/type-size-4.m +++ b/gcc/testsuite/objc.dg/type-size-4.m @@ -2,6 +2,7 @@ /* Contributed by Nicola Pero */ /* PR objc/47832 */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct { diff --git a/gcc/testsuite/objc.dg/type-size-5.m b/gcc/testsuite/objc.dg/type-size-5.m index d89af32..e1b11f7 100644 --- a/gcc/testsuite/objc.dg/type-size-5.m +++ b/gcc/testsuite/objc.dg/type-size-5.m @@ -1,6 +1,7 @@ /* Reject ivars that use flexible array members. */ /* Contributed by Nicola Pero */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ typedef struct { diff --git a/gcc/testsuite/objc.dg/undeclared-selector.m b/gcc/testsuite/objc.dg/undeclared-selector.m index 1cfc6c8..389b032 100644 --- a/gcc/testsuite/objc.dg/undeclared-selector.m +++ b/gcc/testsuite/objc.dg/undeclared-selector.m @@ -2,6 +2,7 @@ /* Author: Nicola Pero . */ /* { dg-do compile } */ /* { dg-options "-Wundeclared-selector" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/objc.dg/volatile-1.m b/gcc/testsuite/objc.dg/volatile-1.m index 8b5381a..a713631 100644 --- a/gcc/testsuite/objc.dg/volatile-1.m +++ b/gcc/testsuite/objc.dg/volatile-1.m @@ -1,7 +1,8 @@ /* Test for proper handling of volatile parameters in ObjC methods. */ +/* Contributed by Ziemowit Laski */ /* { dg-do compile } */ /* { dg-options "-O2" } */ -/* Contributed by Ziemowit Laski */ +/* { dg-additional-options "-Wno-objc-root-class" } */ @interface Test -(void) test2: (volatile int) a; -- cgit v1.1 From 64f191b152cb1df0e108a91880cb415e413bad56 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 25 Oct 2020 09:54:21 +0000 Subject: Objective-C [3/3] : Implement Wobjc-root-class [PR77404]. Add Wno-objc-root-class where needed to the objective-c++ tests. gcc/testsuite/ChangeLog: PR objc/77404 * obj-c++.dg/attributes/class-attribute-1.mm: Add Wno-objc-root-class. * obj-c++.dg/attributes/class-attribute-2.mm: Likewise. * obj-c++.dg/attributes/class-attribute-3.mm: Likewise. * obj-c++.dg/attributes/method-deprecated-1.mm: Likewise. * obj-c++.dg/attributes/method-deprecated-2.mm: Likewise. * obj-c++.dg/attributes/method-deprecated-3.mm: Likewise. * obj-c++.dg/attributes/method-format-1.mm: Likewise. * obj-c++.dg/attributes/method-nonnull-1.mm: Likewise. * obj-c++.dg/attributes/method-noreturn-1.mm: Likewise. * obj-c++.dg/attributes/method-sentinel-1.mm: Likewise. * obj-c++.dg/attributes/nsobject-01.mm: Likewise. * obj-c++.dg/attributes/parameter-attribute-1.mm: Likewise. * obj-c++.dg/attributes/parameter-attribute-2.mm: Likewise. * obj-c++.dg/attributes/proto-attribute-1.mm: Likewise. * obj-c++.dg/attributes/proto-attribute-3.mm: Likewise. * obj-c++.dg/attributes/proto-attribute-4.mm: Likewise. * obj-c++.dg/attributes/unused-parameter-1.mm: Likewise. * obj-c++.dg/bad-receiver-type.mm: Likewise. * obj-c++.dg/bitfield-3.mm: Likewise. * obj-c++.dg/bitfield-5.mm: Likewise. * obj-c++.dg/class-extension-1.mm: Likewise. * obj-c++.dg/class-extension-2.mm: Likewise. * obj-c++.dg/class-extension-3.mm: Likewise. * obj-c++.dg/class-extension-4.mm: Likewise. * obj-c++.dg/class-protocol-1.mm: Likewise. * obj-c++.dg/comp-types-1.mm: Likewise. * obj-c++.dg/comp-types-10.mm: Likewise. * obj-c++.dg/comp-types-2.mm: Likewise. * obj-c++.dg/comp-types-3.mm: Likewise. * obj-c++.dg/comp-types-5.mm: Likewise. * obj-c++.dg/comp-types-6.mm: Likewise. * obj-c++.dg/comp-types-7.mm: Likewise. * obj-c++.dg/comp-types-8.mm: Likewise. * obj-c++.dg/demangle-2.mm: Likewise. * obj-c++.dg/demangle-3.mm: Likewise. * obj-c++.dg/duplicate-class-1.mm: Likewise. * obj-c++.dg/encode-1-next.mm: Likewise. * obj-c++.dg/encode-1.mm: Likewise. * obj-c++.dg/enhanced-proto-2.mm: Likewise. * obj-c++.dg/exceptions-1.mm: Likewise. * obj-c++.dg/exceptions-3.mm: Likewise. * obj-c++.dg/exceptions-4.mm: Likewise. * obj-c++.dg/exceptions-5.mm: Likewise. * obj-c++.dg/extern-c-1.mm: Likewise. * obj-c++.dg/fobjc-std-1.mm: Likewise. * obj-c++.dg/gnu-api-2-class-meta.mm: Likewise. * obj-c++.dg/gnu-api-2-class.mm: Likewise. * obj-c++.dg/gnu-api-2-ivar.mm: Likewise. * obj-c++.dg/gnu-api-2-method.mm: Likewise. * obj-c++.dg/gnu-api-2-objc.mm: Likewise. * obj-c++.dg/gnu-api-2-objc_msg_lookup.mm: Likewise. * obj-c++.dg/gnu-api-2-object.mm: Likewise. * obj-c++.dg/gnu-api-2-property.mm: Likewise. * obj-c++.dg/gnu-api-2-protocol.mm: Likewise. * obj-c++.dg/gnu-api-2-resolve-method.mm: Likewise. * obj-c++.dg/gnu-api-2-sel.mm: Likewise. * obj-c++.dg/invalid-method-2.mm: Likewise. * obj-c++.dg/ivar-invalid-type-1.mm: Likewise. * obj-c++.dg/ivar-problem-1.mm: Likewise. * obj-c++.dg/lto/lto.exp: Likewise. * obj-c++.dg/lto/trivial-1_0.mm: Likewise. * obj-c++.dg/method-1.mm: Likewise. * obj-c++.dg/method-12.mm: Likewise. * obj-c++.dg/method-18.mm: Likewise. * obj-c++.dg/method-19.mm: Likewise. * obj-c++.dg/method-20.mm: Likewise. * obj-c++.dg/method-3.mm: Likewise. * obj-c++.dg/method-4.mm: Likewise. * obj-c++.dg/method-5.mm: Likewise. * obj-c++.dg/method-8.mm: Likewise. * obj-c++.dg/method-9.mm: Likewise. * obj-c++.dg/method-namespace-1.mm: Likewise. * obj-c++.dg/plugin/diagnostic-test-expressions-1.mm: Likewise. * obj-c++.dg/pr23709.mm: Likewise. * obj-c++.dg/pragma-2.mm: Likewise. * obj-c++.dg/private-1.mm: Likewise. * obj-c++.dg/private-2.mm: Likewise. * obj-c++.dg/property/property.exp: Likewise. * obj-c++.dg/proto-lossage-1.mm: Likewise. * obj-c++.dg/proto-lossage-5.mm: Likewise. * obj-c++.dg/proto-qual-1.mm: Likewise. * obj-c++.dg/protocol-inheritance-1.mm: Likewise. * obj-c++.dg/protocol-inheritance-2.mm: Likewise. * obj-c++.dg/protocol-optional-1.mm: Likewise. * obj-c++.dg/selector-1.mm: Likewise. * obj-c++.dg/selector-2.mm: Likewise. * obj-c++.dg/selector-3.mm: Likewise. * obj-c++.dg/selector-4.mm: Likewise. * obj-c++.dg/strings/strings.exp: Likewise. * obj-c++.dg/stubify-1.mm: Likewise. * obj-c++.dg/stubify-2.mm: Likewise. * obj-c++.dg/super-dealloc-1.mm: Likewise. * obj-c++.dg/super-dealloc-2.mm: Likewise. * obj-c++.dg/sync-3.mm: Likewise. * obj-c++.dg/syntax-error-2.mm: Likewise. * obj-c++.dg/syntax-error-4.mm: Likewise. * obj-c++.dg/syntax-error-7.mm: Likewise. * obj-c++.dg/syntax-error-9.mm: Likewise. * obj-c++.dg/template-4.mm: Likewise. * obj-c++.dg/template-7.mm: Likewise. * obj-c++.dg/template-8.mm: Likewise. * obj-c++.dg/threedotthree-abi-1.mm: Likewise. * obj-c++.dg/torture/dg-torture.exp: Likewise. * obj-c++.dg/torture/strings/strings.exp: Likewise. * obj-c++.dg/try-catch-12.mm: Likewise. * obj-c++.dg/try-catch-13.mm: Likewise. --- gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm | 1 + .../obj-c++.dg/attributes/method-deprecated-1.mm | 1 + .../obj-c++.dg/attributes/method-deprecated-2.mm | 1 + .../obj-c++.dg/attributes/method-deprecated-3.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/nsobject-01.mm | 2 +- .../obj-c++.dg/attributes/parameter-attribute-1.mm | 1 + .../obj-c++.dg/attributes/parameter-attribute-2.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm | 1 + gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm | 2 +- gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm | 1 + .../obj-c++.dg/attributes/unused-parameter-1.mm | 1 + gcc/testsuite/obj-c++.dg/bad-receiver-type.mm | 1 + gcc/testsuite/obj-c++.dg/bitfield-3.mm | 1 + gcc/testsuite/obj-c++.dg/bitfield-5.mm | 1 + gcc/testsuite/obj-c++.dg/class-extension-1.mm | 1 + gcc/testsuite/obj-c++.dg/class-extension-2.mm | 1 + gcc/testsuite/obj-c++.dg/class-extension-3.mm | 1 + gcc/testsuite/obj-c++.dg/class-extension-4.mm | 1 + gcc/testsuite/obj-c++.dg/class-protocol-1.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-1.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-10.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-2.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-3.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-5.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-6.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-7.mm | 1 + gcc/testsuite/obj-c++.dg/comp-types-8.mm | 1 + gcc/testsuite/obj-c++.dg/demangle-2.mm | 1 + gcc/testsuite/obj-c++.dg/demangle-3.mm | 1 + gcc/testsuite/obj-c++.dg/duplicate-class-1.mm | 1 + gcc/testsuite/obj-c++.dg/encode-1-next.mm | 1 + gcc/testsuite/obj-c++.dg/encode-1.mm | 1 + gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm | 1 + gcc/testsuite/obj-c++.dg/exceptions-1.mm | 1 + gcc/testsuite/obj-c++.dg/exceptions-3.mm | 1 + gcc/testsuite/obj-c++.dg/exceptions-4.mm | 1 + gcc/testsuite/obj-c++.dg/exceptions-5.mm | 1 + gcc/testsuite/obj-c++.dg/extern-c-1.mm | 1 + gcc/testsuite/obj-c++.dg/fobjc-std-1.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm | 1 + gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm | 1 + gcc/testsuite/obj-c++.dg/invalid-method-2.mm | 1 + gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm | 1 + gcc/testsuite/obj-c++.dg/ivar-problem-1.mm | 1 + gcc/testsuite/obj-c++.dg/lto/lto.exp | 16 ++++++++-------- gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm | 2 +- gcc/testsuite/obj-c++.dg/method-1.mm | 1 + gcc/testsuite/obj-c++.dg/method-12.mm | 1 + gcc/testsuite/obj-c++.dg/method-18.mm | 1 + gcc/testsuite/obj-c++.dg/method-19.mm | 1 + gcc/testsuite/obj-c++.dg/method-20.mm | 1 + gcc/testsuite/obj-c++.dg/method-3.mm | 1 + gcc/testsuite/obj-c++.dg/method-4.mm | 1 + gcc/testsuite/obj-c++.dg/method-5.mm | 1 + gcc/testsuite/obj-c++.dg/method-8.mm | 1 + gcc/testsuite/obj-c++.dg/method-9.mm | 1 + gcc/testsuite/obj-c++.dg/method-namespace-1.mm | 1 + .../obj-c++.dg/plugin/diagnostic-test-expressions-1.mm | 1 + gcc/testsuite/obj-c++.dg/pr23709.mm | 1 + gcc/testsuite/obj-c++.dg/pragma-2.mm | 1 + gcc/testsuite/obj-c++.dg/private-1.mm | 1 + gcc/testsuite/obj-c++.dg/private-2.mm | 1 + gcc/testsuite/obj-c++.dg/property/property.exp | 4 ++-- gcc/testsuite/obj-c++.dg/proto-lossage-1.mm | 1 + gcc/testsuite/obj-c++.dg/proto-lossage-5.mm | 1 + gcc/testsuite/obj-c++.dg/proto-qual-1.mm | 1 + gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm | 1 + gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm | 1 + gcc/testsuite/obj-c++.dg/protocol-optional-1.mm | 1 + gcc/testsuite/obj-c++.dg/selector-1.mm | 1 + gcc/testsuite/obj-c++.dg/selector-2.mm | 1 + gcc/testsuite/obj-c++.dg/selector-3.mm | 1 + gcc/testsuite/obj-c++.dg/selector-4.mm | 1 + gcc/testsuite/obj-c++.dg/strings/strings.exp | 4 ++-- gcc/testsuite/obj-c++.dg/stubify-1.mm | 1 + gcc/testsuite/obj-c++.dg/stubify-2.mm | 1 + gcc/testsuite/obj-c++.dg/super-dealloc-1.mm | 1 + gcc/testsuite/obj-c++.dg/super-dealloc-2.mm | 1 + gcc/testsuite/obj-c++.dg/sync-3.mm | 1 + gcc/testsuite/obj-c++.dg/syntax-error-2.mm | 1 + gcc/testsuite/obj-c++.dg/syntax-error-4.mm | 1 + gcc/testsuite/obj-c++.dg/syntax-error-7.mm | 1 + gcc/testsuite/obj-c++.dg/syntax-error-9.mm | 1 + gcc/testsuite/obj-c++.dg/template-4.mm | 1 + gcc/testsuite/obj-c++.dg/template-7.mm | 1 + gcc/testsuite/obj-c++.dg/template-8.mm | 1 + gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm | 1 + gcc/testsuite/obj-c++.dg/torture/dg-torture.exp | 4 ++-- gcc/testsuite/obj-c++.dg/torture/strings/strings.exp | 4 ++-- gcc/testsuite/obj-c++.dg/try-catch-12.mm | 1 + gcc/testsuite/obj-c++.dg/try-catch-13.mm | 1 + 106 files changed, 117 insertions(+), 19 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm index f078339..7eafdbc 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-1.mm @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test deprecate attribute with an @interface declaration. */ diff --git a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm index 35015c0..629ba86 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-2.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm index f96500d..3b7c8c3 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/class-attribute-3.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that you get a warning when an unknown class attribute is ignored. */ diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm index 8343856..68e8373 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-1.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm index 1e5d87f..8fb0e15 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-2.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm index 5c715a2..efa2d34 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-deprecated-3.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm index 9ff34f9..d3bb997 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-format-1.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ /* { dg-options "-Wall" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm index 83f918c..af48787 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-nonnull-1.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , May 2011. */ /* { dg-do compile } */ /* { dg-options "-Wall" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm index a83048b..413a0be 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-noreturn-1.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm b/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm index 2b8e6fd..ece7a9f 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/method-sentinel-1.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , October 2010. */ /* { dg-do compile } */ /* { dg-options "-Wall" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/nsobject-01.mm b/gcc/testsuite/obj-c++.dg/attributes/nsobject-01.mm index 498fbc7..3af785b 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/nsobject-01.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/nsobject-01.mm @@ -1,5 +1,5 @@ /* Test handling of the NSObject attribute. */ -/* { dg-additional-options "-fsyntax-only " } */ +/* { dg-additional-options "-fsyntax-only -Wno-objc-root-class" } */ typedef struct AnObj * __attribute__ ((NSObject)) AnObjRef; typedef struct AnObj * __attribute__ ((__NSObject__)) AnotherObjRef; diff --git a/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-1.mm index a4ba259..b4556ba 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-1.mm @@ -1,6 +1,7 @@ /* Test __attribute__((unused)) for an Objective-C method parameter. */ /* { dg-do compile } */ /* { dg-options "-Wunused-parameter" } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-2.mm b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-2.mm index 3908faf..9d69e42 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-2.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/parameter-attribute-2.mm @@ -1,5 +1,6 @@ /* Test that we get warnings for unrecognized attributes. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm index a852a7a..03726dc 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-1.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm index fc5251e..263f927 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-3.mm @@ -1,7 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ - +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test deprecate attribute with normal @protocol declarations. */ diff --git a/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm index d2e5f28..665e13d 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/proto-attribute-4.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ /* Test that you get a warning when an unknown protocol attribute is ignored. */ diff --git a/gcc/testsuite/obj-c++.dg/attributes/unused-parameter-1.mm b/gcc/testsuite/obj-c++.dg/attributes/unused-parameter-1.mm index 8fbb11e..c56a7f7 100644 --- a/gcc/testsuite/obj-c++.dg/attributes/unused-parameter-1.mm +++ b/gcc/testsuite/obj-c++.dg/attributes/unused-parameter-1.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class" } */ #include diff --git a/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm b/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm index 1d6699f..9c00a06 100644 --- a/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm +++ b/gcc/testsuite/obj-c++.dg/bad-receiver-type.mm @@ -1,5 +1,6 @@ // { dg-do compile } // { dg-options "" } +// { dg-additional-options "-Wno-objc-root-class" } @interface A diff --git a/gcc/testsuite/obj-c++.dg/bitfield-3.mm b/gcc/testsuite/obj-c++.dg/bitfield-3.mm index d81976a..c4ed984 100644 --- a/gcc/testsuite/obj-c++.dg/bitfield-3.mm +++ b/gcc/testsuite/obj-c++.dg/bitfield-3.mm @@ -4,6 +4,7 @@ /* { dg-do run { target *-*-darwin* } } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-options "-fsigned-char" } */ +// { dg-additional-options "-Wno-objc-root-class" } typedef struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/obj-c++.dg/bitfield-5.mm b/gcc/testsuite/obj-c++.dg/bitfield-5.mm index 3b0065d..d86c9b1 100644 --- a/gcc/testsuite/obj-c++.dg/bitfield-5.mm +++ b/gcc/testsuite/obj-c++.dg/bitfield-5.mm @@ -3,6 +3,7 @@ (@interface vs. @implementation) checks take the bitfield width into account. */ /* Author: Ziemowit Laski */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface Base { int i; diff --git a/gcc/testsuite/obj-c++.dg/class-extension-1.mm b/gcc/testsuite/obj-c++.dg/class-extension-1.mm index 5c89a98..c497c1d 100644 --- a/gcc/testsuite/obj-c++.dg/class-extension-1.mm +++ b/gcc/testsuite/obj-c++.dg/class-extension-1.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This test tests the basic of class extensions. */ diff --git a/gcc/testsuite/obj-c++.dg/class-extension-2.mm b/gcc/testsuite/obj-c++.dg/class-extension-2.mm index 7f55b60..108bc00 100644 --- a/gcc/testsuite/obj-c++.dg/class-extension-2.mm +++ b/gcc/testsuite/obj-c++.dg/class-extension-2.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This test tests class extensions and protocols. */ diff --git a/gcc/testsuite/obj-c++.dg/class-extension-3.mm b/gcc/testsuite/obj-c++.dg/class-extension-3.mm index 69e5705..bed8490 100644 --- a/gcc/testsuite/obj-c++.dg/class-extension-3.mm +++ b/gcc/testsuite/obj-c++.dg/class-extension-3.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This test tests warnings on class extensions. */ diff --git a/gcc/testsuite/obj-c++.dg/class-extension-4.mm b/gcc/testsuite/obj-c++.dg/class-extension-4.mm index 9e19aa7..2cfbc5d 100644 --- a/gcc/testsuite/obj-c++.dg/class-extension-4.mm +++ b/gcc/testsuite/obj-c++.dg/class-extension-4.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This test tests you can not declare a class extension after the class @implementation. */ diff --git a/gcc/testsuite/obj-c++.dg/class-protocol-1.mm b/gcc/testsuite/obj-c++.dg/class-protocol-1.mm index 78957cb..3b33264 100644 --- a/gcc/testsuite/obj-c++.dg/class-protocol-1.mm +++ b/gcc/testsuite/obj-c++.dg/class-protocol-1.mm @@ -1,6 +1,7 @@ /* Check Class types */ /* Author: David Ayers */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include "../objc-obj-c++-shared/runtime.h" diff --git a/gcc/testsuite/obj-c++.dg/comp-types-1.mm b/gcc/testsuite/obj-c++.dg/comp-types-1.mm index 6d4e86e..6402abc 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-1.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-1.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface A + new; diff --git a/gcc/testsuite/obj-c++.dg/comp-types-10.mm b/gcc/testsuite/obj-c++.dg/comp-types-10.mm index c7f0cb6..fdfd093 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-10.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-10.mm @@ -2,6 +2,7 @@ /* { dg-do compile } */ /* { dg-prune-output ".*internal compiler error.*" } */ /* { dg-options "-O3" } */ +// { dg-additional-options "-Wno-objc-root-class" } @class NSString; @protocol NSObject diff --git a/gcc/testsuite/obj-c++.dg/comp-types-2.mm b/gcc/testsuite/obj-c++.dg/comp-types-2.mm index 0704378..87750fd 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-2.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-2.mm @@ -1,6 +1,7 @@ /* Test various ObjC types assignments and comparisons. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/comp-types-3.mm b/gcc/testsuite/obj-c++.dg/comp-types-3.mm index 2bea015..d4d0790 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-3.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-3.mm @@ -1,6 +1,7 @@ /* Test simple ObjC types casts. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/comp-types-5.mm b/gcc/testsuite/obj-c++.dg/comp-types-5.mm index 99f6772..2c4fc57 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-5.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-5.mm @@ -1,6 +1,7 @@ /* Test errors for assignments and comparisons between ObjC and C++ types. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/comp-types-6.mm b/gcc/testsuite/obj-c++.dg/comp-types-6.mm index 23b84ed..071a756 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-6.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-6.mm @@ -1,6 +1,7 @@ /* Test assignments and comparisons involving `one-off' protocols. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/comp-types-7.mm b/gcc/testsuite/obj-c++.dg/comp-types-7.mm index e235581..6286355 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-7.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-7.mm @@ -1,6 +1,7 @@ /* Test assignments and comparisons involving category protocols. */ /* Author: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/comp-types-8.mm b/gcc/testsuite/obj-c++.dg/comp-types-8.mm index 6db76bb..0221164 100644 --- a/gcc/testsuite/obj-c++.dg/comp-types-8.mm +++ b/gcc/testsuite/obj-c++.dg/comp-types-8.mm @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-additional-options "-Wno-return-type" } */ +// { dg-additional-options "-Wno-objc-root-class" } /* We used to ICE because we removed the cast to List_linked* in -[ListIndex_linked next]. */ diff --git a/gcc/testsuite/obj-c++.dg/demangle-2.mm b/gcc/testsuite/obj-c++.dg/demangle-2.mm index f282085..14c7b3e 100644 --- a/gcc/testsuite/obj-c++.dg/demangle-2.mm +++ b/gcc/testsuite/obj-c++.dg/demangle-2.mm @@ -1,6 +1,7 @@ /* Test demangling an Objective-C method. */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include diff --git a/gcc/testsuite/obj-c++.dg/demangle-3.mm b/gcc/testsuite/obj-c++.dg/demangle-3.mm index afb83d7..d8d8178 100644 --- a/gcc/testsuite/obj-c++.dg/demangle-3.mm +++ b/gcc/testsuite/obj-c++.dg/demangle-3.mm @@ -1,6 +1,7 @@ /* Test demangling an Objective-C method in error messages. */ /* { dg-do compile } */ /* { dg-additional-options "-Wno-return-type" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm b/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm index 3a5e510..77e52c6 100644 --- a/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm +++ b/gcc/testsuite/obj-c++.dg/duplicate-class-1.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* Test that a duplicated @implementation for the same class does not crash the compiler. */ diff --git a/gcc/testsuite/obj-c++.dg/encode-1-next.mm b/gcc/testsuite/obj-c++.dg/encode-1-next.mm index 47673f2..854dd72 100644 --- a/gcc/testsuite/obj-c++.dg/encode-1-next.mm +++ b/gcc/testsuite/obj-c++.dg/encode-1-next.mm @@ -5,6 +5,7 @@ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } struct Cxx { const struct Cxx *next; diff --git a/gcc/testsuite/obj-c++.dg/encode-1.mm b/gcc/testsuite/obj-c++.dg/encode-1.mm index 5f5ba20..6247c64 100644 --- a/gcc/testsuite/obj-c++.dg/encode-1.mm +++ b/gcc/testsuite/obj-c++.dg/encode-1.mm @@ -3,6 +3,7 @@ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } struct Cxx { const struct Cxx *next; diff --git a/gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm b/gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm index 31c2e50..5964dfb 100644 --- a/gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm +++ b/gcc/testsuite/obj-c++.dg/enhanced-proto-2.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @protocol MyProto1 @optional diff --git a/gcc/testsuite/obj-c++.dg/exceptions-1.mm b/gcc/testsuite/obj-c++.dg/exceptions-1.mm index 0f3b7e8..75327ef 100644 --- a/gcc/testsuite/obj-c++.dg/exceptions-1.mm +++ b/gcc/testsuite/obj-c++.dg/exceptions-1.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This test checks the syntax @catch (...) which catches any exceptions. At the moment, @catch (...) is identical to @catch (id diff --git a/gcc/testsuite/obj-c++.dg/exceptions-3.mm b/gcc/testsuite/obj-c++.dg/exceptions-3.mm index 622e4ca..7cf77a7 100644 --- a/gcc/testsuite/obj-c++.dg/exceptions-3.mm +++ b/gcc/testsuite/obj-c++.dg/exceptions-3.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* Test that the compiler is checking the argument of @catch(), and produce errors when invalid types are used. */ diff --git a/gcc/testsuite/obj-c++.dg/exceptions-4.mm b/gcc/testsuite/obj-c++.dg/exceptions-4.mm index 4aa00a6..1391c43 100644 --- a/gcc/testsuite/obj-c++.dg/exceptions-4.mm +++ b/gcc/testsuite/obj-c++.dg/exceptions-4.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* Test warnings when parsing syntax errors in @catch(). */ diff --git a/gcc/testsuite/obj-c++.dg/exceptions-5.mm b/gcc/testsuite/obj-c++.dg/exceptions-5.mm index 5aa08f3..4547a75 100644 --- a/gcc/testsuite/obj-c++.dg/exceptions-5.mm +++ b/gcc/testsuite/obj-c++.dg/exceptions-5.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* Test that you can use an unnamed argument with @catch. This test is the same as exceptions-3.mm, but with no name for @catch arguments. */ diff --git a/gcc/testsuite/obj-c++.dg/extern-c-1.mm b/gcc/testsuite/obj-c++.dg/extern-c-1.mm index c5fec6f..8b9147a 100644 --- a/gcc/testsuite/obj-c++.dg/extern-c-1.mm +++ b/gcc/testsuite/obj-c++.dg/extern-c-1.mm @@ -1,5 +1,6 @@ /* Test extern c support inside @implementation */ /* Devang Patel . */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/fobjc-std-1.mm b/gcc/testsuite/obj-c++.dg/fobjc-std-1.mm index 59db950..f7f4a19 100644 --- a/gcc/testsuite/obj-c++.dg/fobjc-std-1.mm +++ b/gcc/testsuite/obj-c++.dg/fobjc-std-1.mm @@ -1,6 +1,7 @@ /* Test warnings when using -fobjc-std=objc1. */ /* { dg-do compile } */ /* { dg-options "-fobjc-std=objc1" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm index bdaef98..92852c3 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm @@ -21,6 +21,7 @@ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm index ae39026..f6e3d8d 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm @@ -8,6 +8,7 @@ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm index 1c85d23..991edc7 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm index 97bf84b..07c3a22 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm index 201ab7e..e68e7a8 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm @@ -9,6 +9,7 @@ systems that don't have the V2 APis). XFAILing the run is not useful since it will XPASS on the sub-set that works. */ /* { dg-skip-if "Incompatible" { *-*-darwin* } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm index dcbf6d2..1fb56dc 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc_msg_lookup.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm index a2702d6..4d99053 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm index 953e9bb..601f39f 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm @@ -4,6 +4,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm index 9a2ceca..21ae06b 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm index f8a54d3..dc311324 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-resolve-method.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm index ff50058..dd8ff3e 100644 --- a/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm +++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm @@ -4,6 +4,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* To get the modern GNU Objective-C Runtime API, you include objc/runtime.h. */ diff --git a/gcc/testsuite/obj-c++.dg/invalid-method-2.mm b/gcc/testsuite/obj-c++.dg/invalid-method-2.mm index e3a8ed1..8eee0ff 100644 --- a/gcc/testsuite/obj-c++.dg/invalid-method-2.mm +++ b/gcc/testsuite/obj-c++.dg/invalid-method-2.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* Test that using an invalid type in a method declaration produces a friendly error without a compiler crash. */ diff --git a/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm b/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm index 4c1480a..974e919 100644 --- a/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm +++ b/gcc/testsuite/obj-c++.dg/ivar-invalid-type-1.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include @interface MyRootClass diff --git a/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm b/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm index 4ed5afa..1736f9c 100644 --- a/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm +++ b/gcc/testsuite/obj-c++.dg/ivar-problem-1.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This test checks what happens if there are 16 instance variables. In that case, the class was not created correctly. In this testcase, diff --git a/gcc/testsuite/obj-c++.dg/lto/lto.exp b/gcc/testsuite/obj-c++.dg/lto/lto.exp index 6ba5f9c..936872a 100644 --- a/gcc/testsuite/obj-c++.dg/lto/lto.exp +++ b/gcc/testsuite/obj-c++.dg/lto/lto.exp @@ -41,10 +41,10 @@ if { ![check_effective_target_lto] } { global LTO_OPTIONS set LTO_OPTIONS [list \ - {-O0 -flto -fgnu-runtime} \ - {-O2 -flto -fgnu-runtime} \ - {-O0 -flto -flto-partition=none -fgnu-runtime} \ - {-O2 -flto -flto-partition=none -fgnu-runtime} \ + {-O0 -flto -fgnu-runtime -Wno-objc-root-class} \ + {-O2 -flto -fgnu-runtime -Wno-objc-root-class} \ + {-O0 -flto -flto-partition=none -fgnu-runtime -Wno-objc-root-class} \ + {-O2 -flto -flto-partition=none -fgnu-runtime -Wno-objc-root-class} \ ] obj-c++_init @@ -67,10 +67,10 @@ foreach src $tests { # darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { set LTO_OPTIONS [list \ - {-O0 -flto -fnext-runtime} \ - {-O2 -flto -fnext-runtime} \ - {-O0 -flto -flto-partition=none -fnext-runtime} \ - {-O2 -flto -flto-partition=none -fnext-runtime} \ + {-O0 -flto -fnext-runtime -Wno-objc-root-class} \ + {-O2 -flto -fnext-runtime -Wno-objc-root-class} \ + {-O0 -flto -flto-partition=none -fnext-runtime -Wno-objc-root-class} \ + {-O2 -flto -flto-partition=none -fnext-runtime -Wno-objc-root-class} \ ] foreach src $tests { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm b/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm index 55f62f0..c3620c3 100644 --- a/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm +++ b/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm @@ -1,5 +1,5 @@ /* { dg-lto-do run } */ -/* { dg-skip-if "Needs OBJC2 ABI" { "*-*-darwin*" && lp64 } } */ + extern "C" { extern int printf (const char *,...) ; extern void abort (void) ; diff --git a/gcc/testsuite/obj-c++.dg/method-1.mm b/gcc/testsuite/obj-c++.dg/method-1.mm index 7317ae2..5bb851a 100644 --- a/gcc/testsuite/obj-c++.dg/method-1.mm +++ b/gcc/testsuite/obj-c++.dg/method-1.mm @@ -3,6 +3,7 @@ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/method-12.mm b/gcc/testsuite/obj-c++.dg/method-12.mm index 4546144..d3145ab 100644 --- a/gcc/testsuite/obj-c++.dg/method-12.mm +++ b/gcc/testsuite/obj-c++.dg/method-12.mm @@ -3,6 +3,7 @@ /* { dg-options "-Wstrict-selector-match" } */ /* { dg-do compile } */ /* { dg-skip-if "Object interface removed" { *-*-darwin[1-2]* && { lp64 } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/method-18.mm b/gcc/testsuite/obj-c++.dg/method-18.mm index 411caac..c753f33 100644 --- a/gcc/testsuite/obj-c++.dg/method-18.mm +++ b/gcc/testsuite/obj-c++.dg/method-18.mm @@ -1,5 +1,6 @@ /* Contributed by Igor Seleznev . */ /* This used to be broken. */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/method-19.mm b/gcc/testsuite/obj-c++.dg/method-19.mm index 225beca..a3b977e 100644 --- a/gcc/testsuite/obj-c++.dg/method-19.mm +++ b/gcc/testsuite/obj-c++.dg/method-19.mm @@ -4,6 +4,7 @@ /* Author: Ziemowit Laski . */ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include "../objc-obj-c++-shared/runtime.h" diff --git a/gcc/testsuite/obj-c++.dg/method-20.mm b/gcc/testsuite/obj-c++.dg/method-20.mm index 9698225..a7fe41d 100644 --- a/gcc/testsuite/obj-c++.dg/method-20.mm +++ b/gcc/testsuite/obj-c++.dg/method-20.mm @@ -2,6 +2,7 @@ used as method selectors. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface Foo - (void)insertNewButtonImage:(Foo *)newButtonImage in:(Foo *)buttonCell; diff --git a/gcc/testsuite/obj-c++.dg/method-3.mm b/gcc/testsuite/obj-c++.dg/method-3.mm index 9dab8c5..17b0c99 100644 --- a/gcc/testsuite/obj-c++.dg/method-3.mm +++ b/gcc/testsuite/obj-c++.dg/method-3.mm @@ -3,6 +3,7 @@ /* { dg-do compile } */ /* { dg-options "-Wno-strict-selector-match" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/method-4.mm b/gcc/testsuite/obj-c++.dg/method-4.mm index e94f8f1..1f2f93e 100644 --- a/gcc/testsuite/obj-c++.dg/method-4.mm +++ b/gcc/testsuite/obj-c++.dg/method-4.mm @@ -3,6 +3,7 @@ /* { dg-do compile } */ /* { dg-options "-Wstrict-selector-match" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/method-5.mm b/gcc/testsuite/obj-c++.dg/method-5.mm index 17c841a4..10364cc 100644 --- a/gcc/testsuite/obj-c++.dg/method-5.mm +++ b/gcc/testsuite/obj-c++.dg/method-5.mm @@ -3,6 +3,7 @@ /* { dg-do compile } */ /* { dg-options "-Wno-strict-selector-match" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/method-8.mm b/gcc/testsuite/obj-c++.dg/method-8.mm index cde1bc2..9c5c17a 100644 --- a/gcc/testsuite/obj-c++.dg/method-8.mm +++ b/gcc/testsuite/obj-c++.dg/method-8.mm @@ -1,5 +1,6 @@ /* Tests of duplication. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface class1 - (int) meth1; /* { dg-message "previous declaration" } */ diff --git a/gcc/testsuite/obj-c++.dg/method-9.mm b/gcc/testsuite/obj-c++.dg/method-9.mm index 787e25d..bee076e 100644 --- a/gcc/testsuite/obj-c++.dg/method-9.mm +++ b/gcc/testsuite/obj-c++.dg/method-9.mm @@ -1,6 +1,7 @@ /* Test for lookup of class (factory) methods. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface MyBase - (void) rootInstanceMethod; diff --git a/gcc/testsuite/obj-c++.dg/method-namespace-1.mm b/gcc/testsuite/obj-c++.dg/method-namespace-1.mm index 6095f57..86006a7 100644 --- a/gcc/testsuite/obj-c++.dg/method-namespace-1.mm +++ b/gcc/testsuite/obj-c++.dg/method-namespace-1.mm @@ -1,5 +1,6 @@ /* Test for usage of namespace inside @implementation. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface MyDocument @end diff --git a/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm b/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm index 988b290..128b3bd 100644 --- a/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm +++ b/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm @@ -1,6 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O -fdiagnostics-show-caret" } */ /* { dg-excess-errors "tree range 0:0-0:0" { target { *-*-darwin* } } } */ +// { dg-additional-options "-Wno-objc-root-class" } /* This file is similar to diagnostic-test-expressions-1.c (see the notes in that file); this file adds test diff --git a/gcc/testsuite/obj-c++.dg/pr23709.mm b/gcc/testsuite/obj-c++.dg/pr23709.mm index 018b53a..7936956 100644 --- a/gcc/testsuite/obj-c++.dg/pr23709.mm +++ b/gcc/testsuite/obj-c++.dg/pr23709.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface A +(void)method: (int)parameter {} /* { dg-error "expected" } */ diff --git a/gcc/testsuite/obj-c++.dg/pragma-2.mm b/gcc/testsuite/obj-c++.dg/pragma-2.mm index 14c4d79..09feac7 100644 --- a/gcc/testsuite/obj-c++.dg/pragma-2.mm +++ b/gcc/testsuite/obj-c++.dg/pragma-2.mm @@ -1,5 +1,6 @@ /* It is OK to use #pragma inside @implementation body. This test checks that. */ /* Ziemowit Laski . */ +// { dg-additional-options "-Wno-objc-root-class" } @interface A { diff --git a/gcc/testsuite/obj-c++.dg/private-1.mm b/gcc/testsuite/obj-c++.dg/private-1.mm index 0c25aea..2173b90 100644 --- a/gcc/testsuite/obj-c++.dg/private-1.mm +++ b/gcc/testsuite/obj-c++.dg/private-1.mm @@ -1,6 +1,7 @@ /* Test errors for accessing @private and @protected variables. */ /* Based on work by: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include @interface MySuperClass diff --git a/gcc/testsuite/obj-c++.dg/private-2.mm b/gcc/testsuite/obj-c++.dg/private-2.mm index 3e6ff11..93b8a8f 100644 --- a/gcc/testsuite/obj-c++.dg/private-2.mm +++ b/gcc/testsuite/obj-c++.dg/private-2.mm @@ -2,6 +2,7 @@ /* Based on work by: Nicola Pero . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/property/property.exp b/gcc/testsuite/obj-c++.dg/property/property.exp index d18f610..31e683c 100644 --- a/gcc/testsuite/obj-c++.dg/property/property.exp +++ b/gcc/testsuite/obj-c++.dg/property/property.exp @@ -31,12 +31,12 @@ dg-init set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] # Main loop. -dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS +dg-runtest $tests "-fgnu-runtime -Wno-objc-root-class" $DEFAULT_OBJCXXFLAGS # Darwin targets can also run code with the NeXT runtime. # but Properties are not supported by the runtime lib before Darwin 9. if [istarget "*-*-darwin\[9123\]*" ] { - dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS + dg-runtest $tests "-fnext-runtime -Wno-objc-root-class" $DEFAULT_OBJCXXFLAGS } # All done. diff --git a/gcc/testsuite/obj-c++.dg/proto-lossage-1.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-1.mm index 2f7eb98..82cd053 100644 --- a/gcc/testsuite/obj-c++.dg/proto-lossage-1.mm +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-1.mm @@ -2,6 +2,7 @@ may be lost, leading to superfluous warnings. */ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* One-line substitute for objc/objc.h */ typedef struct objc_object { struct objc_class *class_pointer; } *id; diff --git a/gcc/testsuite/obj-c++.dg/proto-lossage-5.mm b/gcc/testsuite/obj-c++.dg/proto-lossage-5.mm index 35c0956..2a30bc2 100644 --- a/gcc/testsuite/obj-c++.dg/proto-lossage-5.mm +++ b/gcc/testsuite/obj-c++.dg/proto-lossage-5.mm @@ -1,5 +1,6 @@ /* Do not lose references to forward-declared protocols. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @class MyBaseClass; @class MyClassThatFails; @protocol _MyProtocol; diff --git a/gcc/testsuite/obj-c++.dg/proto-qual-1.mm b/gcc/testsuite/obj-c++.dg/proto-qual-1.mm index 7ef0e9a..b235064 100644 --- a/gcc/testsuite/obj-c++.dg/proto-qual-1.mm +++ b/gcc/testsuite/obj-c++.dg/proto-qual-1.mm @@ -3,6 +3,7 @@ /* { dg-do run } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include diff --git a/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm b/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm index 5241b29..c505c00 100644 --- a/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm +++ b/gcc/testsuite/obj-c++.dg/protocol-inheritance-1.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ /* { dg-options "-Wno-protocol" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm b/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm index 74c9174..f2bc1ca 100644 --- a/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm +++ b/gcc/testsuite/obj-c++.dg/protocol-inheritance-2.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/protocol-optional-1.mm b/gcc/testsuite/obj-c++.dg/protocol-optional-1.mm index bc4a3d0..4ecf436 100644 --- a/gcc/testsuite/obj-c++.dg/protocol-optional-1.mm +++ b/gcc/testsuite/obj-c++.dg/protocol-optional-1.mm @@ -1,5 +1,6 @@ /* Contributed by Nicola Pero , November 2010. */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/selector-1.mm b/gcc/testsuite/obj-c++.dg/selector-1.mm index d34f8c8..b0cdc9c 100644 --- a/gcc/testsuite/obj-c++.dg/selector-1.mm +++ b/gcc/testsuite/obj-c++.dg/selector-1.mm @@ -3,6 +3,7 @@ /* Author: Ziemowit Laski . */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface Int1 + (int)and_eq:(int)arg1 and:(int)arg2; diff --git a/gcc/testsuite/obj-c++.dg/selector-2.mm b/gcc/testsuite/obj-c++.dg/selector-2.mm index 840ee19..fa9ab41 100644 --- a/gcc/testsuite/obj-c++.dg/selector-2.mm +++ b/gcc/testsuite/obj-c++.dg/selector-2.mm @@ -1,6 +1,7 @@ /* Test that we don't ICE when issuing a -Wselector warning. */ /* { dg-options "-Wselector" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } #include diff --git a/gcc/testsuite/obj-c++.dg/selector-3.mm b/gcc/testsuite/obj-c++.dg/selector-3.mm index a1321a7..0c98056 100644 --- a/gcc/testsuite/obj-c++.dg/selector-3.mm +++ b/gcc/testsuite/obj-c++.dg/selector-3.mm @@ -2,6 +2,7 @@ /* This is the "-fgnu-runtime" variant of objc.dg/selector-1.m. */ /* { dg-options "-Wselector -fgnu-runtime" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } typedef struct objc_object { struct objc_class *class_pointer; } *id; typedef const struct objc_selector *SEL; diff --git a/gcc/testsuite/obj-c++.dg/selector-4.mm b/gcc/testsuite/obj-c++.dg/selector-4.mm index 690cc44..b6ddcbe 100644 --- a/gcc/testsuite/obj-c++.dg/selector-4.mm +++ b/gcc/testsuite/obj-c++.dg/selector-4.mm @@ -3,6 +3,7 @@ /* { dg-options "-Wselector -fnext-runtime" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } typedef struct objc_object { struct objc_class *class_pointer; } *id; typedef struct objc_selector *SEL; diff --git a/gcc/testsuite/obj-c++.dg/strings/strings.exp b/gcc/testsuite/obj-c++.dg/strings/strings.exp index 1bfb3be..0243f24 100644 --- a/gcc/testsuite/obj-c++.dg/strings/strings.exp +++ b/gcc/testsuite/obj-c++.dg/strings/strings.exp @@ -34,11 +34,11 @@ dg-init set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] # Main loop. -dg-runtest $tests "-fgnu-runtime" $DEFAULT_OBJCXXFLAGS +dg-runtest $tests "-fgnu-runtime -Wno-objc-root-class" $DEFAULT_OBJCXXFLAGS # darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { - dg-runtest $tests "-fnext-runtime" $DEFAULT_OBJCXXFLAGS + dg-runtest $tests "-fnext-runtime -Wno-objc-root-class" $DEFAULT_OBJCXXFLAGS } # All done. diff --git a/gcc/testsuite/obj-c++.dg/stubify-1.mm b/gcc/testsuite/obj-c++.dg/stubify-1.mm index a32e282..21de463 100644 --- a/gcc/testsuite/obj-c++.dg/stubify-1.mm +++ b/gcc/testsuite/obj-c++.dg/stubify-1.mm @@ -5,6 +5,7 @@ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-require-effective-target ilp32 } */ /* { dg-options "-Os -mdynamic-no-pic -fno-exceptions -mmacosx-version-min=10.4 -msymbol-stubs" } */ +// { dg-additional-options "-Wno-objc-root-class" } typedef struct objc_object { } *id ; int x = 41 ; diff --git a/gcc/testsuite/obj-c++.dg/stubify-2.mm b/gcc/testsuite/obj-c++.dg/stubify-2.mm index 69fea8d..cbc52b1 100644 --- a/gcc/testsuite/obj-c++.dg/stubify-2.mm +++ b/gcc/testsuite/obj-c++.dg/stubify-2.mm @@ -5,6 +5,7 @@ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ /* { dg-require-effective-target ilp32 } */ /* { dg-options "-mdynamic-no-pic -fdump-rtl-jump -mmacosx-version-min=10.4 -msymbol-stubs" } */ +// { dg-additional-options "-Wno-objc-root-class" } typedef struct objc_object { } *id ; int x = 41 ; diff --git a/gcc/testsuite/obj-c++.dg/super-dealloc-1.mm b/gcc/testsuite/obj-c++.dg/super-dealloc-1.mm index 0ab177b..39ddd01 100644 --- a/gcc/testsuite/obj-c++.dg/super-dealloc-1.mm +++ b/gcc/testsuite/obj-c++.dg/super-dealloc-1.mm @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface Foo { void *isa; diff --git a/gcc/testsuite/obj-c++.dg/super-dealloc-2.mm b/gcc/testsuite/obj-c++.dg/super-dealloc-2.mm index 80dcf49..6dac31c 100644 --- a/gcc/testsuite/obj-c++.dg/super-dealloc-2.mm +++ b/gcc/testsuite/obj-c++.dg/super-dealloc-2.mm @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface Foo { void *isa; diff --git a/gcc/testsuite/obj-c++.dg/sync-3.mm b/gcc/testsuite/obj-c++.dg/sync-3.mm index 95def43..2949d6a 100644 --- a/gcc/testsuite/obj-c++.dg/sync-3.mm +++ b/gcc/testsuite/obj-c++.dg/sync-3.mm @@ -1,6 +1,7 @@ /* Contributed by Nicola Pero , December 2010. */ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } /* Test that the compiler is checking the argument of @synchronized(), and produce errors when invalid types are used. */ diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-2.mm b/gcc/testsuite/obj-c++.dg/syntax-error-2.mm index ba8804a..bf4d5ff 100644 --- a/gcc/testsuite/obj-c++.dg/syntax-error-2.mm +++ b/gcc/testsuite/obj-c++.dg/syntax-error-2.mm @@ -1,4 +1,5 @@ /* Recover gracefully from a syntax error. */ +// { dg-additional-options "-Wno-objc-root-class" } @implementation Whatever /* { dg-warning "cannot find interface declaration for .Whatever." } */ diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-4.mm b/gcc/testsuite/obj-c++.dg/syntax-error-4.mm index 0df0618..97587f9 100644 --- a/gcc/testsuite/obj-c++.dg/syntax-error-4.mm +++ b/gcc/testsuite/obj-c++.dg/syntax-error-4.mm @@ -1,5 +1,6 @@ /* Yet another stray infinite loop... */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface t { diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-7.mm b/gcc/testsuite/obj-c++.dg/syntax-error-7.mm index 5bdccc7..c406d8f 100644 --- a/gcc/testsuite/obj-c++.dg/syntax-error-7.mm +++ b/gcc/testsuite/obj-c++.dg/syntax-error-7.mm @@ -1,4 +1,5 @@ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface Foo -(void) someMethod; diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-9.mm b/gcc/testsuite/obj-c++.dg/syntax-error-9.mm index 1876c32..ad8837c 100644 --- a/gcc/testsuite/obj-c++.dg/syntax-error-9.mm +++ b/gcc/testsuite/obj-c++.dg/syntax-error-9.mm @@ -1,3 +1,4 @@ +// { dg-additional-options "-Wno-objc-root-class" } @implementation SaturnDoc /* { dg-warning "cannot find interface declaration" } */ - read: (void*)aStream ggg /* { dg-error "expected .:. at end of input" } */ /* { dg-error "-:expected ..*. at end of input" "" { target *-*-* } .+1 } */ diff --git a/gcc/testsuite/obj-c++.dg/template-4.mm b/gcc/testsuite/obj-c++.dg/template-4.mm index 5301df5..02795e7 100644 --- a/gcc/testsuite/obj-c++.dg/template-4.mm +++ b/gcc/testsuite/obj-c++.dg/template-4.mm @@ -4,6 +4,7 @@ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ /* { dg-options "-mno-constant-cfstrings" { target *-*-darwin* } } */ /* { dg-additional-sources "../objc-obj-c++-shared/nsconstantstring-class-impl.mm" } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include diff --git a/gcc/testsuite/obj-c++.dg/template-7.mm b/gcc/testsuite/obj-c++.dg/template-7.mm index 8621abe..b3697a5 100644 --- a/gcc/testsuite/obj-c++.dg/template-7.mm +++ b/gcc/testsuite/obj-c++.dg/template-7.mm @@ -3,6 +3,7 @@ // Author: Fariborz Jahanian // { dg-do compile } // { dg-options "" } +// { dg-additional-options "-Wno-objc-root-class" } typedef struct objc_class *Class; @interface Object diff --git a/gcc/testsuite/obj-c++.dg/template-8.mm b/gcc/testsuite/obj-c++.dg/template-8.mm index df215b8..1b9f4d1 100644 --- a/gcc/testsuite/obj-c++.dg/template-8.mm +++ b/gcc/testsuite/obj-c++.dg/template-8.mm @@ -5,6 +5,7 @@ /* { dg-do run } */ /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include diff --git a/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm b/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm index c481810..32f4fd8 100644 --- a/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm +++ b/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm @@ -3,6 +3,7 @@ /* { dg-do run { target *-*-darwin* } } */ /* { dg-require-effective-target ilp32 } */ /* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +// { dg-additional-options "-Wno-objc-root-class" } #include #include diff --git a/gcc/testsuite/obj-c++.dg/torture/dg-torture.exp b/gcc/testsuite/obj-c++.dg/torture/dg-torture.exp index c3d3f8e..4e46207 100644 --- a/gcc/testsuite/obj-c++.dg/torture/dg-torture.exp +++ b/gcc/testsuite/obj-c++.dg/torture/dg-torture.exp @@ -7,11 +7,11 @@ dg-init # Gather a list of all tests. set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] -obj-c++-dg-runtest $tests "" "-fgnu-runtime" +obj-c++-dg-runtest $tests "" "-fgnu-runtime -Wno-objc-root-class" # darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { - obj-c++-dg-runtest $tests "" "-fnext-runtime" + obj-c++-dg-runtest $tests "" "-fnext-runtime -Wno-objc-root-class" } dg-finish diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/strings.exp b/gcc/testsuite/obj-c++.dg/torture/strings/strings.exp index 401bc58..6181c30 100644 --- a/gcc/testsuite/obj-c++.dg/torture/strings/strings.exp +++ b/gcc/testsuite/obj-c++.dg/torture/strings/strings.exp @@ -24,11 +24,11 @@ dg-init # Gather a list of all tests. set tests [lsort [glob -nocomplain $srcdir/$subdir/*.mm]] -obj-c++-dg-runtest $tests "" "-fgnu-runtime" +obj-c++-dg-runtest $tests "" "-fgnu-runtime -Wno-objc-root-class" # Darwin targets can also run code with the NeXT runtime. if [istarget "*-*-darwin*" ] { - obj-c++-dg-runtest $tests "" "-fnext-runtime" + obj-c++-dg-runtest $tests "" "-fnext-runtime -Wno-objc-root-class" } dg-finish diff --git a/gcc/testsuite/obj-c++.dg/try-catch-12.mm b/gcc/testsuite/obj-c++.dg/try-catch-12.mm index e08f321..6a60805 100644 --- a/gcc/testsuite/obj-c++.dg/try-catch-12.mm +++ b/gcc/testsuite/obj-c++.dg/try-catch-12.mm @@ -4,6 +4,7 @@ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } typedef volatile int IOSharedLockData; diff --git a/gcc/testsuite/obj-c++.dg/try-catch-13.mm b/gcc/testsuite/obj-c++.dg/try-catch-13.mm index 050d811..0e6f01b 100644 --- a/gcc/testsuite/obj-c++.dg/try-catch-13.mm +++ b/gcc/testsuite/obj-c++.dg/try-catch-13.mm @@ -4,6 +4,7 @@ /* { dg-options "-fobjc-exceptions" } */ /* { dg-do compile } */ +// { dg-additional-options "-Wno-objc-root-class" } @interface TestMyTests - (void) testSpoon; -- cgit v1.1 From 5e28fca09c9c72bf5631efd0f0b06d52b0ebdb4d Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 25 Oct 2020 19:33:07 +0000 Subject: C-Family, Objective-C : Implement Objective-C nullability Part 1[PR90707]. This part of the implementation covers property nullability attributes and includes the changes to common code. Follow-on changes will be needed to cover Objective-C method definitions, but those are expected to be local to the Objective-C front end. The basis of the implementation is to translate the Objective-C-specific keywords into an attribute (objc_nullability) which has the required states to carry the attribute markup. We introduce the keywords, and these are parsed and validated in the same manner as other property attributes. The resulting value is attached to the property as an objc_nullability attribute. gcc/c-family/ChangeLog: PR objc/90707 * c-common.c (c_common_reswords): null_unspecified, nullable, nonnull, null_resettable: New keywords. * c-common.h (enum rid): RID_NULL_UNSPECIFIED, RID_NULLABLE, RID_NONNULL, RID_NULL_RESETTABLE: New. (OBJC_IS_PATTR_KEYWORD): Include nullability keywords in the ranges accepted for property attributes. * c-attribs.c (handle_objc_nullability_attribute): New. * c-objc.h (enum objc_property_attribute_group): Add OBJC_PROPATTR_GROUP_NULLABLE. (enum objc_property_attribute_kind):Add OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED, OBJC_PROPERTY_ATTR_NULLABLE, OBJC_PROPERTY_ATTR_NONNULL, OBJC_PROPERTY_ATTR_NULL_RESETTABLE. gcc/objc/ChangeLog: PR objc/90707 * objc-act.c (objc_prop_attr_kind_for_rid): Handle nullability. (objc_add_property_declaration): Handle nullability attributes. Check that these are applicable to the property type. * objc-act.h (enum objc_property_nullability): New. gcc/testsuite/ChangeLog: PR objc/90707 * obj-c++.dg/property/at-property-4.mm: Add basic nullability tests. * objc.dg/property/at-property-4.m: Likewise. * obj-c++.dg/attributes/nullability-00.mm: New test. * obj-c++.dg/property/nullability-00.mm: New test. * objc.dg/attributes/nullability-00.m: New test. * objc.dg/property/nullability-00.m: New test. gcc/ChangeLog: PR objc/90707 * doc/extend.texi: Document the objc_nullability attribute. --- gcc/c-family/c-attribs.c | 49 +++++++++++++++++++++ gcc/c-family/c-common.c | 6 +++ gcc/c-family/c-common.h | 7 ++- gcc/c-family/c-objc.h | 5 +++ gcc/doc/extend.texi | 27 ++++++++++++ gcc/objc/objc-act.c | 51 +++++++++++++++++++++- gcc/objc/objc-act.h | 10 +++++ .../obj-c++.dg/attributes/nullability-00.mm | 20 +++++++++ gcc/testsuite/obj-c++.dg/property/at-property-4.mm | 20 ++++++++- .../obj-c++.dg/property/nullability-00.mm | 21 +++++++++ gcc/testsuite/objc.dg/attributes/nullability-00.m | 20 +++++++++ gcc/testsuite/objc.dg/property/at-property-4.m | 18 ++++++++ gcc/testsuite/objc.dg/property/nullability-00.m | 21 +++++++++ 13 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm create mode 100644 gcc/testsuite/obj-c++.dg/property/nullability-00.mm create mode 100644 gcc/testsuite/objc.dg/attributes/nullability-00.m create mode 100644 gcc/testsuite/objc.dg/property/nullability-00.m (limited to 'gcc') diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 24bcd70..abdc32e 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -159,6 +159,7 @@ static tree handle_patchable_function_entry_attribute (tree *, tree, tree, static tree handle_copy_attribute (tree *, tree, tree, int, bool *); static tree handle_nsobject_attribute (tree *, tree, tree, int, bool *); static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *); +static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -516,6 +517,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_nsobject_attribute, NULL }, { "objc_root_class", 0, 0, true, false, false, false, handle_objc_root_class_attribute, NULL }, + { "objc_nullability", 1, 1, true, false, false, false, + handle_objc_nullability_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -5182,6 +5185,52 @@ handle_objc_root_class_attribute (tree */*node*/, tree name, tree /*args*/, return NULL_TREE; } +/* Handle an "objc_nullability" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_objc_nullability_attribute (tree *node, tree name, tree args, + int /*flags*/, + bool *no_add_attrs) +{ + *no_add_attrs = true; + + tree type = TREE_TYPE (*node); + if (TREE_CODE (*node) == FUNCTION_DECL) + type = TREE_TYPE (type); + + if (type && !POINTER_TYPE_P (type)) + { + error ("%qE cannot be applied to non-pointer type %qT", name, type); + return NULL_TREE; + } + + /* We accept objc_nullability() with a single argument. + string: "unspecified", "nullable", "nonnull" or "resettable" + integer: 0 and 3 where the values have the same meaning as + the strings. */ + tree val = TREE_VALUE (args); + if (TREE_CODE (val) == INTEGER_CST) + { + val = default_conversion (val); + if (!tree_fits_uhwi_p (val) || tree_to_uhwi (val) > 3) + error ("%qE attribute argument %qE is not an integer constant" + " between 0 and 3", name, val); + else + *no_add_attrs = false; /* OK */ + } + else if (TREE_CODE (val) == STRING_CST + && (strcmp (TREE_STRING_POINTER (val), "nullable") == 0 + || strcmp (TREE_STRING_POINTER (val), "nonnull") == 0 + || strcmp (TREE_STRING_POINTER (val), "unspecified") == 0 + || strcmp (TREE_STRING_POINTER (val), "resettable") == 0)) + *no_add_attrs = false; /* OK */ + else if (val != error_mark_node) + error ("%qE attribute argument %qE is not recognised", name, val); + + return NULL_TREE; +} + /* Attempt to partially validate a single attribute ATTR as if it were to be applied to an entity OPER. */ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 29508bc..ab7f642 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -580,6 +580,12 @@ const struct c_common_resword c_common_reswords[] = { "readwrite", RID_READWRITE, D_OBJC }, { "retain", RID_RETAIN, D_OBJC }, { "setter", RID_SETTER, D_OBJC }, + /* These are Objective C implementation of nullability, accepted only in + specific contexts. */ + { "null_unspecified", RID_NULL_UNSPECIFIED, D_OBJC }, + { "nullable", RID_NULLABLE, D_OBJC }, + { "nonnull", RID_NONNULL, D_OBJC }, + { "null_resettable", RID_NULL_RESETTABLE, D_OBJC }, }; const unsigned int num_c_common_reswords = diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index f470974..3c50897 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -87,6 +87,11 @@ enum rid RID_ASSIGN, RID_RETAIN, RID_COPY, RID_PROPATOMIC, RID_NONATOMIC, + /* ObjC nullability support keywords that also can appear in the + property attribute context. These values should remain contiguous + with the other property attributes. */ + RID_NULL_UNSPECIFIED, RID_NULLABLE, RID_NONNULL, RID_NULL_RESETTABLE, + /* C (reserved and imaginary types not implemented, so any use is a syntax error) */ RID_IMAGINARY, @@ -264,7 +269,7 @@ enum rid RID_FIRST_PQ = RID_IN, RID_LAST_PQ = RID_ONEWAY, RID_FIRST_PATTR = RID_GETTER, - RID_LAST_PATTR = RID_NONATOMIC + RID_LAST_PATTR = RID_NULL_RESETTABLE }; #define OBJC_IS_AT_KEYWORD(rid) \ diff --git a/gcc/c-family/c-objc.h b/gcc/c-family/c-objc.h index 9414aec..4b50260 100644 --- a/gcc/c-family/c-objc.h +++ b/gcc/c-family/c-objc.h @@ -44,6 +44,7 @@ enum objc_property_attribute_group OBJC_PROPATTR_GROUP_READWRITE, OBJC_PROPATTR_GROUP_ASSIGN, OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPATTR_GROUP_NULLABLE, OBJC_PROPATTR_GROUP_CLASS, OBJC_PROPATTR_GROUP_MAX }; @@ -60,6 +61,10 @@ enum objc_property_attribute_kind OBJC_PROPERTY_ATTR_COPY = ( 7 << 8)|OBJC_PROPATTR_GROUP_ASSIGN, OBJC_PROPERTY_ATTR_ATOMIC = ( 8 << 8)|OBJC_PROPATTR_GROUP_ATOMIC, OBJC_PROPERTY_ATTR_NONATOMIC = ( 9 << 8)|OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED = (12 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, + OBJC_PROPERTY_ATTR_NULLABLE = (13 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, + OBJC_PROPERTY_ATTR_NONNULL = (14 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, + OBJC_PROPERTY_ATTR_NULL_RESETTABLE = (15 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, OBJC_PROPERTY_ATTR_CLASS = (16 << 8)|OBJC_PROPATTR_GROUP_CLASS, OBJC_PROPERTY_ATTR_MAX = (255 << 8|OBJC_PROPATTR_GROUP_MAX) }; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index c353eb4..4e5197f 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7429,6 +7429,33 @@ data in this way can reduce program startup times. This attribute is specific to ELF targets and relies on the linker to place such data in the right location +@item objc_nullability (@var{nullability kind}) @r{(Objective-C and Objective +-C++ only)} +@cindex @code{objc_nullability} variable attribute +This attribute applies to pointer variables only. It allows marking the +pointer with one of four possible values describing the conditions under +which the pointer might have a @code{nil} value. In most cases, the +attribute is intended to be an internal representation for property and +method nullability (specified by language keywords); it is not recommended +to use it directly. + +When @var{nullability kind} is @code{"unspecified"} or @code{0}, nothing is +known about the conditions in which the pointer might be @code{nil}. Making +this state specific serves to avoid false positives in diagnostics. + +When @var{nullability kind} is @code{"nonnull"} or @code{1}, the pointer has +no meaning if it is @code{nil} and thus the compiler is free to emit +diagnostics if it can be determined that the value will be @code{nil}. + +When @var{nullability kind} is @code{"nullable"} or @code{2}, the pointer might +be @code{nil} and carry meaning as such. + +When @var{nullability kind} is @code{"resettable"} or @code{3} (used only in +the context of property attribute lists) this describes the case in which a +property setter may take the value @code{nil} (which perhaps causes the +property to be reset in some manner to a default) but for which the property +getter will never validly return @code{nil}. + @end table @node ARC Variable Attributes diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index e410386..2700bbe 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -825,6 +825,11 @@ objc_prop_attr_kind_for_rid (enum rid prop_rid) case RID_PROPATOMIC: return OBJC_PROPERTY_ATTR_ATOMIC; case RID_NONATOMIC: return OBJC_PROPERTY_ATTR_NONATOMIC; + case RID_NULL_UNSPECIFIED:return OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED; + case RID_NULLABLE: return OBJC_PROPERTY_ATTR_NULLABLE; + case RID_NONNULL: return OBJC_PROPERTY_ATTR_NONNULL; + case RID_NULL_RESETTABLE: return OBJC_PROPERTY_ATTR_NULL_RESETTABLE; + case RID_CLASS: return OBJC_PROPERTY_ATTR_CLASS; } } @@ -995,6 +1000,27 @@ objc_add_property_declaration (location_t location, tree decl, property_nonatomic = attrs[OBJC_PROPATTR_GROUP_CLASS]->prop_kind == OBJC_PROPERTY_ATTR_CLASS; + /* Nullability specifications for the property. */ + enum objc_property_nullability property_nullability + = OBJC_PROPERTY_NULL_UNSET; + if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]) + { + if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED) + property_nullability = OBJC_PROPERTY_NULL_UNSPECIFIED; + else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NULLABLE) + property_nullability = OBJC_PROPERTY_NULLABLE; + else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NONNULL) + property_nullability = OBJC_PROPERTY_NONNULL; + else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NULL_RESETTABLE) + property_nullability = OBJC_PROPERTY_NULL_RESETTABLE; + else + gcc_unreachable (); + } + /* TODO: Check that the property type is an Objective-C object or a "POD". */ @@ -1272,7 +1298,8 @@ objc_add_property_declaration (location_t location, tree decl, tree property_decl = make_node (PROPERTY_DECL); /* Copy the basic information from the original decl. */ - TREE_TYPE (property_decl) = TREE_TYPE (decl); + tree p_type = TREE_TYPE (decl); + TREE_TYPE (property_decl) = p_type; DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl); TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (decl); @@ -1287,6 +1314,28 @@ objc_add_property_declaration (location_t location, tree decl, PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; + /* FIXME: We seem to drop any existing DECL_ATTRIBUTES on the floor. */ + if (property_nullability != OBJC_PROPERTY_NULL_UNSET) + { + if (p_type && !POINTER_TYPE_P (p_type)) + error_at (decl_loc, "nullability specifier %qE cannot be applied to" + " non-pointer type %qT", + attrs[OBJC_PROPATTR_GROUP_NULLABLE]->name, p_type); + else if (p_type && POINTER_TYPE_P (p_type) && TREE_TYPE (p_type) + && POINTER_TYPE_P (TREE_TYPE (p_type))) + error_at (decl_loc, "nullability specifier %qE cannot be applied to" + " multi-level pointer type %qT", + attrs[OBJC_PROPATTR_GROUP_NULLABLE]->name, p_type); + else + { + tree attr_name = get_identifier ("objc_nullability"); + tree attr_value = build_int_cst (unsigned_type_node, + (unsigned)property_nullability); + tree nulla = build_tree_list (attr_name, attr_value); + DECL_ATTRIBUTES (property_decl) = nulla; + } + } + /* Remember the fact that the property was found in the @optional section in a @protocol, or not. */ if (objc_method_optional_flag) diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 5b0433f..2fe409db 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -141,6 +141,16 @@ enum objc_property_assign_semantics { #define PROPERTY_CLASS(DECL) \ DECL_LANG_FLAG_6 (PROPERTY_DECL_CHECK (DECL)) +/* PROPERTY_NULLABILITY attributes added to the decl attributes. + effectively, __attribute__((objc_nullability(kind))), */ +enum objc_property_nullability { + OBJC_PROPERTY_NULL_UNSPECIFIED = 0, + OBJC_PROPERTY_NULLABLE, + OBJC_PROPERTY_NONNULL, + OBJC_PROPERTY_NULL_RESETTABLE, + OBJC_PROPERTY_NULL_UNSET +}; + /* PROPERTY_REF. A PROPERTY_REF represents an 'object.property' expression. It is normally used for property access, but when the Objective-C 2.0 "dot-syntax" (object.component) is used diff --git a/gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm b/gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm new file mode 100644 index 0000000..957fca4 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class -fsyntax-only" } */ + +__attribute__((objc_nullability(0))) id a; +__attribute__((objc_nullability(4))) id e_1; /* { dg-error {'objc_nullability' attribute argument '4' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability(-22))) id e_2; /* { dg-error {'objc_nullability' attribute argument '-22' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability("unspecified"))) id b; +__attribute__((objc_nullability("nullable"))) id c; +__attribute__((objc_nullability("nonnull"))) id d; +__attribute__((objc_nullability("resettable"))) id e; +__attribute__((objc_nullability("nonsense"))) id e_3; /* { dg-error {'objc_nullability' attribute argument '"nonsense"' is not recognised} } */ +__attribute__((objc_nullability(noGoingToWork))) id e_4; /* { dg-error {'noGoingToWork' was not declared in this scope} } */ + +@interface MyRoot +{ + __attribute__((objc_nullability(0))) id iv_a; + __attribute__((objc_nullability(3))) struct { int bad_a; } s;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type ''} } */ + __attribute__((objc_nullability("resettable"))) int iv_b;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type 'int'} } */ +} +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm index f73d706..f589354 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm @@ -26,12 +26,17 @@ @property (class) int property_cl_1; +@property (null_unspecified) int *property_null_1; +@property (nullable) int *property_null_2; +@property (nonnull) int *property_null_3; +@property (null_resettable) int *property_null_4; + @property (release) int property_err_1; /* { dg-error "unknown property attribute" } */ @property (getter=myGetter) int property_g0; @property (setter=mySetter:) int property_s0; -/* Now test various problems. */ +/* Now test various basic problems. */ @property (readonly, readwrite) int a; /* { dg-error ".readwrite. attribute conflicts with .readonly. attribute" } */ @property (readonly, setter=mySetterB:) int b; /* { dg-error ".readonly. attribute conflicts with .setter. attribute" } */ @@ -42,6 +47,19 @@ @property (atomic, nonatomic) int property_j; /* { dg-error {'nonatomic' attribute conflicts with 'atomic' attribute} } */ +@property (null_unspecified) int property_bad_t_1; /* { dg-error {nullability specifier 'null_unspecified' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int property_bad_t_2;/* { dg-error {nullability specifier 'nullable' cannot be applied to non-pointer type 'int'} } */ +@property (nonnull) int property_bad_t_3;/* { dg-error {nullability specifier 'nonnull' cannot be applied to non-pointer type 'int'} } */ +@property (null_resettable) int property_bad_t_4;/* { dg-error {nullability specifier 'null_resettable' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int **property_bad_t_5;/* { dg-error {nullability specifier 'nullable' cannot be applied to multi-level pointer type 'int\*\*'} } */ + +@property (null_unspecified, nullable) int *property_ne_1; /* { dg-error {'nullable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, nonnull) int *property_ne_2; /* { dg-error {'nonnull' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, null_resettable) int *property_ne_3; /* { dg-error {'null_resettable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (nullable,nonnull) int *property_ne_4; /* { dg-error {'nonnull' attribute conflicts with 'nullable' attribute} } */ +@property (nullable,null_resettable) int *property_ne_5; /* { dg-error {'null_resettable' attribute conflicts with 'nullable' attribute} } */ +@property (nonnull, null_resettable) int *property_ne_6; /* { dg-error {'null_resettable' attribute conflicts with 'nonnull' attribute} } */ + @property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-warning {multiple property 'setter' methods specified, the latest one will be used} } */ @property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-warning {multiple property 'getter' methods specified, the latest one will be used} } */ diff --git a/gcc/testsuite/obj-c++.dg/property/nullability-00.mm b/gcc/testsuite/obj-c++.dg/property/nullability-00.mm new file mode 100644 index 0000000..9b0c808 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/nullability-00.mm @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fsyntax-only" } */ + +@interface MyRoot +{ + Class isa __attribute__((deprecated)); + id p; + int x; + int *i; +} + +@property(null_unspecified, assign) MyRoot *p1; +@property(nonnull, assign) MyRoot *p2; +@property(nullable, assign) MyRoot *p3; +@property(null_resettable, assign) MyRoot *p4; +@property(null_exciting, assign) MyRoot *e_5; /* { dg-error {unknown property attribute 'null_exciting'} } */ + +@property(nonnull, retain, nullable) MyRoot *e_6; /* { dg-error {'nullable' attribute conflicts with 'nonnull' attribute} } */ +@property(nonnull, nonnull) int *i; /* { dg-warning {duplicate 'nonnull' attribute} } */ + +@end diff --git a/gcc/testsuite/objc.dg/attributes/nullability-00.m b/gcc/testsuite/objc.dg/attributes/nullability-00.m new file mode 100644 index 0000000..81c0145 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/nullability-00.m @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class -fsyntax-only" } */ + +__attribute__((objc_nullability(0))) id a; +__attribute__((objc_nullability(4))) id e_1; /* { dg-error {'objc_nullability' attribute argument '4' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability(-22))) id e_2; /* { dg-error {'objc_nullability' attribute argument '-22' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability("unspecified"))) id b; +__attribute__((objc_nullability("nullable"))) id c; +__attribute__((objc_nullability("nonnull"))) id d; +__attribute__((objc_nullability("resettable"))) id e; +__attribute__((objc_nullability("nonsense"))) id e_3; /* { dg-error {'objc_nullability' attribute argument '"nonsense"' is not recognised} } */ +__attribute__((objc_nullability(noGoingToWork))) id e_4; /* { dg-error {'noGoingToWork' undeclared here} } */ + +@interface MyRoot +{ + __attribute__((objc_nullability(0))) id iv_a; + __attribute__((objc_nullability(3))) struct { int bad_a; } s;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type 'struct '} } */ + __attribute__((objc_nullability("resettable"))) int iv_b;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type 'int'} } */ +} +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-4.m b/gcc/testsuite/objc.dg/property/at-property-4.m index 0e905db..04da34e 100644 --- a/gcc/testsuite/objc.dg/property/at-property-4.m +++ b/gcc/testsuite/objc.dg/property/at-property-4.m @@ -26,6 +26,11 @@ @property (class) int property_cl_1; +@property (null_unspecified) int *property_null_1; +@property (nullable) int *property_null_2; +@property (nonnull) int *property_null_3; +@property (null_resettable) int *property_null_4; + @property (release) int property_err_1; /* { dg-error "unknown property attribute" } */ @property (getter=myGetter) int property_h; @@ -42,6 +47,19 @@ @property (atomic, nonatomic) int property_j; /* { dg-error {'nonatomic' attribute conflicts with 'atomic' attribute} } */ +@property (null_unspecified) int property_bad_t_1; /* { dg-error {nullability specifier 'null_unspecified' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int property_bad_t_2;/* { dg-error {nullability specifier 'nullable' cannot be applied to non-pointer type 'int'} } */ +@property (nonnull) int property_bad_t_3;/* { dg-error {nullability specifier 'nonnull' cannot be applied to non-pointer type 'int'} } */ +@property (null_resettable) int property_bad_t_4;/* { dg-error {nullability specifier 'null_resettable' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int **property_bad_t_5;/* { dg-error {nullability specifier 'nullable' cannot be applied to multi-level pointer type 'int \*\*'} } */ + +@property (null_unspecified, nullable) int *property_ne_1; /* { dg-error {'nullable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, nonnull) int *property_ne_2; /* { dg-error {'nonnull' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, null_resettable) int *property_ne_3; /* { dg-error {'null_resettable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (nullable,nonnull) int *property_ne_4; /* { dg-error {'nonnull' attribute conflicts with 'nullable' attribute} } */ +@property (nullable,null_resettable) int *property_ne_5; /* { dg-error {'null_resettable' attribute conflicts with 'nullable' attribute} } */ +@property (nonnull, null_resettable) int *property_ne_6; /* { dg-error {'null_resettable' attribute conflicts with 'nonnull' attribute} } */ + @property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-warning {multiple property 'setter' methods specified, the latest one will be used} } */ @property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-warning {multiple property 'getter' methods specified, the latest one will be used} } */ diff --git a/gcc/testsuite/objc.dg/property/nullability-00.m b/gcc/testsuite/objc.dg/property/nullability-00.m new file mode 100644 index 0000000..9b0c808 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/nullability-00.m @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fsyntax-only" } */ + +@interface MyRoot +{ + Class isa __attribute__((deprecated)); + id p; + int x; + int *i; +} + +@property(null_unspecified, assign) MyRoot *p1; +@property(nonnull, assign) MyRoot *p2; +@property(nullable, assign) MyRoot *p3; +@property(null_resettable, assign) MyRoot *p4; +@property(null_exciting, assign) MyRoot *e_5; /* { dg-error {unknown property attribute 'null_exciting'} } */ + +@property(nonnull, retain, nullable) MyRoot *e_6; /* { dg-error {'nullable' attribute conflicts with 'nonnull' attribute} } */ +@property(nonnull, nonnull) int *i; /* { dg-warning {duplicate 'nonnull' attribute} } */ + +@end -- cgit v1.1 From 54bbde550ec557e48a67ca1f4036e46710bcfeda Mon Sep 17 00:00:00 2001 From: Sudakshina Das Date: Fri, 13 Nov 2020 10:48:27 +0000 Subject: aarch64: Add backend support for expanding __builtin_memset This patch implements aarch64 backend expansion for __builtin_memset. Most of the implementation is based on the expansion of __builtin_memcpy. We change the values of SET_RATIO and MOVE_RATIO for cases where we do not have to strictly align and where we can benefit from NEON instructions in the backend. gcc/ChangeLog: * config/aarch64/aarch64-protos.h (aarch64_expand_setmem): New declaration. * config/aarch64/aarch64.c (aarch64_gen_store_pair): Add case for E_V16QImode. (aarch64_set_one_block_and_progress_pointer): New helper for aarch64_expand_setmem. (aarch64_expand_setmem): Define the expansion for memset. * config/aarch64/aarch64.h (CLEAR_RATIO): Tweak to favor aarch64_expand_setmem when allowed and profitable. (SET_RATIO): Likewise. * config/aarch64/aarch64.md: Define pattern for setmemdi. gcc/testsuite/ChangeLog: * g++.dg/tree-ssa/pr90883.C: Remove xfail for aarch64. * gcc.dg/tree-prof/stringop-2.c: Add xfail for aarch64. * gcc.target/aarch64/memset-corner-cases.c: New test. * gcc.target/aarch64/memset-q-reg.c: New test. --- gcc/config/aarch64/aarch64-protos.h | 1 + gcc/config/aarch64/aarch64.c | 132 +++++++++++++++++++++ gcc/config/aarch64/aarch64.h | 17 +-- gcc/config/aarch64/aarch64.md | 18 +++ gcc/testsuite/g++.dg/tree-ssa/pr90883.C | 4 +- gcc/testsuite/gcc.dg/tree-prof/stringop-2.c | 4 +- .../gcc.target/aarch64/memset-corner-cases.c | 88 ++++++++++++++ gcc/testsuite/gcc.target/aarch64/memset-q-reg.c | 81 +++++++++++++ 8 files changed, 334 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c create mode 100644 gcc/testsuite/gcc.target/aarch64/memset-q-reg.c (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 7a34c84..2aa3f1f 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -510,6 +510,7 @@ bool aarch64_emit_approx_div (rtx, rtx, rtx); bool aarch64_emit_approx_sqrt (rtx, rtx, bool); void aarch64_expand_call (rtx, rtx, rtx, bool); bool aarch64_expand_cpymem (rtx *); +bool aarch64_expand_setmem (rtx *); bool aarch64_float_const_zero_rtx_p (rtx); bool aarch64_float_const_rtx_p (rtx); bool aarch64_function_arg_regno_p (unsigned); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 97cb689..0e572ba 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -7030,6 +7030,9 @@ aarch64_gen_store_pair (machine_mode mode, rtx mem1, rtx reg1, rtx mem2, case E_V4SImode: return gen_vec_store_pairv4siv4si (mem1, reg1, mem2, reg2); + case E_V16QImode: + return gen_vec_store_pairv16qiv16qi (mem1, reg1, mem2, reg2); + default: gcc_unreachable (); } @@ -21276,6 +21279,135 @@ aarch64_expand_cpymem (rtx *operands) return true; } +/* Like aarch64_copy_one_block_and_progress_pointers, except for memset where + SRC is a register we have created with the duplicated value to be set. */ +static void +aarch64_set_one_block_and_progress_pointer (rtx src, rtx *dst, + machine_mode mode) +{ + /* If we are copying 128bits or 256bits, we can do that straight from + the SIMD register we prepared. */ + if (known_eq (GET_MODE_BITSIZE (mode), 256)) + { + mode = GET_MODE (src); + /* "Cast" the *dst to the correct mode. */ + *dst = adjust_address (*dst, mode, 0); + /* Emit the memset. */ + emit_insn (aarch64_gen_store_pair (mode, *dst, src, + aarch64_progress_pointer (*dst), src)); + + /* Move the pointers forward. */ + *dst = aarch64_move_pointer (*dst, 32); + return; + } + if (known_eq (GET_MODE_BITSIZE (mode), 128)) + { + /* "Cast" the *dst to the correct mode. */ + *dst = adjust_address (*dst, GET_MODE (src), 0); + /* Emit the memset. */ + emit_move_insn (*dst, src); + /* Move the pointers forward. */ + *dst = aarch64_move_pointer (*dst, 16); + return; + } + /* For copying less, we have to extract the right amount from src. */ + rtx reg = lowpart_subreg (mode, src, GET_MODE (src)); + + /* "Cast" the *dst to the correct mode. */ + *dst = adjust_address (*dst, mode, 0); + /* Emit the memset. */ + emit_move_insn (*dst, reg); + /* Move the pointer forward. */ + *dst = aarch64_progress_pointer (*dst); +} + +/* Expand setmem, as if from a __builtin_memset. Return true if + we succeed, otherwise return false. */ + +bool +aarch64_expand_setmem (rtx *operands) +{ + int n, mode_bits; + unsigned HOST_WIDE_INT len; + rtx dst = operands[0]; + rtx val = operands[2], src; + rtx base; + machine_mode cur_mode = BLKmode, next_mode; + + /* We can't do anything smart if the amount to copy is not constant. */ + if (!CONST_INT_P (operands[1])) + return false; + + bool speed_p = !optimize_function_for_size_p (cfun); + + /* Default the maximum to 256-bytes. */ + unsigned max_set_size = 256; + + /* In case we are optimizing for size or if the core does not + want to use STP Q regs, lower the max_set_size. */ + max_set_size = (!speed_p + || (aarch64_tune_params.extra_tuning_flags + & AARCH64_EXTRA_TUNE_NO_LDP_STP_QREGS)) + ? max_set_size / 2 : max_set_size; + + len = INTVAL (operands[1]); + + /* Upper bound check. */ + if (len > max_set_size) + return false; + + base = copy_to_mode_reg (Pmode, XEXP (dst, 0)); + dst = adjust_automodify_address (dst, VOIDmode, base, 0); + + /* Prepare the val using a DUP/MOVI v0.16B, val. */ + src = expand_vector_broadcast (V16QImode, val); + src = force_reg (V16QImode, src); + + /* Convert len to bits to make the rest of the code simpler. */ + n = len * BITS_PER_UNIT; + + /* Maximum amount to copy in one go. We allow 256-bit chunks based on the + AARCH64_EXTRA_TUNE_NO_LDP_STP_QREGS tuning parameter. setmem expand + pattern is only turned on for TARGET_SIMD. */ + const int copy_limit = (speed_p + && (aarch64_tune_params.extra_tuning_flags + & AARCH64_EXTRA_TUNE_NO_LDP_STP_QREGS)) + ? GET_MODE_BITSIZE (TImode) : 256; + + while (n > 0) + { + /* Find the largest mode in which to do the copy without + over writing. */ + opt_scalar_int_mode mode_iter; + FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT) + if (GET_MODE_BITSIZE (mode_iter.require ()) <= MIN (n, copy_limit)) + cur_mode = mode_iter.require (); + + gcc_assert (cur_mode != BLKmode); + + mode_bits = GET_MODE_BITSIZE (cur_mode).to_constant (); + aarch64_set_one_block_and_progress_pointer (src, &dst, cur_mode); + + n -= mode_bits; + + /* Do certain trailing copies as overlapping if it's going to be + cheaper. i.e. less instructions to do so. For instance doing a 15 + byte copy it's more efficient to do two overlapping 8 byte copies than + 8 + 4 + 2 + 1. */ + if (n > 0 && n < copy_limit / 2) + { + next_mode = smallest_mode_for_size (n, MODE_INT); + int n_bits = GET_MODE_BITSIZE (next_mode).to_constant (); + gcc_assert (n_bits <= mode_bits); + dst = aarch64_move_pointer (dst, (n - n_bits) / BITS_PER_UNIT); + n = n_bits; + } + } + + return true; +} + + /* Split a DImode store of a CONST_INT SRC to MEM DST as two SImode stores. Handle the case when the constant has identical bottom and top halves. This is beneficial when the two stores can be diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 00b5f84..d241c5b 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -1024,16 +1024,19 @@ typedef struct #define MOVE_RATIO(speed) \ (!STRICT_ALIGNMENT ? 2 : (((speed) ? 15 : AARCH64_CALL_RATIO) / 2)) -/* For CLEAR_RATIO, when optimizing for size, give a better estimate - of the length of a memset call, but use the default otherwise. */ +/* Like MOVE_RATIO, without -mstrict-align, make decisions in "setmem" when + we would use more than 3 scalar instructions. + Otherwise follow a sensible default: when optimizing for size, give a better + estimate of the length of a memset call, but use the default otherwise. */ #define CLEAR_RATIO(speed) \ - ((speed) ? 15 : AARCH64_CALL_RATIO) + (!STRICT_ALIGNMENT ? 4 : (speed) ? 15 : AARCH64_CALL_RATIO) -/* SET_RATIO is similar to CLEAR_RATIO, but for a non-zero constant, so when - optimizing for size adjust the ratio to account for the overhead of loading - the constant. */ +/* SET_RATIO is similar to CLEAR_RATIO, but for a non-zero constant. Without + -mstrict-align, make decisions in "setmem". Otherwise follow a sensible + default: when optimizing for size adjust the ratio to account for the + overhead of loading the constant. */ #define SET_RATIO(speed) \ - ((speed) ? 15 : AARCH64_CALL_RATIO - 2) + (!STRICT_ALIGNMENT ? 0 : (speed) ? 15 : AARCH64_CALL_RATIO - 2) /* Disable auto-increment in move_by_pieces et al. Use of auto-increment is rarely a good idea in straight-line code since it adds an extra address diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 11e0f46..eed06de 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -1571,6 +1571,24 @@ } ) +;; 0 is dst +;; 1 is val +;; 2 is size of copy in bytes +;; 3 is alignment + +(define_expand "setmemdi" + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:QI 2 "nonmemory_operand")) ;; Value + (use (match_operand:DI 1 "immediate_operand")) ;; Length + (match_operand 3 "immediate_operand")] ;; Align + "TARGET_SIMD" +{ + if (aarch64_expand_setmem (operands)) + DONE; + + FAIL; +}) + ;; Operands 1 and 3 are tied together by the final condition; so we allow ;; fairly lax checking on the second memory operation. (define_insn "load_pair_sw_" diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr90883.C b/gcc/testsuite/g++.dg/tree-ssa/pr90883.C index 0e622f2..37df17d 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr90883.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr90883.C @@ -15,6 +15,6 @@ // We want to match enough here to capture that we deleted an empty // constructor store -// aarch64 and mips will expand to loop to clear because CLEAR_RATIO. -// { dg-final { scan-tree-dump "Deleted redundant store: .*\.a = {}" "dse1" { xfail { aarch64-*-* mips*-*-* } } } } +// mips will expand to loop to clear because CLEAR_RATIO. +// { dg-final { scan-tree-dump "Deleted redundant store: .*\.a = {}" "dse1" { xfail { mips*-*-* } } } } diff --git a/gcc/testsuite/gcc.dg/tree-prof/stringop-2.c b/gcc/testsuite/gcc.dg/tree-prof/stringop-2.c index b7471bf..e8b1644 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/stringop-2.c +++ b/gcc/testsuite/gcc.dg/tree-prof/stringop-2.c @@ -20,6 +20,6 @@ main() return 0; } /* autofdo doesn't support value profiling for now: */ -/* { dg-final-use-not-autofdo { scan-ipa-dump "Transformation done: single value 4 stringop" "profile"} } */ +/* { dg-final-use-not-autofdo { scan-ipa-dump "Transformation done: single value 4 stringop" "profile" { target { ! aarch64*-*-* } } } } */ /* The versioned memset of size 4 should be optimized to an assignment. - { dg-final-use-not-autofdo { scan-tree-dump "MEM <\[a-z \]+> \\\[\\(void .\\)&a\\\] = 168430090" "optimized" } } */ + { dg-final-use-not-autofdo { scan-tree-dump "MEM <\[a-z \]+> \\\[\\(void .\\)&a\\\] = 168430090" "optimized" { target { ! aarch64*-*-* } } } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c b/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c new file mode 100644 index 0000000..c43f019 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c @@ -0,0 +1,88 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target lp64 } */ + +#include + +/* One byte variable set should be scalar +**set1byte: +** strb w1, \[x0\] +** ret +*/ +void __attribute__((__noinline__)) +set1byte (int64_t *src, char c) +{ + __builtin_memset (src, c, 1); +} + +/* Special cases for setting 0. */ +/* 1-byte should be STRB with wzr +**set0byte: +** strb wzr, \[x0\] +** ret +*/ +void __attribute__((__noinline__)) +set0byte (int64_t *src) +{ + __builtin_memset (src, 0, 1); +} + +/* 35bytes would become 4 scalar instructions. So favour NEON. +**set0neon: +** movi v0.4s, 0 +** stp q0, q0, \[x0\] +** str wzr, \[x0, 31\] +** ret +*/ +void __attribute__((__noinline__)) +set0neon (int64_t *src) +{ + __builtin_memset (src, 0, 35); +} + +/* 36bytes should be scalar however. +**set0scalar: +** stp xzr, xzr, \[x0\] +** stp xzr, xzr, \[x0, 16\] +** str wzr, \[x0, 32\] +** ret +*/ +void __attribute__((__noinline__)) +set0scalar (int64_t *src) +{ + __builtin_memset (src, 0, 36); +} + + +/* 256-bytes expanded +**set256byte: +** dup v0.16b, w1 +** stp q0, q0, \[x0\] +** stp q0, q0, \[x0, 32\] +** stp q0, q0, \[x0, 64\] +** stp q0, q0, \[x0, 96\] +** stp q0, q0, \[x0, 128\] +** stp q0, q0, \[x0, 160\] +** stp q0, q0, \[x0, 192\] +** stp q0, q0, \[x0, 224\] +** ret +*/ +void __attribute__((__noinline__)) +set256byte (int64_t *src, char c) +{ + __builtin_memset (src, c, 256); +} + +/* More than 256 bytes goes to memset +**set257byte: +** mov x2, 257 +** mov w1, 99 +** b memset +*/ +void __attribute__((__noinline__)) +set257byte (int64_t *src) +{ + __builtin_memset (src, 'c', 257); +} + +/* { dg-final { check-function-bodies "**" "" "" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/memset-q-reg.c b/gcc/testsuite/gcc.target/aarch64/memset-q-reg.c new file mode 100644 index 0000000..156146b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/memset-q-reg.c @@ -0,0 +1,81 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target lp64 } */ + +#include + +/* +**set128bits: +** dup v0.16b, w1 +** str q0, \[x0\] +** ret +*/ +void __attribute__((__noinline__)) +set128bits (int64_t *src, char c) +{ + __builtin_memset (src, c, 2*sizeof(int64_t)); +} + +/* +**set128bitszero: +** stp xzr, xzr, \[x0\] +** ret +*/ +void __attribute__((__noinline__)) +set128bitszero (int64_t *src) +{ + __builtin_memset (src, 0, 2*sizeof(int64_t)); +} + +/* +** set128bitsplus: +** dup v0.16b, w1 +** str q0, \[x0\] +** str q0, \[x0, 12\] +** ret +*/ +void __attribute__((__noinline__)) +set128bitsplus (int64_t *src, char c) +{ + __builtin_memset (src, c, 7*sizeof(int32_t)); +} + +/* +** set256bits: +** movi v0.16b, 0x63 +** stp q0, q0, \[x0\] +** ret +*/ +void __attribute__((__noinline__)) +set256bits (int64_t *src) +{ + __builtin_memset (src, 'c', 4*sizeof(int64_t)); +} + +/* +**set256bitszero: +** stp xzr, xzr, \[x0\] +** stp xzr, xzr, \[x0, 16\] +** ret +*/ +void __attribute__((__noinline__)) +set256bitszero (int64_t *src) +{ + __builtin_memset (src, 0, 4*sizeof(int64_t)); +} + +/* +** set256bitsplus: +** movi v0.16b, 0x63 +** stp q0, q0, \[x0\] +** str q0, \[x0, 32\] +** str d0, \[x0, 48\] +** ret +*/ +void __attribute__((__noinline__)) +set256bitsplus (int64_t *src) +{ + __builtin_memset (src, 'c', 7*sizeof(int64_t)); +} + +/* { dg-final { check-function-bodies "**" "" "" } } */ -- cgit v1.1 From 3793ecc10fd4f8be8abd65ba41824f3cc91238e7 Mon Sep 17 00:00:00 2001 From: Andrea Corallo Date: Tue, 10 Nov 2020 11:23:15 +0000 Subject: aarch64: Make use of RTL predicates 2020-11-10 Andrea Corallo * config/aarch64/aarch64.c (tls_symbolic_operand_type) (aarch64_load_symref_appropriately, aarch64_mov128_immediate) (aarch64_expand_mov_immediate) (aarch64_maybe_expand_sve_subreg_move) (aarch64_tls_referenced_p, aarch64_cannot_force_const_mem) (aarch64_base_register_rtx_p, aarch64_classify_index) (aarch64_classify_address, aarch64_symbolic_address_p) (aarch64_reinterpret_float_as_int, aarch64_float_const_rtx_p) (aarch64_can_const_movi_rtx_p, aarch64_select_cc_mode) (aarch64_print_operand, aarch64_label_mentioned_p) (aarch64_secondary_reload, aarch64_preferred_reload_class) (aarch64_address_cost, aarch64_tls_symbol_p) (aarch64_classify_symbol, aarch64_legitimate_pic_operand_p) (aarch64_legitimate_constant_p) (aarch64_sve_float_arith_immediate_p) (aarch64_sve_float_mul_immediate_p, aarch64_mov_operand_p) (fusion_load_store): Use RTL operands where possible. --- gcc/config/aarch64/aarch64.c | 80 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 0e572ba..6de51b5 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -2985,7 +2985,7 @@ tls_symbolic_operand_type (rtx addr) enum tls_model tls_kind = TLS_MODEL_NONE; poly_int64 offset; addr = strip_offset_and_salt (addr, &offset); - if (GET_CODE (addr) == SYMBOL_REF) + if (SYMBOL_REF_P (addr)) tls_kind = SYMBOL_REF_TLS_MODEL (addr); return tls_kind; @@ -3126,7 +3126,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, /* The operand is expected to be MEM. Whenever the related insn pattern changed, above code which calculate mem should be updated. */ - gcc_assert (GET_CODE (mem) == MEM); + gcc_assert (MEM_P (mem)); MEM_READONLY_P (mem) = 1; MEM_NOTRAP_P (mem) = 1; emit_insn (insn); @@ -3169,7 +3169,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, mem = XVECEXP (XEXP (SET_SRC (insn), 0), 0, 0); } - gcc_assert (GET_CODE (mem) == MEM); + gcc_assert (MEM_P (mem)); MEM_READONLY_P (mem) = 1; MEM_NOTRAP_P (mem) = 1; emit_insn (insn); @@ -4235,7 +4235,7 @@ aarch64_internal_mov_immediate (rtx dest, rtx imm, bool generate, bool aarch64_mov128_immediate (rtx imm) { - if (GET_CODE (imm) == CONST_INT) + if (CONST_INT_P (imm)) return true; gcc_assert (CONST_WIDE_INT_NUNITS (imm) == 2); @@ -5099,8 +5099,8 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) /* Check on what type of symbol it is. */ scalar_int_mode int_mode; - if ((GET_CODE (imm) == SYMBOL_REF - || GET_CODE (imm) == LABEL_REF + if ((SYMBOL_REF_P (imm) + || LABEL_REF_P (imm) || GET_CODE (imm) == CONST || GET_CODE (imm) == CONST_POLY_INT) && is_a (mode, &int_mode)) @@ -5390,9 +5390,9 @@ bool aarch64_maybe_expand_sve_subreg_move (rtx dest, rtx src) { gcc_assert (BYTES_BIG_ENDIAN); - if (GET_CODE (dest) == SUBREG) + if (SUBREG_P (dest)) dest = SUBREG_REG (dest); - if (GET_CODE (src) == SUBREG) + if (SUBREG_P (src)) src = SUBREG_REG (src); /* The optimization handles two single SVE REGs with different element @@ -8536,7 +8536,7 @@ aarch64_tls_referenced_p (rtx x) FOR_EACH_SUBRTX (iter, array, x, ALL) { const_rtx x = *iter; - if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0) + if (SYMBOL_REF_P (x) && SYMBOL_REF_TLS_MODEL (x) != 0) return true; /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are TLS offsets, not real symbol references. */ @@ -8762,7 +8762,7 @@ aarch64_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) poly_int64 offset; rtx base = strip_offset_and_salt (x, &offset); - if (GET_CODE (base) == SYMBOL_REF || GET_CODE (base) == LABEL_REF) + if (SYMBOL_REF_P (base) || LABEL_REF_P (base)) { /* We checked for POLY_INT_CST offsets above. */ if (aarch64_classify_symbol (base, offset.to_constant ()) @@ -8848,7 +8848,7 @@ static bool aarch64_base_register_rtx_p (rtx x, bool strict_p) { if (!strict_p - && GET_CODE (x) == SUBREG + && SUBREG_P (x) && contains_reg_of_mode[GENERAL_REGS][GET_MODE (SUBREG_REG (x))]) x = SUBREG_REG (x); @@ -8867,7 +8867,7 @@ aarch64_classify_index (struct aarch64_address_info *info, rtx x, int shift; /* (reg:P) */ - if ((REG_P (x) || GET_CODE (x) == SUBREG) + if ((REG_P (x) || SUBREG_P (x)) && GET_MODE (x) == Pmode) { type = ADDRESS_REG_REG; @@ -8965,7 +8965,7 @@ aarch64_classify_index (struct aarch64_address_info *info, rtx x, return false; if (!strict_p - && GET_CODE (index) == SUBREG + && SUBREG_P (index) && contains_reg_of_mode[GENERAL_REGS][GET_MODE (SUBREG_REG (index))]) index = SUBREG_REG (index); @@ -9261,8 +9261,8 @@ aarch64_classify_address (struct aarch64_address_info *info, { poly_int64 offset; rtx sym = strip_offset_and_salt (x, &offset); - return ((GET_CODE (sym) == LABEL_REF - || (GET_CODE (sym) == SYMBOL_REF + return ((LABEL_REF_P (sym) + || (SYMBOL_REF_P (sym) && CONSTANT_POOL_ADDRESS_P (sym) && aarch64_pcrelative_literal_loads))); } @@ -9278,7 +9278,7 @@ aarch64_classify_address (struct aarch64_address_info *info, poly_int64 offset; HOST_WIDE_INT const_offset; rtx sym = strip_offset_and_salt (info->offset, &offset); - if (GET_CODE (sym) == SYMBOL_REF + if (SYMBOL_REF_P (sym) && offset.is_constant (&const_offset) && (aarch64_classify_symbol (sym, const_offset) == SYMBOL_SMALL_ABSOLUTE)) @@ -9340,7 +9340,7 @@ aarch64_symbolic_address_p (rtx x) { poly_int64 offset; x = strip_offset_and_salt (x, &offset); - return GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF; + return SYMBOL_REF_P (x) || LABEL_REF_P (x); } /* Classify the base of symbolic expression X. */ @@ -9465,7 +9465,7 @@ aarch64_reinterpret_float_as_int (rtx value, unsigned HOST_WIDE_INT *intval) } scalar_float_mode mode; - if (GET_CODE (value) != CONST_DOUBLE + if (!CONST_DOUBLE_P (value) || !is_a (GET_MODE (value), &mode) || GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT /* Only support up to DF mode. */ @@ -9505,7 +9505,7 @@ aarch64_float_const_rtx_p (rtx x) mov/movk pairs over ldr/adrp pairs. */ unsigned HOST_WIDE_INT ival; - if (GET_CODE (x) == CONST_DOUBLE + if (CONST_DOUBLE_P (x) && SCALAR_FLOAT_MODE_P (mode) && aarch64_reinterpret_float_as_int (x, &ival)) { @@ -9544,7 +9544,7 @@ aarch64_can_const_movi_rtx_p (rtx x, machine_mode mode) scalar_int_mode imode; unsigned HOST_WIDE_INT ival; - if (GET_CODE (x) == CONST_DOUBLE + if (CONST_DOUBLE_P (x) && SCALAR_FLOAT_MODE_P (mode)) { if (!aarch64_reinterpret_float_as_int (x, &ival)) @@ -9556,7 +9556,7 @@ aarch64_can_const_movi_rtx_p (rtx x, machine_mode mode) imode = int_mode_for_mode (mode).require (); } - else if (GET_CODE (x) == CONST_INT + else if (CONST_INT_P (x) && is_a (mode, &imode)) ival = INTVAL (x); else @@ -9707,7 +9707,7 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y) the comparison will have to be swapped when we emit the assembly code. */ if ((mode_x == SImode || mode_x == DImode) - && (REG_P (y) || GET_CODE (y) == SUBREG || y == const0_rtx) + && (REG_P (y) || SUBREG_P (y) || y == const0_rtx) && (code_x == ASHIFT || code_x == ASHIFTRT || code_x == LSHIFTRT || code_x == ZERO_EXTEND || code_x == SIGN_EXTEND)) @@ -9716,7 +9716,7 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y) /* Similarly for a negated operand, but we can only do this for equalities. */ if ((mode_x == SImode || mode_x == DImode) - && (REG_P (y) || GET_CODE (y) == SUBREG) + && (REG_P (y) || SUBREG_P (y)) && (code == EQ || code == NE) && code_x == NEG) return CC_Zmode; @@ -10510,7 +10510,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) { machine_mode mode = GET_MODE (x); - if (GET_CODE (x) != MEM + if (!MEM_P (x) || (code == 'y' && maybe_ne (GET_MODE_SIZE (mode), 16))) { output_operand_lossage ("invalid operand for '%%%c'", code); @@ -10673,7 +10673,7 @@ aarch64_label_mentioned_p (rtx x) const char *fmt; int i; - if (GET_CODE (x) == LABEL_REF) + if (LABEL_REF_P (x)) return true; /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the @@ -10855,7 +10855,7 @@ aarch64_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, /* If we have to disable direct literal pool loads and stores because the function is too big, then we need a scratch register. */ - if (MEM_P (x) && GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x) + if (MEM_P (x) && SYMBOL_REF_P (x) && CONSTANT_POOL_ADDRESS_P (x) && (SCALAR_FLOAT_MODE_P (GET_MODE (x)) || targetm.vector_mode_supported_p (GET_MODE (x))) && !aarch64_pcrelative_literal_loads) @@ -11086,7 +11086,7 @@ aarch64_preferred_reload_class (rtx x, reg_class_t regclass) rtx lhs = XEXP (x, 0); /* Look through a possible SUBREG introduced by ILP32. */ - if (GET_CODE (lhs) == SUBREG) + if (SUBREG_P (lhs)) lhs = SUBREG_REG (lhs); gcc_assert (REG_P (lhs)); @@ -11546,7 +11546,7 @@ aarch64_address_cost (rtx x, if (!aarch64_classify_address (&info, x, mode, false)) { - if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF) + if (GET_CODE (x) == CONST || SYMBOL_REF_P (x)) { /* This is a CONST or SYMBOL ref which will be split in a different way depending on the code model in use. @@ -15947,7 +15947,7 @@ aarch64_tls_symbol_p (rtx x) return false; x = strip_salt (x); - if (GET_CODE (x) != SYMBOL_REF) + if (!SYMBOL_REF_P (x)) return false; return SYMBOL_REF_TLS_MODEL (x) != 0; @@ -16004,7 +16004,7 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) { x = strip_salt (x); - if (GET_CODE (x) == LABEL_REF) + if (LABEL_REF_P (x)) { switch (aarch64_cmodel) { @@ -16025,7 +16025,7 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) } } - if (GET_CODE (x) == SYMBOL_REF) + if (SYMBOL_REF_P (x)) { if (aarch64_tls_symbol_p (x)) return aarch64_classify_tls_symbol (x); @@ -16105,7 +16105,7 @@ aarch64_legitimate_pic_operand_p (rtx x) { poly_int64 offset; x = strip_offset_and_salt (x, &offset); - if (GET_CODE (x) == SYMBOL_REF) + if (SYMBOL_REF_P (x)) return false; return true; @@ -16166,7 +16166,7 @@ aarch64_legitimate_constant_p (machine_mode mode, rtx x) return true; /* Label references are always constant. */ - if (GET_CODE (x) == LABEL_REF) + if (LABEL_REF_P (x)) return true; return false; @@ -17609,7 +17609,7 @@ aarch64_sve_float_arith_immediate_p (rtx x, bool negate_p) REAL_VALUE_TYPE r; if (!const_vec_duplicate_p (x, &elt) - || GET_CODE (elt) != CONST_DOUBLE) + || !CONST_DOUBLE_P (elt)) return false; r = *CONST_DOUBLE_REAL_VALUE (elt); @@ -17633,7 +17633,7 @@ aarch64_sve_float_mul_immediate_p (rtx x) rtx elt; return (const_vec_duplicate_p (x, &elt) - && GET_CODE (elt) == CONST_DOUBLE + && CONST_DOUBLE_P (elt) && (real_equal (CONST_DOUBLE_REAL_VALUE (elt), &dconsthalf) || real_equal (CONST_DOUBLE_REAL_VALUE (elt), &dconst2))); } @@ -18052,7 +18052,7 @@ aarch64_mov_operand_p (rtx x, machine_mode mode) } x = strip_salt (x); - if (GET_CODE (x) == SYMBOL_REF && mode == DImode && CONSTANT_ADDRESS_P (x)) + if (SYMBOL_REF_P (x) && mode == DImode && CONSTANT_ADDRESS_P (x)) return true; if (TARGET_SVE && aarch64_sve_cnt_immediate_p (x)) @@ -22083,20 +22083,20 @@ fusion_load_store (rtx_insn *insn, rtx *base, rtx *offset) { fusion = SCHED_FUSION_LD_SIGN_EXTEND; src = XEXP (src, 0); - if (GET_CODE (src) != MEM || GET_MODE (src) != SImode) + if (!MEM_P (src) || GET_MODE (src) != SImode) return SCHED_FUSION_NONE; } else if (GET_CODE (src) == ZERO_EXTEND) { fusion = SCHED_FUSION_LD_ZERO_EXTEND; src = XEXP (src, 0); - if (GET_CODE (src) != MEM || GET_MODE (src) != SImode) + if (!MEM_P (src) || GET_MODE (src) != SImode) return SCHED_FUSION_NONE; } - if (GET_CODE (src) == MEM && REG_P (dest)) + if (MEM_P (src) && REG_P (dest)) extract_base_offset_in_addr (src, base, offset); - else if (GET_CODE (dest) == MEM && (REG_P (src) || src == const0_rtx)) + else if (MEM_P (dest) && (REG_P (src) || src == const0_rtx)) { fusion = SCHED_FUSION_ST; extract_base_offset_in_addr (dest, base, offset); -- cgit v1.1 From dcfd302a79a5e2ea3bb16fc4fc45a5ee31cc0eab Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 13 Nov 2020 11:31:22 +0100 Subject: tree-optimization/97812 - fix range query in VRP assert discovery This makes sure to properly extend the input range before seeing whether it fits the target. 2020-11-13 Richard Biener PR tree-optimization/97812 * tree-vrp.c (register_edge_assert_for_2): Extend the range according to its sign before seeing whether it fits. * gcc.dg/torture/pr97812.c: New testcase. --- gcc/testsuite/gcc.dg/torture/pr97812.c | 15 +++++++++++++++ gcc/tree-vrp.c | 10 ++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr97812.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/pr97812.c b/gcc/testsuite/gcc.dg/torture/pr97812.c new file mode 100644 index 0000000..4d468ad --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr97812.c @@ -0,0 +1,15 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fdisable-tree-evrp" } */ + +unsigned char c; + +int main() { +volatile short b = 4066; + unsigned short bp = b; + unsigned d = bp & 2305; + signed char e = d; + c = e ? : e; + if (!d) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 54ce017..d661866 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -1740,8 +1740,14 @@ register_edge_assert_for_2 (tree name, edge e, && ((TYPE_PRECISION (TREE_TYPE (name)) > TYPE_PRECISION (TREE_TYPE (rhs1))) || (get_range_info (rhs1, &rmin, &rmax) == VR_RANGE - && wi::fits_to_tree_p (rmin, TREE_TYPE (name)) - && wi::fits_to_tree_p (rmax, TREE_TYPE (name))))) + && wi::fits_to_tree_p + (widest_int::from (rmin, + TYPE_SIGN (TREE_TYPE (rhs1))), + TREE_TYPE (name)) + && wi::fits_to_tree_p + (widest_int::from (rmax, + TYPE_SIGN (TREE_TYPE (rhs1))), + TREE_TYPE (name))))) add_assert_info (asserts, rhs1, rhs1, comp_code, fold_convert (TREE_TYPE (rhs1), val)); } -- cgit v1.1 From 4cfa85396c69d0957eccca896bc88868aaf64073 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 13 Nov 2020 11:45:34 +0000 Subject: doc : Fix build error from r11-4972. Some tex tools don't allow the @r{} command to be split across lines. Fixed by making the change occupy a long line. gcc/ChangeLog: * doc/extend.texi: Don't try to line-wrap an @r command. --- gcc/doc/extend.texi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4e5197f..4ddbf80 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7429,8 +7429,7 @@ data in this way can reduce program startup times. This attribute is specific to ELF targets and relies on the linker to place such data in the right location -@item objc_nullability (@var{nullability kind}) @r{(Objective-C and Objective --C++ only)} +@item objc_nullability (@var{nullability kind}) @r{(Objective-C and Objective-C++ only)} @cindex @code{objc_nullability} variable attribute This attribute applies to pointer variables only. It allows marking the pointer with one of four possible values describing the conditions under -- cgit v1.1 From 5fa821bba737cf3e74801c5fe4d3e87a62aa79bf Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 13 Nov 2020 14:04:09 +0100 Subject: clang: fix -Wmisleading-indentation warning. gcc/c-family/c-attribs.c:4698:5: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation] gcc/c-family/ChangeLog: * c-attribs.c (build_attr_access_from_parms): Format properly. --- gcc/c-family/c-attribs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index abdc32e..b979fbc 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -4701,7 +4701,7 @@ build_attr_access_from_parms (tree parms, bool skip_voidptr) /* Attribute access takes a two or three arguments. Wrap VBLIST in another list in case it has more nodes than would otherwise fit. */ - vblist = build_tree_list (NULL_TREE, vblist); + vblist = build_tree_list (NULL_TREE, vblist); /* Build a single attribute access with the string describing all array arguments and an optional list of any non-parameter VLA -- cgit v1.1 From 5d4b824faf1e5846ec684a74f93912cf347928df Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Thu, 12 Nov 2020 15:37:46 +0100 Subject: d: Fix ICE in finish_thunk (PR97644) Because this what the upstream reference compiler did, thunks for the D front-end were associated with the class definition, so were forced code-gen even if the target function was extern. This has now been changed so there are now only generated if there is a function definition, fixing the ICE that occurred in PR 97644, which was caused by calling expand_thunk() early. gcc/d/ChangeLog: PR d/97644 * dmd/MERGE: Merge upstream dmd 95044d8e4. * d-target.cc (TargetCPP::thunkMangle): New function. * decl.cc (finish_thunk): Don't force expand thunks for external functions. (make_thunk): Emit thunks only if the function has a definition. Generate correct mangling for thunks to C++ classes. gcc/testsuite/ChangeLog: * gdc.dg/pr92216.d: Update scan-assember. --- gcc/d/d-target.cc | 9 +++++++ gcc/d/decl.cc | 56 ++++++++++++++++++------------------------ gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/cppmangle.c | 20 ++++++++++++++- gcc/d/dmd/mangle.h | 1 + gcc/d/dmd/target.h | 2 ++ gcc/testsuite/gdc.dg/pr92216.d | 4 +-- 7 files changed, 58 insertions(+), 36 deletions(-) (limited to 'gcc') diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 692fce6..cd136524 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -329,6 +329,15 @@ TargetCPP::typeInfoMangle (ClassDeclaration *cd) return cppTypeInfoMangleItanium (cd); } +/* Get mangle name of a this-adjusting thunk to the function declaration FD + at call offset OFFSET for C++ linkage. */ + +const char * +TargetCPP::thunkMangle (FuncDeclaration *fd, int offset) +{ + return cppThunkMangleItanium (fd, offset); +} + /* For a vendor-specific type, return a string containing the C++ mangling. In all other cases, return NULL. */ diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index d668715..218f358 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1693,26 +1693,6 @@ finish_thunk (tree thunk, tree function) if (DECL_ONE_ONLY (function)) thunk_node->add_to_same_comdat_group (funcn); - - /* Target assemble_mi_thunk doesn't work across section boundaries - on many targets, instead force thunk to be expanded in gimple. */ - if (DECL_EXTERNAL (function)) - { - /* cgraph::expand_thunk writes over current_function_decl, so if this - could ever be in use by the codegen pass, we want to know about it. */ - gcc_assert (current_function_decl == NULL_TREE); - - if (!stdarg_p (TREE_TYPE (thunk))) - { - thunk_node->create_edge (funcn, NULL, thunk_node->count); - expand_thunk (thunk_node, false, true); - } - - /* Tell the back-end to not bother inlining the function, this is - assumed not to work as it could be referencing symbols outside - of the current compilation unit. */ - DECL_UNINLINABLE (function) = 1; - } } /* Return a thunk to DECL. Thunks adjust the incoming `this' pointer by OFFSET. @@ -1789,12 +1769,11 @@ make_thunk (FuncDeclaration *decl, int offset) DECL_CONTEXT (thunk) = d_decl_context (decl); - /* Thunks inherit the public access of the function they are targetting. - When the function is outside the current compilation unit however, then the - thunk must be kept private to not conflict. */ - TREE_PUBLIC (thunk) = TREE_PUBLIC (function) && !DECL_EXTERNAL (function); - - DECL_EXTERNAL (thunk) = 0; + /* Thunks inherit the public access of the function they are targeting. + Thunks are connected to the definitions of the functions, so thunks are + not produced for external functions. */ + TREE_PUBLIC (thunk) = TREE_PUBLIC (function); + DECL_EXTERNAL (thunk) = DECL_EXTERNAL (function); /* Thunks are always addressable. */ TREE_ADDRESSABLE (thunk) = 1; @@ -1806,18 +1785,31 @@ make_thunk (FuncDeclaration *decl, int offset) DECL_COMDAT (thunk) = DECL_COMDAT (function); DECL_WEAK (thunk) = DECL_WEAK (function); - tree target_name = DECL_ASSEMBLER_NAME (function); - unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14; - const char *ident = XNEWVEC (const char, identlen); - snprintf (CONST_CAST (char *, ident), identlen, - "_DT%u%s", offset, IDENTIFIER_POINTER (target_name)); + /* When the thunk is for an extern C++ function, let C++ do the thunk + generation and just reference the symbol as extern, instead of + forcing a D local thunk to be emitted. */ + const char *ident; + + if (decl->linkage == LINKcpp) + ident = target.cpp.thunkMangle (decl, offset); + else + { + tree target_name = DECL_ASSEMBLER_NAME (function); + unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14; + ident = XNEWVEC (const char, identlen); + + snprintf (CONST_CAST (char *, ident), identlen, + "_DTi%u%s", offset, IDENTIFIER_POINTER (target_name)); + } DECL_NAME (thunk) = get_identifier (ident); SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk)); d_keep (thunk); + free (CONST_CAST (char *, ident)); - finish_thunk (thunk, function); + if (!DECL_EXTERNAL (function)) + finish_thunk (thunk, function); /* Add it to the list of thunks associated with the function. */ DECL_LANG_THUNKS (thunk) = NULL_TREE; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 39e424f..e2a0bab 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -bec5973b0203c95adbda2a049ccdf3cd3a4378f6 +95044d8e45a4320f07d9c75b4eb30e55688a8195 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c index b361d37..3f571fc 100644 --- a/gcc/d/dmd/cppmangle.c +++ b/gcc/d/dmd/cppmangle.c @@ -582,13 +582,21 @@ class CppMangleVisitor : public Visitor //printf("mangle_function(%s)\n", d->toChars()); /* * ::= _Z + */ + buf->writestring("_Z"); + this->mangle_function_encoding(d); + } + + void mangle_function_encoding(FuncDeclaration *d) + { + //printf("mangle_function_encoding(%s)\n", d->toChars()); + /* * ::= * ::= * ::= */ TypeFunction *tf = (TypeFunction *)d->type; - buf->writestring("_Z"); if (getFuncTemplateDecl(d)) { /* It's an instance of a function template @@ -1132,3 +1140,13 @@ const char *cppTypeInfoMangleItanium(Dsymbol *s) v.cpp_mangle_name(s, false); return buf.extractChars(); } + +const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset) +{ + //printf("cppThunkMangleItanium(%s)\n", fd.toChars()); + OutBuffer buf; + buf.printf("_ZThn%u_", offset); // "Th" means thunk, "n%u" is the call offset + CppMangleVisitor v(&buf, fd->loc); + v.mangle_function_encoding(fd); + return buf.extractChars(); +} diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h index 77801ab..c60f4a7 100644 --- a/gcc/d/dmd/mangle.h +++ b/gcc/d/dmd/mangle.h @@ -20,6 +20,7 @@ struct OutBuffer; // In cppmangle.c const char *toCppMangleItanium(Dsymbol *s); const char *cppTypeInfoMangleItanium(Dsymbol *s); +const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset); // In cppmanglewin.c const char *toCppMangleMSVC(Dsymbol *s); diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index c34826a..f2a55d6 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -19,6 +19,7 @@ class ClassDeclaration; class Dsymbol; class Expression; +class FuncDeclaration; class Parameter; class Type; class TypeTuple; @@ -38,6 +39,7 @@ struct TargetCPP const char *toMangle(Dsymbol *s); const char *typeInfoMangle(ClassDeclaration *cd); + const char *thunkMangle(FuncDeclaration *fd, int offset); const char *typeMangle(Type *t); Type *parameterType(Parameter *p); bool fundamentalType(const Type *t, bool& isFundamental); diff --git a/gcc/testsuite/gdc.dg/pr92216.d b/gcc/testsuite/gdc.dg/pr92216.d index 6a87025..3aff160 100644 --- a/gcc/testsuite/gdc.dg/pr92216.d +++ b/gcc/testsuite/gdc.dg/pr92216.d @@ -1,8 +1,8 @@ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92216 // { dg-options "-I $srcdir/gdc.dg" } // { dg-do compile } -// { dg-final { scan-assembler "_DT(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv\[: \t\n\]" } } -// { dg-final { scan-assembler-not "(.globl|.global)\[ \]+_DT(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv" } } +// { dg-final { scan-assembler "_DTi(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv\[: \t\n\]" } } +// { dg-final { scan-assembler-not "(.globl|.global)\[ \]+_DTi(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv" } } module pr92216; private import imports.pr92216; -- cgit v1.1 From d975d6dce98a3e26ddd304d50dad2786b3acecc4 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Fri, 13 Nov 2020 09:57:57 +0100 Subject: d: Explicitly determine which built-in copysign function to call. For some targets, mathfn_built_in returns NULL as copysign is not implicitly available, causing an ICE. Now copysign is explicitly requested when expanding the intrinsic. gcc/d/ChangeLog: * intrinsics.cc (expand_intrinsic_copysign): Explicitly determine which built-in copysign function to call. --- gcc/d/intrinsics.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc index a629472..a7de910 100644 --- a/gcc/d/intrinsics.cc +++ b/gcc/d/intrinsics.cc @@ -466,11 +466,14 @@ expand_intrinsic_copysign (tree callexp) from = fold_convert (type, from); /* Which variant of __builtin_copysign* should we call? */ - tree builtin = mathfn_built_in (type, BUILT_IN_COPYSIGN); - gcc_assert (builtin != NULL_TREE); + built_in_function code = (type == float_type_node) ? BUILT_IN_COPYSIGNF + : (type == double_type_node) ? BUILT_IN_COPYSIGN + : (type == long_double_type_node) ? BUILT_IN_COPYSIGNL + : END_BUILTINS; - return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2, - to, from); + gcc_assert (code != END_BUILTINS); + + return call_builtin_fn (callexp, code, 2, to, from); } /* Expand a front-end intrinsic call to pow(). This takes two arguments, the -- cgit v1.1 From 4d6b8d4213376e8a2405782c7e360b03d4a2b04a Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 13 Nov 2020 13:17:01 +0100 Subject: improve VN PHI hashing This reduces the number of collisions for PHIs in the VN hashtable by always hashing the number of predecessors and separately hashing the block number when we never merge PHIs from different blocks. This improves collisions seen for the PR69609 testcase dramatically. 2020-11-13 Richard Biener * tree-ssa-sccvn.c (vn_phi_compute_hash): Always hash the number of predecessors. Hash the block number also for loop header PHIs. (expressions_equal_p): Short-cut SSA name compares, remove test for NULL operands. (vn_phi_eq): Cache number of predecessors, change inlined test from expressions_equal_p. --- gcc/tree-ssa-sccvn.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 8c93e51..4d78054 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -4126,13 +4126,27 @@ vn_nary_op_insert_stmt (gimple *stmt, tree result) static inline hashval_t vn_phi_compute_hash (vn_phi_t vp1) { - inchash::hash hstate (EDGE_COUNT (vp1->block->preds) > 2 - ? vp1->block->index : EDGE_COUNT (vp1->block->preds)); + inchash::hash hstate; tree phi1op; tree type; edge e; edge_iterator ei; + hstate.add_int (EDGE_COUNT (vp1->block->preds)); + switch (EDGE_COUNT (vp1->block->preds)) + { + case 1: + break; + case 2: + if (vp1->block->loop_father->header == vp1->block) + ; + else + break; + /* Fallthru. */ + default: + hstate.add_int (vp1->block->index); + } + /* If all PHI arguments are constants we need to distinguish the PHI node via its type. */ type = vp1->type; @@ -4277,11 +4291,12 @@ vn_phi_eq (const_vn_phi_t const vp1, const_vn_phi_t const vp2) /* Any phi in the same block will have it's arguments in the same edge order, because of how we store phi nodes. */ - for (unsigned i = 0; i < EDGE_COUNT (vp1->block->preds); ++i) + unsigned nargs = EDGE_COUNT (vp1->block->preds); + for (unsigned i = 0; i < nargs; ++i) { tree phi1op = vp1->phiargs[i]; tree phi2op = vp2->phiargs[i]; - if (phi1op == VN_TOP || phi2op == VN_TOP) + if (phi1op == phi2op) continue; if (!expressions_equal_p (phi1op, phi2op)) return false; @@ -5612,8 +5627,8 @@ expressions_equal_p (tree e1, tree e2) if (e1 == VN_TOP || e2 == VN_TOP) return true; - /* If only one of them is null, they cannot be equal. */ - if (!e1 || !e2) + /* SSA_NAME compare pointer equal. */ + if (TREE_CODE (e1) == SSA_NAME || TREE_CODE (e2) == SSA_NAME) return false; /* Now perform the actual comparison. */ -- cgit v1.1 From ac91af71c93462cbc701bbd104fa21894bb15e86 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 13 Nov 2020 15:35:18 +0100 Subject: loops: Invoke lim after successful loop interchange This patch makes the entry point to loop invariant motion public, so that it can be called after loop interchange when that pass has swapped loops. This avoids the non-LTO -Ofast run-time regressions of 410.bwaves and 503.bwaves_r (which are 19% and 15% faster than current master on an AMD zen2 machine) while not introducing a full LIM pass into the pass pipeline. The patch also adds a parameter which allows not to perform any store motion so that it is not done after an interchange. gcc/ChangeLog: 2020-11-12 Martin Jambor PR tree-optimization/94406 * tree-ssa-loop-im.c (tree_ssa_lim): Renamed to loop_invariant_motion_in_fun, added a parameter to control store motion. (pass_lim::execute): Adjust call to tree_ssa_lim, now loop_invariant_motion_in_fun. * tree-ssa-loop-manip.h (loop_invariant_motion_in_fun): Declare. * gimple-loop-interchange.cc (pass_linterchange::execute): Call loop_invariant_motion_in_fun if any interchange has been done. --- gcc/gimple-loop-interchange.cc | 9 +++++++-- gcc/tree-ssa-loop-im.c | 12 +++++++----- gcc/tree-ssa-loop-manip.h | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc index 1656004..a36dbb4 100644 --- a/gcc/gimple-loop-interchange.cc +++ b/gcc/gimple-loop-interchange.cc @@ -2085,8 +2085,13 @@ pass_linterchange::execute (function *fun) } if (changed_p) - scev_reset (); - return changed_p ? (TODO_update_ssa_only_virtuals) : 0; + { + unsigned todo = TODO_update_ssa_only_virtuals; + todo |= loop_invariant_motion_in_fun (cfun, false); + scev_reset (); + return todo; + } + return 0; } } // anon namespace diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 6bb07e1..3c74127 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -3089,10 +3089,11 @@ tree_ssa_lim_finalize (void) } /* Moves invariants from loops. Only "expensive" invariants are moved out -- - i.e. those that are likely to be win regardless of the register pressure. */ + i.e. those that are likely to be win regardless of the register pressure. + Only perform store motion if STORE_MOTION is true. */ -static unsigned int -tree_ssa_lim (function *fun) +unsigned int +loop_invariant_motion_in_fun (function *fun, bool store_motion) { unsigned int todo = 0; @@ -3114,7 +3115,8 @@ tree_ssa_lim (function *fun) /* Execute store motion. Force the necessary invariants to be moved out of the loops as well. */ - do_store_motion (); + if (store_motion) + do_store_motion (); free (rpo); rpo = XNEWVEC (int, last_basic_block_for_fn (fun)); @@ -3175,7 +3177,7 @@ pass_lim::execute (function *fun) if (number_of_loops (fun) <= 1) return 0; - unsigned int todo = tree_ssa_lim (fun); + unsigned int todo = loop_invariant_motion_in_fun (fun, true); if (!in_loop_pipeline) loop_optimizer_finalize (); diff --git a/gcc/tree-ssa-loop-manip.h b/gcc/tree-ssa-loop-manip.h index e789e4f..d8e918e 100644 --- a/gcc/tree-ssa-loop-manip.h +++ b/gcc/tree-ssa-loop-manip.h @@ -55,7 +55,7 @@ extern void tree_transform_and_unroll_loop (class loop *, unsigned, extern void tree_unroll_loop (class loop *, unsigned, edge, class tree_niter_desc *); extern tree canonicalize_loop_ivs (class loop *, tree *, bool); - +extern unsigned int loop_invariant_motion_in_fun (function *, bool); #endif /* GCC_TREE_SSA_LOOP_MANIP_H */ -- cgit v1.1 From 47923622c663ffad8b14aa93706183290d4f6791 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 12 Nov 2020 11:53:52 -0500 Subject: Cleanup range of address calculations. Align EVRP and ranger for how ranges of ADDR_EXPR are calculated. gcc/ * gimple-range.cc: (gimple_ranger::range_of_range_op): Check for ADDR_EXPR and call range_of_address. (gimple_ranger::range_of_address): Rename from range_of_non_trivial_assignment and match vrp_stmt_computes_nonzero. * gimple-range.h: (range_of_address): Renamed. * range-op.cc: (pointer_table): Add INTEGER_CST handler. gcc/testsuite/ * gcc.dg/tree-ssa/pr78655.c: New. --- gcc/gimple-range.cc | 99 ++++++++++++++++++++++----------- gcc/gimple-range.h | 2 +- gcc/range-op.cc | 1 + gcc/testsuite/gcc.dg/tree-ssa/pr78655.c | 37 ++++++++++++ 4 files changed, 107 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr78655.c (limited to 'gcc') diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 92a6335..4f5d502 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -431,8 +431,9 @@ gimple_ranger::range_of_range_op (irange &r, gimple *s) m_cache.register_dependency (lhs, op2); } - if (range_of_non_trivial_assignment (r, s)) - return true; + if (gimple_code (s) == GIMPLE_ASSIGN + && gimple_assign_rhs_code (s) == ADDR_EXPR) + return range_of_address (r, s); if (range_of_expr (range1, op1, s)) { @@ -446,48 +447,84 @@ gimple_ranger::range_of_range_op (irange &r, gimple *s) return true; } -// Calculate the range of a non-trivial assignment. That is, is one -// inolving arithmetic on an SSA name (for example, an ADDR_EXPR). +// Calculate the range of an assignment containing an ADDR_EXPR. // Return the range in R. -// -// If a range cannot be calculated, return false. +// If a range cannot be calculated, set it to VARYING and return true. bool -gimple_ranger::range_of_non_trivial_assignment (irange &r, gimple *stmt) +gimple_ranger::range_of_address (irange &r, gimple *stmt) { - if (gimple_code (stmt) != GIMPLE_ASSIGN) - return false; + gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); + gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); - tree base = gimple_range_base_of_assignment (stmt); - if (base) + bool strict_overflow_p; + tree expr = gimple_assign_rhs1 (stmt); + poly_int64 bitsize, bitpos; + tree offset; + machine_mode mode; + int unsignedp, reversep, volatilep; + tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, + &bitpos, &offset, &mode, &unsignedp, + &reversep, &volatilep); + + + if (base != NULL_TREE + && TREE_CODE (base) == MEM_REF + && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) { - if (TREE_CODE (base) == MEM_REF) + tree ssa = TREE_OPERAND (base, 0); + gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa))); + range_of_expr (r, ssa, stmt); + range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt))); + + poly_offset_int off = 0; + bool off_cst = false; + if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST) { - if (TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) - { - int_range_max range1; - tree ssa = TREE_OPERAND (base, 0); - if (range_of_expr (range1, ssa, stmt)) - { - tree type = TREE_TYPE (ssa); - range_operator *op = range_op_handler (POINTER_PLUS_EXPR, - type); - int_range<2> offset (TREE_OPERAND (base, 1), - TREE_OPERAND (base, 1)); - op->fold_range (r, type, range1, offset); - return true; - } - } - return false; + off = mem_ref_offset (base); + if (offset) + off += poly_offset_int::from (wi::to_poly_wide (offset), + SIGNED); + off <<= LOG2_BITS_PER_UNIT; + off += bitpos; + off_cst = true; } - if (gimple_assign_rhs_code (stmt) == ADDR_EXPR) + /* If &X->a is equal to X, the range of X is the result. */ + if (off_cst && known_eq (off, 0)) + return true; + else if (flag_delete_null_pointer_checks + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) + { + /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't + allow going from non-NULL pointer to NULL. */ + if(!range_includes_zero_p (&r)) + return true; + } + /* If MEM_REF has a "positive" offset, consider it non-NULL + always, for -fdelete-null-pointer-checks also "negative" + ones. Punt for unknown offsets (e.g. variable ones). */ + if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) + && off_cst + && known_ne (off, 0) + && (flag_delete_null_pointer_checks || known_gt (off, 0))) { - // Handle "= &a" and return non-zero. r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } + r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; } - return false; + + // Handle "= &a". + if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p)) + { + r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; + } + + // Otherwise return varying. + r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; } // Calculate a range for phi statement S and return it in R. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 88d2ada..dde41e9 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -62,7 +62,7 @@ protected: ranger_cache m_cache; private: bool range_of_phi (irange &r, gphi *phi); - bool range_of_non_trivial_assignment (irange &r, gimple *s); + bool range_of_address (irange &r, gimple *s); bool range_of_builtin_call (irange &r, gcall *call); bool range_with_loop_info (irange &r, tree name); void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 86d1af7..b746aad 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3328,6 +3328,7 @@ pointer_table::pointer_table () set (GT_EXPR, op_gt); set (GE_EXPR, op_ge); set (SSA_NAME, op_identity); + set (INTEGER_CST, op_integer_cst); set (ADDR_EXPR, op_addr); set (NOP_EXPR, op_convert); set (CONVERT_EXPR, op_convert); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr78655.c b/gcc/testsuite/gcc.dg/tree-ssa/pr78655.c new file mode 100644 index 0000000..e9158e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr78655.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-tree-ccp -fno-tree-forwprop -fno-tree-fre -fdump-tree-evrp" } */ + +struct A{int a,b;}; +inline int*f1(struct A*p){return&p->a;} /* offset of 0. */ +inline int*f2(struct A*p){return&p->b;} /* Offset of non-zero. */ +inline int*g(struct A*p){return(int*)p+1;} /* Always non-zero offet. */ + +/* Should be able to eliminate all calls to bad(). */ + +void bad(void); + +int +main() +{ + struct A* ptr = 0; + struct A addr; + + if (f1 (ptr) != 0) + bad(); + if (f1 (&addr) == 0) + bad(); + + if (f2 (ptr) == 0) + bad(); + if (f2 (&addr) == 0) + bad(); + + if (g (ptr) == 0) + bad(); + if (g (&addr) == 0) + bad(); + +} + +/* { dg-final { scan-tree-dump-not "bad" "evrp"} } */ + -- cgit v1.1 From 156edf21fab7dd5891c72db7ec58b38ef7d52bfa Mon Sep 17 00:00:00 2001 From: Andrea Corallo Date: Fri, 13 Nov 2020 11:42:04 +0000 Subject: arm: Make use of RTL predicates 2020-11-13 Andrea Corallo * config/arm/aarch-common.c (aarch_accumulator_forwarding): Use RTL predicates where possible. * config/arm/arm.c (legitimate_pic_operand_p) (legitimize_pic_address, arm_is_segment_info_known) (can_avoid_literal_pool_for_label_p) (thumb1_legitimate_address_p, arm_legitimize_address) (arm_tls_referenced_p, thumb_legitimate_constant_p) (REG_OR_SUBREG_REG, thumb1_rtx_costs, thumb1_size_rtx_costs) (arm_adjust_cost, arm_coproc_mem_operand_wb) (neon_vector_mem_operand, neon_struct_mem_operand) (symbol_mentioned_p, label_mentioned_p, ) (load_multiple_sequence, store_multiple_sequence) (arm_select_cc_mode, arm_reload_in_hi, arm_reload_out_hi) (mem_ok_for_ldrd_strd, arm_emit_call_insn, output_move_neon) (arm_attr_length_move_neon, arm_assemble_integer) (arm_emit_coreregs_64bit_shift, arm_valid_symbolic_address_p) (extract_base_offset_in_addr, fusion_load_store): Likewise. --- gcc/config/arm/aarch-common.c | 2 +- gcc/config/arm/arm.c | 90 +++++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 46 deletions(-) (limited to 'gcc') diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c index 6bc6ccf..e7b13f0 100644 --- a/gcc/config/arm/aarch-common.c +++ b/gcc/config/arm/aarch-common.c @@ -485,7 +485,7 @@ aarch_accumulator_forwarding (rtx_insn *producer, rtx_insn *consumer) return 0; } - if (GET_CODE (accumulator) == SUBREG) + if (SUBREG_P (accumulator)) accumulator = SUBREG_REG (accumulator); if (!REG_P (accumulator)) diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 5612d1e..04190b1 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -7775,7 +7775,7 @@ arm_function_ok_for_sibcall (tree decl, tree exp) int legitimate_pic_operand_p (rtx x) { - if (GET_CODE (x) == SYMBOL_REF + if (SYMBOL_REF_P (x) || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)) @@ -7904,8 +7904,8 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg, { gcc_assert (compute_now == (pic_reg != NULL_RTX)); - if (GET_CODE (orig) == SYMBOL_REF - || GET_CODE (orig) == LABEL_REF) + if (SYMBOL_REF_P (orig) + || LABEL_REF_P (orig)) { if (reg == 0) { @@ -7922,8 +7922,8 @@ legitimize_pic_address (rtx orig, machine_mode mode, rtx reg, rtx pic_reg, /* References to weak symbols cannot be resolved locally: they may be overridden by a non-weak definition at link time. */ rtx_insn *insn; - if ((GET_CODE (orig) == LABEL_REF - || (GET_CODE (orig) == SYMBOL_REF + if ((LABEL_REF_P (orig) + || (SYMBOL_REF_P (orig) && SYMBOL_REF_LOCAL_P (orig) && (SYMBOL_REF_DECL (orig) ? !DECL_WEAK (SYMBOL_REF_DECL (orig)) : 1) @@ -8177,7 +8177,7 @@ arm_is_segment_info_known (rtx orig, bool *is_readonly) { *is_readonly = false; - if (GET_CODE (orig) == LABEL_REF) + if (LABEL_REF_P (orig)) { *is_readonly = true; return true; @@ -8437,7 +8437,7 @@ can_avoid_literal_pool_for_label_p (rtx x) (set (reg r0) (mem (reg r0))). No extra register is required, and (mem (reg r0)) won't cause the use of literal pools. */ - if (arm_disable_literal_pool && GET_CODE (x) == SYMBOL_REF + if (arm_disable_literal_pool && SYMBOL_REF_P (x) && CONSTANT_POOL_ADDRESS_P (x)) return 1; return 0; @@ -8816,7 +8816,7 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p) /* This is PC relative data before arm_reorg runs. */ else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x) - && GET_CODE (x) == SYMBOL_REF + && SYMBOL_REF_P (x) && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic && !arm_disable_literal_pool) return 1; @@ -8824,7 +8824,7 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p) /* This is PC relative data after arm_reorg runs. */ else if ((GET_MODE_SIZE (mode) >= 4 || mode == HFmode) && reload_completed - && (GET_CODE (x) == LABEL_REF + && (LABEL_REF_P (x) || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF @@ -8884,7 +8884,7 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p) else if (GET_MODE_CLASS (mode) != MODE_FLOAT && GET_MODE_SIZE (mode) == 4 - && GET_CODE (x) == SYMBOL_REF + && SYMBOL_REF_P (x) && CONSTANT_POOL_ADDRESS_P (x) && !arm_disable_literal_pool && ! (flag_pic @@ -9212,7 +9212,7 @@ arm_legitimize_address (rtx x, rtx orig_x, machine_mode mode) x = XEXP (XEXP (x, 0), 0); } - if (GET_CODE (x) != SYMBOL_REF) + if (!SYMBOL_REF_P (x)) return x; gcc_assert (SYMBOL_REF_TLS_MODEL (x) != 0); @@ -9421,7 +9421,7 @@ arm_tls_referenced_p (rtx x) FOR_EACH_SUBRTX (iter, array, x, ALL) { const_rtx x = *iter; - if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0) + if (SYMBOL_REF_P (x) && SYMBOL_REF_TLS_MODEL (x) != 0) { /* ARM currently does not provide relocations to encode TLS variables into AArch32 instructions, only data, so there is no way to @@ -9467,7 +9467,7 @@ thumb_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) return (CONST_INT_P (x) || CONST_DOUBLE_P (x) || CONSTANT_ADDRESS_P (x) - || (TARGET_HAVE_MOVT && GET_CODE (x) == SYMBOL_REF) + || (TARGET_HAVE_MOVT && SYMBOL_REF_P (x)) /* On Thumb-1 without MOVT/MOVW and literal pool disabled, we build the symbol address with upper/lower relocations. */ @@ -9511,7 +9511,7 @@ arm_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) #define REG_OR_SUBREG_REG(X) \ (REG_P (X) \ - || (GET_CODE (X) == SUBREG && REG_P (SUBREG_REG (X)))) + || (SUBREG_P (X) && REG_P (SUBREG_REG (X)))) #define REG_OR_SUBREG_RTX(X) \ (REG_P (X) ? (X) : SUBREG_REG (X)) @@ -9622,7 +9622,7 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) /* Memory costs quite a lot for the first word, but subsequent words load at the equivalent of a single insn each. */ return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) - + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) + + ((SYMBOL_REF_P (x) && CONSTANT_POOL_ADDRESS_P (x)) ? 4 : 0)); case IF_THEN_ELSE: @@ -9779,7 +9779,7 @@ thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) return (COSTS_N_INSNS (1) + COSTS_N_INSNS (1) * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) - + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) + + ((SYMBOL_REF_P (x) && CONSTANT_POOL_ADDRESS_P (x)) ? COSTS_N_INSNS (1) : 0)); case IF_THEN_ELSE: @@ -12399,7 +12399,7 @@ arm_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep, int cost, constant pool are cached, and that others will miss. This is a hack. */ - if ((GET_CODE (src_mem) == SYMBOL_REF + if ((SYMBOL_REF_P (src_mem) && CONSTANT_POOL_ADDRESS_P (src_mem)) || reg_mentioned_p (stack_pointer_rtx, src_mem) || reg_mentioned_p (frame_pointer_rtx, src_mem) @@ -13234,7 +13234,7 @@ arm_coproc_mem_operand_wb (rtx op, int wb_level) ind = XEXP (op, 0); if (reload_completed - && (GET_CODE (ind) == LABEL_REF + && (LABEL_REF_P (ind) || (GET_CODE (ind) == CONST && GET_CODE (XEXP (ind, 0)) == PLUS && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF @@ -13410,7 +13410,7 @@ neon_vector_mem_operand (rtx op, int type, bool strict) ind = XEXP (op, 0); if (reload_completed - && (GET_CODE (ind) == LABEL_REF + && (LABEL_REF_P (ind) || (GET_CODE (ind) == CONST && GET_CODE (XEXP (ind, 0)) == PLUS && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF @@ -13476,7 +13476,7 @@ neon_struct_mem_operand (rtx op) ind = XEXP (op, 0); if (reload_completed - && (GET_CODE (ind) == LABEL_REF + && (LABEL_REF_P (ind) || (GET_CODE (ind) == CONST && GET_CODE (XEXP (ind, 0)) == PLUS && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF @@ -13592,7 +13592,7 @@ symbol_mentioned_p (rtx x) const char * fmt; int i; - if (GET_CODE (x) == SYMBOL_REF) + if (SYMBOL_REF_P (x)) return 1; /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they @@ -13626,7 +13626,7 @@ label_mentioned_p (rtx x) const char * fmt; int i; - if (GET_CODE (x) == LABEL_REF) + if (LABEL_REF_P (x)) return 1; /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing @@ -14264,11 +14264,11 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order, offset = const0_rtx; if ((REG_P (reg = XEXP (operands[nops + i], 0)) - || (GET_CODE (reg) == SUBREG + || (SUBREG_P (reg) && REG_P (reg = SUBREG_REG (reg)))) || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS && ((REG_P (reg = XEXP (XEXP (operands[nops + i], 0), 0))) - || (GET_CODE (reg) == SUBREG + || (SUBREG_P (reg) && REG_P (reg = SUBREG_REG (reg)))) && (CONST_INT_P (offset = XEXP (XEXP (operands[nops + i], 0), 1))))) @@ -14418,11 +14418,11 @@ store_multiple_sequence (rtx *operands, int nops, int nops_total, offset = const0_rtx; if ((REG_P (reg = XEXP (operands[nops + i], 0)) - || (GET_CODE (reg) == SUBREG + || (SUBREG_P (reg) && REG_P (reg = SUBREG_REG (reg)))) || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS && ((REG_P (reg = XEXP (XEXP (operands[nops + i], 0), 0))) - || (GET_CODE (reg) == SUBREG + || (SUBREG_P (reg) && REG_P (reg = SUBREG_REG (reg)))) && (CONST_INT_P (offset = XEXP (XEXP (operands[nops + i], 0), 1))))) @@ -15752,7 +15752,7 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) /* A compare with a shifted operand. Because of canonicalization, the comparison will have to be swapped when we emit the assembler. */ if (GET_MODE (y) == SImode - && (REG_P (y) || (GET_CODE (y) == SUBREG)) + && (REG_P (y) || (SUBREG_P (y))) && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE || GET_CODE (x) == ROTATERT)) @@ -15776,14 +15776,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) non-canonical, but arm_gen_compare_reg uses this to generate the correct canonical form. */ if (GET_MODE (y) == SImode - && (REG_P (y) || GET_CODE (y) == SUBREG) + && (REG_P (y) || SUBREG_P (y)) && CONST_INT_P (x)) return CC_RSBmode; /* This operation is performed swapped, but since we only rely on the Z flag we don't need an additional mode. */ if (GET_MODE (y) == SImode - && (REG_P (y) || (GET_CODE (y) == SUBREG)) + && (REG_P (y) || (SUBREG_P (y))) && GET_CODE (x) == NEG && (op == EQ || op == NE)) return CC_Zmode; @@ -16175,7 +16175,7 @@ arm_reload_in_hi (rtx *operands) rtx base, scratch; HOST_WIDE_INT offset = 0; - if (GET_CODE (ref) == SUBREG) + if (SUBREG_P (ref)) { offset = SUBREG_BYTE (ref); ref = SUBREG_REG (ref); @@ -16303,7 +16303,7 @@ arm_reload_out_hi (rtx *operands) rtx base, scratch; HOST_WIDE_INT offset = 0; - if (GET_CODE (ref) == SUBREG) + if (SUBREG_P (ref)) { offset = SUBREG_BYTE (ref); ref = SUBREG_REG (ref); @@ -16634,7 +16634,7 @@ mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset, HOST_WIDE_INT *align) return false; /* Can't deal with subregs. */ - if (GET_CODE (mem) == SUBREG) + if (SUBREG_P (mem)) return false; gcc_assert (MEM_P (mem)); @@ -19534,7 +19534,7 @@ arm_emit_call_insn (rtx pat, rtx addr, bool sibcall) if (TARGET_VXWORKS_RTP && flag_pic && !sibcall - && GET_CODE (addr) == SYMBOL_REF + && SYMBOL_REF_P (addr) && (SYMBOL_REF_DECL (addr) ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr)) : !SYMBOL_REF_LOCAL_P (addr))) @@ -20381,7 +20381,7 @@ output_move_neon (rtx *operands) } else { - if (TARGET_HAVE_MVE && GET_CODE (addr) == LABEL_REF) + if (TARGET_HAVE_MVE && LABEL_REF_P (addr)) sprintf (buff, "v%sr.64\t%%P0, %%1", load ? "ld" : "st"); else sprintf (buff, "v%sr%%?\t%%P0, %%1", load ? "ld" : "st"); @@ -20392,7 +20392,7 @@ output_move_neon (rtx *operands) { ops[0] = gen_rtx_REG (DImode, REGNO (reg) + 2 * overlap); ops[1] = adjust_address (mem, SImode, 8 * overlap); - if (TARGET_HAVE_MVE && GET_CODE (addr) == LABEL_REF) + if (TARGET_HAVE_MVE && LABEL_REF_P (addr)) sprintf (buff, "v%sr.32\t%%P0, %%1", load ? "ld" : "st"); else sprintf (buff, "v%sr%%?\t%%P0, %%1", load ? "ld" : "st"); @@ -20452,7 +20452,7 @@ arm_attr_length_move_neon (rtx_insn *insn) if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS) addr = XEXP (addr, 0); - if (GET_CODE (addr) == LABEL_REF || GET_CODE (addr) == PLUS) + if (LABEL_REF_P (addr) || GET_CODE (addr) == PLUS) { int insns = REG_NREGS (reg) / 2; return insns * 4; @@ -24446,7 +24446,7 @@ arm_assemble_integer (rtx x, unsigned int size, int aligned_p) /* Mark symbols as position independent. We only do this in the .text segment, not in the .data segment. */ if (NEED_GOT_RELOC && flag_pic && making_const_table && - (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)) + (SYMBOL_REF_P (x) || LABEL_REF_P (x))) { /* See legitimize_pic_address for an explanation of the TARGET_VXWORKS_RTP check. */ @@ -24454,7 +24454,7 @@ arm_assemble_integer (rtx x, unsigned int size, int aligned_p) they may be overridden by a non-weak definition at link time. */ if (!arm_pic_data_is_text_relative - || (GET_CODE (x) == SYMBOL_REF + || (SYMBOL_REF_P (x) && (!SYMBOL_REF_LOCAL_P (x) || (SYMBOL_REF_DECL (x) ? DECL_WEAK (SYMBOL_REF_DECL (x)) : 0) @@ -31620,13 +31620,13 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in, gcc_assert (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT); gcc_assert (out - && (REG_P (out) || GET_CODE (out) == SUBREG) + && (REG_P (out) || SUBREG_P (out)) && GET_MODE (out) == DImode); gcc_assert (in - && (REG_P (in) || GET_CODE (in) == SUBREG) + && (REG_P (in) || SUBREG_P (in)) && GET_MODE (in) == DImode); gcc_assert (amount - && (((REG_P (amount) || GET_CODE (amount) == SUBREG) + && (((REG_P (amount) || SUBREG_P (amount)) && GET_MODE (amount) == SImode) || CONST_INT_P (amount))); gcc_assert (scratch1 == NULL @@ -31860,7 +31860,7 @@ arm_valid_symbolic_address_p (rtx addr) if (target_word_relocations) return false; - if (GET_CODE (tmp) == SYMBOL_REF || GET_CODE (tmp) == LABEL_REF) + if (SYMBOL_REF_P (tmp) || LABEL_REF_P (tmp)) return true; /* (const (plus: symbol_ref const_int)) */ @@ -33143,7 +33143,7 @@ extract_base_offset_in_addr (rtx mem, rtx *base, rtx *offset) if (GET_CODE (addr) == CONST) addr = XEXP (addr, 0); - if (GET_CODE (addr) == REG) + if (REG_P (addr)) { *base = addr; *offset = const0_rtx; @@ -33182,12 +33182,12 @@ fusion_load_store (rtx_insn *insn, rtx *base, rtx *offset, bool *is_load) src = SET_SRC (x); dest = SET_DEST (x); - if (GET_CODE (src) == REG && GET_CODE (dest) == MEM) + if (REG_P (src) && MEM_P (dest)) { *is_load = false; extract_base_offset_in_addr (dest, base, offset); } - else if (GET_CODE (src) == MEM && GET_CODE (dest) == REG) + else if (MEM_P (src) && REG_P (dest)) { *is_load = true; extract_base_offset_in_addr (src, base, offset); -- cgit v1.1 From a1fdc16da341187846dd0577e96ee00df5f28608 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 13 Nov 2020 11:41:13 +0100 Subject: Determine access types in ipa-icf-gimple.c This patch adds logic to determine access type (normal or memory) for every operand. This makes it possible to compare memory accesses more carefully which will be implemented in a followup patch. * ipa-icf-gimple.c: Include gimple-walk.h. (func_checker::compare_ssa_name): Update call of compare_operand. (func_checker::hash_operand): Fix comment and add variant taking operand_access_type parameter. (func_checker::compare_operand): Add operand_access_type parameter. (func_checker::compare_asm_inputs_outputs): Add operand_access_type_map parameter; update use of func_checker::compare_operand. (func_checker::compare_gimple_call): Update use of func_checker::compare_operand. (func_checker::compare_gimple_assign): Likewise. (func_checker::compare_gimple_cond): Likewise. (func_checker::compare_gimple_switch): Likewise. (func_checker::compare_gimple_return): Likewise. (func_checker::compare_gimple_goto): Likewise. (func_checker::compare_gimple_asm): Likewise. (visit_load_store): New static functio. (func_checker::classify_operands): New member function. (func_checker::get_operand_access_type): New member function. * ipa-icf-gimple.h (func_checker::operand_access_type): New enum (func_checker::operand_access_type_map): New typedef. (func_checker::compare_operand): Update prototype. (func_checker::compare_asm_inputs_outputs): Likewise. (func_checker::cleassify_operands): Declare. (func_checker::get_operand_access_type): Declare. (func_checker::hash_operand): New variant with operand_access_type. * ipa-icf.c (sem_function::hash_stmt): Update uses of hash_operand. (sem_function::compare_phi_node): Update use of compare_operand. --- gcc/ipa-icf-gimple.c | 109 +++++++++++++++++++++++++++++++++++++++++---------- gcc/ipa-icf-gimple.h | 17 +++++++- gcc/ipa-icf.c | 40 +++++++++---------- 3 files changed, 123 insertions(+), 43 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index b755d7e..0276b20 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "cfgloop.h" #include "attribs.h" +#include "gimple-walk.h" #include "ipa-icf-gimple.h" @@ -109,7 +110,7 @@ func_checker::compare_ssa_name (const_tree t1, const_tree t2) tree b1 = SSA_NAME_VAR (t1); tree b2 = SSA_NAME_VAR (t2); - return compare_operand (b1, b2); + return compare_operand (b1, b2, OP_NORMAL); } return true; @@ -212,8 +213,8 @@ func_checker::compatible_types_p (tree t1, tree t2) return true; } -/* Function compare for equality given trees T1 and T2 which - can be either a constant or a declaration type. */ +/* Add hash of ARG to HSTATE. FLAGS have same meaning + as for operand_equal_p. Works only if operand acces type is OP_NORMAL. */ void func_checker::hash_operand (const_tree arg, inchash::hash &hstate, @@ -246,6 +247,16 @@ func_checker::hash_operand (const_tree arg, inchash::hash &hstate, return operand_compare::hash_operand (arg, hstate, flags); } +/* Add hash of ARG accesses according to ACCESS to HSTATE. + FLAGS have same meaning as for operand_equal_p. */ + +void +func_checker::hash_operand (const_tree arg, inchash::hash &hstate, + unsigned int flags, operand_access_type) +{ + return hash_operand (arg, hstate, flags); +} + bool func_checker::operand_equal_p (const_tree t1, const_tree t2, unsigned int flags) @@ -291,12 +302,13 @@ func_checker::operand_equal_p (const_tree t1, const_tree t2, return operand_compare::operand_equal_p (t1, t2, flags); } -/* Function responsible for comparison of various operands T1 and T2. +/* Function responsible for comparison of various operands T1 and T2 + which are accessed as ACCESS. If these components, from functions FUNC1 and FUNC2, are equal, true is returned. */ bool -func_checker::compare_operand (tree t1, tree t2) +func_checker::compare_operand (tree t1, tree t2, operand_access_type access) { if (!t1 && !t2) return true; @@ -304,11 +316,21 @@ func_checker::compare_operand (tree t1, tree t2) return false; if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS)) return true; - return return_false_with_msg ("operand_equal_p failed"); + switch (access) + { + case OP_MEMORY: + return return_false_with_msg + ("operand_equal_p failed (access == memory)"); + case OP_NORMAL: + return return_false_with_msg + ("operand_equal_p failed (access == normal)"); + } + gcc_unreachable (); } bool -func_checker::compare_asm_inputs_outputs (tree t1, tree t2) +func_checker::compare_asm_inputs_outputs (tree t1, tree t2, + operand_access_type_map *map) { gcc_assert (TREE_CODE (t1) == TREE_LIST); gcc_assert (TREE_CODE (t2) == TREE_LIST); @@ -318,7 +340,8 @@ func_checker::compare_asm_inputs_outputs (tree t1, tree t2) if (!t2) return false; - if (!compare_operand (TREE_VALUE (t1), TREE_VALUE (t2))) + if (!compare_operand (TREE_VALUE (t1), TREE_VALUE (t2), + get_operand_access_type (map, t1))) return return_false (); tree p1 = TREE_PURPOSE (t1); @@ -545,9 +568,12 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2) if (gimple_call_num_args (s1) != gimple_call_num_args (s2)) return false; + operand_access_type_map map (5); + classify_operands (s1, &map); + t1 = gimple_call_fn (s1); t2 = gimple_call_fn (s2); - if (!compare_operand (t1, t2)) + if (!compare_operand (t1, t2, get_operand_access_type (&map, t1))) return return_false (); /* Compare flags. */ @@ -579,7 +605,8 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2) tree chain2 = gimple_call_chain (s2); if ((chain1 && !chain2) || (!chain1 && chain2) - || !compare_operand (chain1, chain2)) + || !compare_operand (chain1, chain2, + get_operand_access_type (&map, chain1))) return return_false_with_msg ("static call chains are different"); /* Checking of argument. */ @@ -588,7 +615,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2) t1 = gimple_call_arg (s1, i); t2 = gimple_call_arg (s2, i); - if (!compare_operand (t1, t2)) + if (!compare_operand (t1, t2, get_operand_access_type (&map, t1))) return return_false_with_msg ("GIMPLE call operands are different"); } @@ -596,7 +623,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2) t1 = gimple_get_lhs (s1); t2 = gimple_get_lhs (s2); - return compare_operand (t1, t2); + return compare_operand (t1, t2, get_operand_access_type (&map, t1)); } @@ -616,6 +643,9 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2) if (code1 != code2) return false; + operand_access_type_map map (5); + classify_operands (s1, &map); + for (i = 0; i < gimple_num_ops (s1); i++) { arg1 = gimple_op (s1, i); @@ -628,7 +658,7 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2) return return_false_with_msg ("GIMPLE NOP LHS type mismatch"); } - if (!compare_operand (arg1, arg2)) + if (!compare_operand (arg1, arg2, get_operand_access_type (&map, arg1))) return return_false_with_msg ("GIMPLE assignment operands " "are different"); } @@ -655,13 +685,13 @@ func_checker::compare_gimple_cond (gimple *s1, gimple *s2) t1 = gimple_cond_lhs (s1); t2 = gimple_cond_lhs (s2); - if (!compare_operand (t1, t2)) + if (!compare_operand (t1, t2, OP_NORMAL)) return false; t1 = gimple_cond_rhs (s1); t2 = gimple_cond_rhs (s2); - return compare_operand (t1, t2); + return compare_operand (t1, t2, OP_NORMAL); } /* Verifies for given GIMPLE_LABEL stmts S1 and S2 that @@ -700,7 +730,7 @@ func_checker::compare_gimple_switch (const gswitch *g1, const gswitch *g2) tree t1 = gimple_switch_index (g1); tree t2 = gimple_switch_index (g2); - if (!compare_operand (t1, t2)) + if (!compare_operand (t1, t2, OP_NORMAL)) return false; for (i = 0; i < lsize1; i++) @@ -727,7 +757,7 @@ func_checker::compare_gimple_switch (const gswitch *g1, const gswitch *g2) label1 = CASE_LABEL (label1); label2 = CASE_LABEL (label2); - if (!compare_operand (label1, label2)) + if (!compare_operand (label1, label2, OP_NORMAL)) return return_false_with_msg ("switch label_exprs are different"); } else if (!tree_int_cst_equal (label1, label2)) @@ -752,7 +782,10 @@ func_checker::compare_gimple_return (const greturn *g1, const greturn *g2) if (t1 == NULL && t2 == NULL) return true; else - return compare_operand (t1, t2); + { + operand_access_type_map map (3); + return compare_operand (t1, t2, get_operand_access_type (&map, t1)); + } } /* Verifies for given GIMPLEs S1 and S2 that @@ -769,7 +802,7 @@ func_checker::compare_gimple_goto (gimple *g1, gimple *g2) if (TREE_CODE (dest1) != TREE_CODE (dest2) || TREE_CODE (dest1) != SSA_NAME) return false; - return compare_operand (dest1, dest2); + return compare_operand (dest1, dest2, OP_NORMAL); } /* Verifies for given GIMPLE_RESX stmts S1 and S2 that @@ -813,12 +846,15 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2) if (strcmp (gimple_asm_string (g1), gimple_asm_string (g2)) != 0) return return_false_with_msg ("ASM strings are different"); + operand_access_type_map map (5); + classify_operands (g1, &map); + for (unsigned i = 0; i < gimple_asm_ninputs (g1); i++) { tree input1 = gimple_asm_input_op (g1, i); tree input2 = gimple_asm_input_op (g2, i); - if (!compare_asm_inputs_outputs (input1, input2)) + if (!compare_asm_inputs_outputs (input1, input2, &map)) return return_false_with_msg ("ASM input is different"); } @@ -827,7 +863,7 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2) tree output1 = gimple_asm_output_op (g1, i); tree output2 = gimple_asm_output_op (g2, i); - if (!compare_asm_inputs_outputs (output1, output2)) + if (!compare_asm_inputs_outputs (output1, output2, &map)) return return_false_with_msg ("ASM output is different"); } @@ -844,4 +880,35 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2) return true; } +/* Helper for func_checker::classify_operands. Record that T is a load. */ + +static bool +visit_load_store (gimple *, tree, tree t, void *data) +{ + func_checker::operand_access_type_map *map = + (func_checker::operand_access_type_map *) data; + map->add (t); + return false; +} + +/* Compute hash map determining access types of operands. */ + +void +func_checker::classify_operands (const gimple *stmt, + operand_access_type_map *map) +{ + walk_stmt_load_store_ops (const_cast (stmt), + (void *)map, visit_load_store, visit_load_store); +} + +/* Return access type of a given operand. */ + +func_checker::operand_access_type +func_checker::get_operand_access_type (operand_access_type_map *map, tree t) +{ + if (map->contains (t)) + return OP_MEMORY; + return OP_NORMAL; +} + } // ipa_icf_gimple namespace diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h index 28459d2..84a0b9d 100644 --- a/gcc/ipa-icf-gimple.h +++ b/gcc/ipa-icf-gimple.h @@ -200,14 +200,19 @@ public: /* Verification function for declaration trees T1 and T2. */ bool compare_decl (const_tree t1, const_tree t2); + /* Compute hash map MAP that determines loads and stores of STMT. */ + enum operand_access_type {OP_MEMORY, OP_NORMAL}; + typedef hash_set operand_access_type_map; + /* Function responsible for comparison of various operands T1 and T2. If these components, from functions FUNC1 and FUNC2, are equal, true is returned. */ - bool compare_operand (tree t1, tree t2); + bool compare_operand (tree t1, tree t2, operand_access_type type); /* Compares GIMPLE ASM inputs (or outputs) where we iterate tree chain and compare both TREE_PURPOSEs and TREE_VALUEs. */ - bool compare_asm_inputs_outputs (tree t1, tree t2); + bool compare_asm_inputs_outputs (tree t1, tree t2, + operand_access_type_map *map); /* Verifies that trees T1 and T2, representing function declarations are equivalent from perspective of ICF. */ @@ -230,7 +235,13 @@ public: first parameter of a function. */ static bool compatible_types_p (tree t1, tree t2); + /* Compute hash map determining access types of operands. */ + static void classify_operands (const gimple *stmt, + operand_access_type_map *map); + /* Return access type of a given operand. */ + static operand_access_type get_operand_access_type + (operand_access_type_map *map, tree); private: /* Vector mapping source SSA names to target ones. */ vec m_source_ssa_names; @@ -272,6 +283,8 @@ public: /* Generate a hash value for an expression. This can be used iteratively by passing a previous result as the HSTATE argument. */ virtual void hash_operand (const_tree, inchash::hash &, unsigned flags); + void hash_operand (const_tree, inchash::hash &, unsigned flags, + operand_access_type access); }; } // ipa_icf_gimple namespace diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c index 8cae076..83f9786 100644 --- a/gcc/ipa-icf.c +++ b/gcc/ipa-icf.c @@ -1419,33 +1419,32 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate) { case GIMPLE_SWITCH: m_checker->hash_operand (gimple_switch_index (as_a (stmt)), - hstate, 0); + hstate, 0, func_checker::OP_NORMAL); break; case GIMPLE_ASSIGN: hstate.add_int (gimple_assign_rhs_code (stmt)); - if (commutative_tree_code (gimple_assign_rhs_code (stmt)) - || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt))) - { - m_checker->hash_operand (gimple_assign_rhs1 (stmt), hstate, 0); - m_checker->hash_operand (gimple_assign_rhs2 (stmt), hstate, 0); - if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt))) - m_checker->hash_operand (gimple_assign_rhs3 (stmt), hstate, 0); - m_checker->hash_operand (gimple_assign_lhs (stmt), hstate, 0); - } /* fall through */ case GIMPLE_CALL: case GIMPLE_ASM: case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_RETURN: - /* All these statements are equivalent if their operands are. */ - for (unsigned i = 0; i < gimple_num_ops (stmt); ++i) - m_checker->hash_operand (gimple_op (stmt, i), hstate, 0); - /* Consider nocf_check attribute in hash as it affects code - generation. */ - if (code == GIMPLE_CALL - && flag_cf_protection & CF_BRANCH) - hstate.add_flag (gimple_call_nocf_check_p (as_a (stmt))); + { + func_checker::operand_access_type_map map (5); + func_checker::classify_operands (stmt, &map); + + /* All these statements are equivalent if their operands are. */ + for (unsigned i = 0; i < gimple_num_ops (stmt); ++i) + m_checker->hash_operand (gimple_op (stmt, i), hstate, 0, + func_checker::get_operand_access_type + (&map, gimple_op (stmt, i))); + /* Consider nocf_check attribute in hash as it affects code + generation. */ + if (code == GIMPLE_CALL + && flag_cf_protection & CF_BRANCH) + hstate.add_flag (gimple_call_nocf_check_p (as_a (stmt))); + } + break; default: break; } @@ -1534,7 +1533,8 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2) tree phi_result1 = gimple_phi_result (phi1); tree phi_result2 = gimple_phi_result (phi2); - if (!m_checker->compare_operand (phi_result1, phi_result2)) + if (!m_checker->compare_operand (phi_result1, phi_result2, + func_checker::OP_NORMAL)) return return_false_with_msg ("PHI results are different"); size1 = gimple_phi_num_args (phi1); @@ -1548,7 +1548,7 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2) t1 = gimple_phi_arg (phi1, i)->def; t2 = gimple_phi_arg (phi2, i)->def; - if (!m_checker->compare_operand (t1, t2)) + if (!m_checker->compare_operand (t1, t2, func_checker::OP_NORMAL)) return return_false (); e1 = gimple_phi_arg_edge (phi1, i); -- cgit v1.1 From 602c6cfc79ce4ae61e277107e0a60079c1a93a97 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 13 Nov 2020 15:58:41 +0100 Subject: Improve handling of memory operands in ipa-icf 2/4 this patch iplements new class ao_compare that is derived from operand_compare and adds a method to compare and hash ao_refs. This is used by ICF to enable more merging. Comparsion is done as follows 1) Verify that the memory access will happen at the same address and will have same size. For constant addresses this is done by comparing ao_ref_base and offset/size For varable accesses it uses operand_equal_p but with OEP_ADDRESS (that does not match TBAA metadata) and then operand_equal_p on type size. 2) Compare alignments. I use get_object_alignment_1 like ipa-icf did before revamp to operand_equal_p in gcc 9. I noticed that return value is bitodd so added a comment 3) Match MR_DEPENDENCE_CLIQUE At this point the memory refrences are same except for TBAA information. We continue by checking 4) ref and base alias sets. Now if lto streaming is going to happen instead of comparing alias sets themselves we compare alias_ptr_types (the patch depends on the ao_ref_alias_ptr_tyep and ao_ref_base_alias_ptr_type acessors I sent yesterday) 5) See if accesses are view converted. If they are we are done since access path is not present 6) Compare the part of access path relevant for TBAA. I recall FRE relies on the fact that if base and ref types are same the access path is, but I do not thing this is 100% reliable especially with LTO alias sets. The access path comparsion logic is also useful for modref (for next stage1). Tracking the access paths improves quite noticeably disambiguation in C++ code by being able to distinquish different fields of same type within a struct. I had the comparsion logic in my tree for some time and it seems to work quite well. During cc1plus build we have some cases where we find mismatch after matching the base/ref alias sets. These are due to failed type merging: access path oracle in LTO uses TYPE_MAIN_VARIANTs. I implemented relatively basic hashing using base and offset. gcc/ChangeLog: * ipa-icf-gimple.c: Include tree-ssa-alias-compare.h. (find_checker::func_checker): Initialize m_tbaa. (func_checker::hash_operand): Use hash_ao_ref for memory accesses. (func_checker::compare_operand): Use compare_ao_refs for memory accesses. (func_checker::cmopare_gimple_assign): Do not check LHS types of memory stores. * ipa-icf-gimple.h (func_checker): Derive from ao_compare; add m_tbaa. * ipa-icf.c: Include tree-ssa-alias-compare.h. (sem_function::equals_private): Update call of func_checker::func_checker. * ipa-utils.h (lto_streaming_expected_p): New inline predicate. * tree-ssa-alias-compare.h: New file. * tree-ssa-alias.c: Include tree-ssa-alias-compare.h and bultins.h (view_converted_memref_p): New function. (types_equal_for_same_type_for_tbaa_p): New function. (ao_ref_alias_ptr_type, ao_ref_base_alias_ptr_type): New functions. (ao_compare::compare_ao_refs): New member function. (ao_compare::hash_ao_ref): New function * tree-ssa-alias.h (ao_ref_base_alias_ptr_type, ao_ref_alias_ptr_type): Declare. gcc/testsuite/ChangeLog: * c-c++-common/Wstringop-overflow-2.c: Disable ICF. * g++.dg/warn/Warray-bounds-8.C: Disable ICF. --- gcc/ipa-icf-gimple.c | 75 +++-- gcc/ipa-icf-gimple.h | 8 +- gcc/ipa-icf.c | 3 + gcc/ipa-utils.h | 12 + gcc/testsuite/c-c++-common/Wstringop-overflow-2.c | 2 +- gcc/testsuite/g++.dg/warn/Warray-bounds-8.C | 2 +- gcc/tree-ssa-alias-compare.h | 43 +++ gcc/tree-ssa-alias.c | 376 +++++++++++++++++++++- gcc/tree-ssa-alias.h | 2 + 9 files changed, 499 insertions(+), 24 deletions(-) create mode 100644 gcc/tree-ssa-alias-compare.h (limited to 'gcc') diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index 0276b20..ffb1bad 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "gimple-walk.h" +#include "tree-ssa-alias-compare.h" #include "ipa-icf-gimple.h" namespace ipa_icf_gimple { @@ -52,13 +53,13 @@ namespace ipa_icf_gimple { of declarations that can be skipped. */ func_checker::func_checker (tree source_func_decl, tree target_func_decl, - bool ignore_labels, + bool ignore_labels, bool tbaa, hash_set *ignored_source_nodes, hash_set *ignored_target_nodes) : m_source_func_decl (source_func_decl), m_target_func_decl (target_func_decl), m_ignored_source_nodes (ignored_source_nodes), m_ignored_target_nodes (ignored_target_nodes), - m_ignore_labels (ignore_labels) + m_ignore_labels (ignore_labels), m_tbaa (tbaa) { function *source_func = DECL_STRUCT_FUNCTION (source_func_decl); function *target_func = DECL_STRUCT_FUNCTION (target_func_decl); @@ -252,9 +253,16 @@ func_checker::hash_operand (const_tree arg, inchash::hash &hstate, void func_checker::hash_operand (const_tree arg, inchash::hash &hstate, - unsigned int flags, operand_access_type) + unsigned int flags, operand_access_type access) { - return hash_operand (arg, hstate, flags); + if (access == OP_MEMORY) + { + ao_ref ref; + ao_ref_init (&ref, const_cast (arg)); + return hash_ao_ref (&ref, lto_streaming_expected_p (), m_tbaa, hstate); + } + else + return hash_operand (arg, hstate, flags); } bool @@ -314,18 +322,40 @@ func_checker::compare_operand (tree t1, tree t2, operand_access_type access) return true; else if (!t1 || !t2) return false; - if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS)) - return true; - switch (access) + if (access == OP_MEMORY) { - case OP_MEMORY: - return return_false_with_msg - ("operand_equal_p failed (access == memory)"); - case OP_NORMAL: + ao_ref ref1, ref2; + ao_ref_init (&ref1, const_cast (t1)); + ao_ref_init (&ref2, const_cast (t2)); + int flags = compare_ao_refs (&ref1, &ref2, + lto_streaming_expected_p (), m_tbaa); + + if (!flags) + return true; + if (flags & SEMANTICS) + return return_false_with_msg + ("compare_ao_refs failed (semantic difference)"); + if (flags & BASE_ALIAS_SET) + return return_false_with_msg + ("compare_ao_refs failed (base alias set difference)"); + if (flags & REF_ALIAS_SET) + return return_false_with_msg + ("compare_ao_refs failed (ref alias set difference)"); + if (flags & ACCESS_PATH) + return return_false_with_msg + ("compare_ao_refs failed (access path difference)"); + if (flags & DEPENDENCE_CLIQUE) + return return_false_with_msg + ("compare_ao_refs failed (dependence clique difference)"); + gcc_unreachable (); + } + else + { + if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS)) + return true; return return_false_with_msg - ("operand_equal_p failed (access == normal)"); + ("operand_equal_p failed"); } - gcc_unreachable (); } bool @@ -593,10 +623,17 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2) tree fntype1 = gimple_call_fntype (s1); tree fntype2 = gimple_call_fntype (s2); - if ((fntype1 && !fntype2) - || (!fntype1 && fntype2) - || (fntype1 && !types_compatible_p (fntype1, fntype2))) - return return_false_with_msg ("call function types are not compatible"); + + /* For direct calls we verify that types are comopatible so if we matced + callees, callers must match, too. For indirect calls however verify + function type. */ + if (!gimple_call_fndecl (s1)) + { + if ((fntype1 && !fntype2) + || (!fntype1 && fntype2) + || (fntype1 && !types_compatible_p (fntype1, fntype2))) + return return_false_with_msg ("call function types are not compatible"); + } if (fntype1 && fntype2 && comp_type_attributes (fntype1, fntype2) != 1) return return_false_with_msg ("different fntype attributes"); @@ -652,10 +689,10 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2) arg2 = gimple_op (s2, i); /* Compare types for LHS. */ - if (i == 0) + if (i == 0 && !gimple_store_p (s1)) { if (!compatible_types_p (TREE_TYPE (arg1), TREE_TYPE (arg2))) - return return_false_with_msg ("GIMPLE NOP LHS type mismatch"); + return return_false_with_msg ("GIMPLE LHS type mismatch"); } if (!compare_operand (arg1, arg2, get_operand_access_type (&map, arg1))) diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h index 84a0b9d..40f7474 100644 --- a/gcc/ipa-icf-gimple.h +++ b/gcc/ipa-icf-gimple.h @@ -118,14 +118,14 @@ public: /* A class aggregating all connections and semantic equivalents for a given pair of semantic function candidates. */ -class func_checker : operand_compare +class func_checker : ao_compare { public: /* Default constructor. */ func_checker (): m_source_func_decl (NULL_TREE), m_target_func_decl (NULL_TREE), m_ignored_source_nodes (NULL), m_ignored_target_nodes (NULL), - m_ignore_labels (false) + m_ignore_labels (false), m_tbaa (true) { m_source_ssa_names.create (0); m_target_ssa_names.create (0); @@ -139,6 +139,7 @@ public: of declarations that can be skipped. */ func_checker (tree source_func_decl, tree target_func_decl, bool ignore_labels = false, + bool tbaa = true, hash_set *ignored_source_nodes = NULL, hash_set *ignored_target_nodes = NULL); @@ -275,6 +276,9 @@ private: /* Flag if ignore labels in comparison. */ bool m_ignore_labels; + /* Flag if we should compare type based alias analysis info. */ + bool m_tbaa; + public: /* Return true if two operands are equal. The flags fields can be used to specify OEP flags described above. */ diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c index 83f9786..a283195 100644 --- a/gcc/ipa-icf.c +++ b/gcc/ipa-icf.c @@ -78,6 +78,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "print-tree.h" #include "ipa-utils.h" +#include "tree-ssa-alias-compare.h" #include "ipa-icf-gimple.h" #include "fibonacci_heap.h" #include "ipa-icf.h" @@ -843,6 +844,8 @@ sem_function::equals_private (sem_item *item) m_checker = new func_checker (decl, m_compared_func->decl, false, + opt_for_fn (m_compared_func->decl, + flag_strict_aliasing), &refs_set, &m_compared_func->refs_set); arg1 = DECL_ARGUMENTS (decl); diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 178c2cb..880e527 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -265,4 +265,16 @@ get_odr_name_for_type (tree type) return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (type_name)); } +/* Return true if we are going to do LTO streaming. */ + +inline bool +lto_streaming_expected_p () +{ + /* Compilation before LTO stremaing. */ + if (flag_lto && !in_lto_p && symtab->state < IPA_SSA_AFTER_INLINING) + return true; + /* WPA or incremental link. */ + return (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO); +} + #endif /* GCC_IPA_UTILS_H */ diff --git a/gcc/testsuite/c-c++-common/Wstringop-overflow-2.c b/gcc/testsuite/c-c++-common/Wstringop-overflow-2.c index 7c7932e..63b1a30 100644 --- a/gcc/testsuite/c-c++-common/Wstringop-overflow-2.c +++ b/gcc/testsuite/c-c++-common/Wstringop-overflow-2.c @@ -1,7 +1,7 @@ /* PR middle-end/91458 - inconsistent warning for writing past the end of an array member { dg-do compile } - { dg-options "-O2 -Wall -Wno-array-bounds" } */ + { dg-options "-O2 -Wall -Wno-array-bounds -fno-ipa-icf" } */ void sink (void*); diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-8.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-8.C index 6db2013..6e0d7f3 100644 --- a/gcc/testsuite/g++.dg/warn/Warray-bounds-8.C +++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-8.C @@ -3,7 +3,7 @@ See Wstringop-overflow-3.C for the same test that exercises the other warning. { dg-do compile } - { dg-options "-O2 -Wall -Wno-stringop-overflow" } + { dg-options "-O2 -Wall -Wno-stringop-overflow -fno-ipa-icf" } { dg-skip-if "" { *-*-aix* } } */ void sink (void*); diff --git a/gcc/tree-ssa-alias-compare.h b/gcc/tree-ssa-alias-compare.h new file mode 100644 index 0000000..0e8409a --- /dev/null +++ b/gcc/tree-ssa-alias-compare.h @@ -0,0 +1,43 @@ +/* Comparsion of AO ref. + Copyright (C) 2020 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + GCC 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 GCC; see the file COPYING3. If not see + . */ + +#ifndef TREE_SSA_ALIAS_COMPARE_H +#define TREE_SSA_ALIAS_COMPARE_H + +class operand_compare; +/* A class aggregating all connections and semantic equivalents + for a given pair of semantic function candidates. */ +class ao_compare : public operand_compare +{ + public: + enum ao_ref_diff + { + SEMANTICS = 1, + BASE_ALIAS_SET = 2, + REF_ALIAS_SET = 4, + ACCESS_PATH = 8, + DEPENDENCE_CLIQUE = 16 + }; + int compare_ao_refs (ao_ref *ref1, ao_ref *ref2, bool lto_streaming_safe, + bool tbaa); + void hash_ao_ref (ao_ref *ref, bool lto_streaming_safe, bool tbaa, + inchash::hash &hstate); +}; + +#endif diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index b1e8e5b..9f279c8 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -45,6 +45,8 @@ along with GCC; see the file COPYING3. If not see #include "dbgcnt.h" #include "gimple-pretty-print.h" #include "print-tree.h" +#include "tree-ssa-alias-compare.h" +#include "builtins.h" /* Broad overview of how alias analysis on gimple works: @@ -739,6 +741,38 @@ ao_ref_alias_set (ao_ref *ref) return ref->ref_alias_set; } +/* Returns a type satisfying + get_deref_alias_set (type) == ao_ref_base_alias_set (REF). */ + +tree +ao_ref_base_alias_ptr_type (ao_ref *ref) +{ + tree base_ref; + + if (!ref->ref) + return NULL_TREE; + base_ref = ref->ref; + while (handled_component_p (base_ref)) + base_ref = TREE_OPERAND (base_ref, 0); + tree ret = reference_alias_ptr_type (base_ref); + gcc_checking_assert (get_deref_alias_set (ret) == ao_ref_base_alias_set (ref)); + return ret; +} + +/* Returns a type satisfying + get_deref_alias_set (type) == ao_ref_alias_set (REF). */ + +tree +ao_ref_alias_ptr_type (ao_ref *ref) +{ + if (!ref->ref) + return NULL_TREE; + tree ret = reference_alias_ptr_type (ref->ref); + gcc_checking_assert (get_deref_alias_set (ret) == ao_ref_alias_set (ref)); + return ret; +} + + /* Init an alias-oracle reference representation from a gimple pointer PTR a range specified by OFFSET, SIZE and MAX_SIZE under the assumption that RANGE_KNOWN is set. @@ -1175,7 +1209,7 @@ aliasing_component_refs_p (tree ref1, struct a {int array1[0]; int array[];}; Such struct has size 0 but accesses to a.array may have non-zero size. In this case the size of TREE_TYPE (base1) is smaller than - size of TREE_TYPE (TREE_OPERNAD (base1, 0)). + size of TREE_TYPE (TREE_OPERAND (base1, 0)). Because we compare sizes of arrays just by sizes of their elements, we only need to care about zero sized array fields here. */ @@ -1950,6 +1984,20 @@ decl_refs_may_alias_p (tree ref1, tree base1, return true; } +/* Return true if access with BASE is view converted. + Base must not be stripped from inner MEM_REF (&decl) + which is done by ao_ref_base and thus one extra walk + of handled components is needed. */ + +static bool +view_converted_memref_p (tree base) +{ + if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF) + return false; + return same_type_for_tbaa (TREE_TYPE (base), + TREE_TYPE (TREE_OPERAND (base, 1))) != 1; +} + /* Return true if an indirect reference based on *PTR1 constrained to [OFFSET1, OFFSET1 + MAX_SIZE1) may alias a variable based on BASE2 constrained to [OFFSET2, OFFSET2 + MAX_SIZE2). *PTR1 and BASE2 have @@ -3840,3 +3888,329 @@ attr_fnspec::verify () internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i); } } + +/* Return ture if TYPE1 and TYPE2 will always give the same answer + when compared wit hother types using same_type_for_tbaa_p. */ + +static bool +types_equal_for_same_type_for_tbaa_p (tree type1, tree type2, + bool lto_streaming_safe) +{ + /* We use same_type_for_tbaa_p to match types in the access path. + This check is overly conservative. */ + type1 = TYPE_MAIN_VARIANT (type1); + type2 = TYPE_MAIN_VARIANT (type2); + + if (TYPE_STRUCTURAL_EQUALITY_P (type1) + != TYPE_STRUCTURAL_EQUALITY_P (type2)) + return false; + if (TYPE_STRUCTURAL_EQUALITY_P (type1)) + return true; + + if (lto_streaming_safe) + return type1 == type2; + else + return TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2); +} + +/* Compare REF1 and REF2 and return flags specifying their differences. + If LTO_STREAMING_SAFE is true do not use alias sets and canonical + types that are going to be recomputed. + If TBAA is true also compare TBAA metadata. */ + +int +ao_compare::compare_ao_refs (ao_ref *ref1, ao_ref *ref2, + bool lto_streaming_safe, + bool tbaa) +{ + if (TREE_THIS_VOLATILE (ref1->ref) != TREE_THIS_VOLATILE (ref2->ref)) + return SEMANTICS; + tree base1 = ao_ref_base (ref1); + tree base2 = ao_ref_base (ref2); + + if (!known_eq (ref1->offset, ref2->offset) + || !known_eq (ref1->size, ref2->size) + || !known_eq (ref1->max_size, ref2->max_size)) + return SEMANTICS; + + /* For variable accesses we need to compare actual paths + to check that both refs are accessing same address and the access size. */ + if (!known_eq (ref1->size, ref1->max_size)) + { + if (!operand_equal_p (TYPE_SIZE (TREE_TYPE (ref1->ref)), + TYPE_SIZE (TREE_TYPE (ref2->ref)), 0)) + return SEMANTICS; + tree r1 = ref1->ref; + tree r2 = ref2->ref; + + /* Handle toplevel COMPONENT_REFs of bitfields. + Those are special since they are not allowed in + ADDR_EXPR. */ + if (TREE_CODE (r1) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (r1, 1))) + { + if (TREE_CODE (r2) != COMPONENT_REF + || !DECL_BIT_FIELD (TREE_OPERAND (r2, 1))) + return SEMANTICS; + tree field1 = TREE_OPERAND (r1, 1); + tree field2 = TREE_OPERAND (r2, 1); + if (!operand_equal_p (DECL_FIELD_OFFSET (field1), + DECL_FIELD_OFFSET (field2), 0) + || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field1), + DECL_FIELD_BIT_OFFSET (field2), 0) + || !operand_equal_p (DECL_SIZE (field1), DECL_SIZE (field2), 0) + || !types_compatible_p (TREE_TYPE (r1), + TREE_TYPE (r2))) + return SEMANTICS; + r1 = TREE_OPERAND (r1, 0); + r2 = TREE_OPERAND (r2, 0); + } + else if (TREE_CODE (r2) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (r2, 1))) + return SEMANTICS; + + /* Similarly for bit field refs. */ + if (TREE_CODE (r1) == BIT_FIELD_REF) + { + if (TREE_CODE (r2) != BIT_FIELD_REF + || !operand_equal_p (TREE_OPERAND (r1, 1), + TREE_OPERAND (r2, 1), 0) + || !operand_equal_p (TREE_OPERAND (r1, 2), + TREE_OPERAND (r2, 2), 0) + || !types_compatible_p (TREE_TYPE (r1), + TREE_TYPE (r2))) + return SEMANTICS; + r1 = TREE_OPERAND (r1, 0); + r2 = TREE_OPERAND (r2, 0); + } + else if (TREE_CODE (r2) == BIT_FIELD_REF) + return SEMANTICS; + + /* Now we can compare the address of actual memory access. */ + if (!operand_equal_p (r1, r2, OEP_ADDRESS_OF)) + return SEMANTICS; + } + /* For constant accesses we get more matches by comparing offset only. */ + else if (!operand_equal_p (base1, base2, OEP_ADDRESS_OF)) + return SEMANTICS; + + /* We can't simply use get_object_alignment_1 on the full + reference as for accesses with variable indexes this reports + too conservative alignment. */ + unsigned int align1, align2; + unsigned HOST_WIDE_INT bitpos1, bitpos2; + bool known1 = get_object_alignment_1 (base1, &align1, &bitpos1); + bool known2 = get_object_alignment_1 (base2, &align2, &bitpos2); + /* ??? For MEMREF get_object_alignment_1 determines aligned from + TYPE_ALIGN but still returns false. This seem to contradict + its description. So compare even if alignment is unknown. */ + if (known1 != known2 + || (bitpos1 != bitpos2 || align1 != align2)) + return SEMANTICS; + + /* Now we know that accesses are semantically same. */ + int flags = 0; + + /* ao_ref_base strips inner MEM_REF [&decl], recover from that here. */ + tree rbase1 = ref1->ref; + if (rbase1) + while (handled_component_p (rbase1)) + rbase1 = TREE_OPERAND (rbase1, 0); + tree rbase2 = ref2->ref; + while (handled_component_p (rbase2)) + rbase2 = TREE_OPERAND (rbase2, 0); + + /* MEM_REFs and TARGET_MEM_REFs record dependence cliques which are used to + implement restrict pointers. MR_DEPENDENCE_CLIQUE 0 means no information. + Otherwise we need to match bases and cliques. */ + if ((((TREE_CODE (rbase1) == MEM_REF || TREE_CODE (rbase1) == TARGET_MEM_REF) + && MR_DEPENDENCE_CLIQUE (rbase1)) + || ((TREE_CODE (rbase2) == MEM_REF || TREE_CODE (rbase2) == TARGET_MEM_REF) + && MR_DEPENDENCE_CLIQUE (rbase2))) + && (TREE_CODE (rbase1) != TREE_CODE (rbase2) + || MR_DEPENDENCE_CLIQUE (rbase1) != MR_DEPENDENCE_CLIQUE (rbase2) + || (MR_DEPENDENCE_BASE (rbase1) != MR_DEPENDENCE_BASE (rbase2)))) + flags |= DEPENDENCE_CLIQUE; + + if (!tbaa) + return flags; + + /* Alias sets are not stable across LTO sreaming; be conservative here + and compare types the alias sets are ultimately based on. */ + if (lto_streaming_safe) + { + tree t1 = ao_ref_alias_ptr_type (ref1); + tree t2 = ao_ref_alias_ptr_type (ref2); + if (!alias_ptr_types_compatible_p (t1, t2)) + flags |= REF_ALIAS_SET; + + t1 = ao_ref_base_alias_ptr_type (ref1); + t2 = ao_ref_base_alias_ptr_type (ref2); + if (!alias_ptr_types_compatible_p (t1, t2)) + flags |= BASE_ALIAS_SET; + } + else + { + if (ao_ref_alias_set (ref1) != ao_ref_alias_set (ref2)) + flags |= REF_ALIAS_SET; + if (ao_ref_base_alias_set (ref1) != ao_ref_base_alias_set (ref2)) + flags |= BASE_ALIAS_SET; + } + + /* Access path is used only on non-view-converted references. */ + bool view_converted = view_converted_memref_p (rbase1); + if (view_converted_memref_p (rbase2) != view_converted) + return flags | ACCESS_PATH; + else if (view_converted) + return flags; + + + /* Find start of access paths and look for trailing arrays. */ + tree c1 = ref1->ref, c2 = ref2->ref; + tree end_struct_ref1 = NULL, end_struct_ref2 = NULL; + int nskipped1 = 0, nskipped2 = 0; + int i = 0; + + for (tree p1 = ref1->ref; handled_component_p (p1); p1 = TREE_OPERAND (p1, 0)) + { + if (component_ref_to_zero_sized_trailing_array_p (p1)) + end_struct_ref1 = p1; + if (ends_tbaa_access_path_p (p1)) + c1 = p1, nskipped1 = i; + i++; + } + for (tree p2 = ref2->ref; handled_component_p (p2); p2 = TREE_OPERAND (p2, 0)) + { + if (component_ref_to_zero_sized_trailing_array_p (p2)) + end_struct_ref2 = p2; + if (ends_tbaa_access_path_p (p2)) + c2 = p2, nskipped1 = i; + i++; + } + + /* For variable accesses we can not rely on offset match bellow. + We know that paths are struturally same, so only check that + starts of TBAA paths did not diverge. */ + if (!known_eq (ref1->size, ref1->max_size) + && nskipped1 != nskipped2) + return flags | ACCESS_PATH; + + /* Information about trailing refs is used by + aliasing_component_refs_p that is applied only if paths + has handled components.. */ + if (!handled_component_p (c1) && !handled_component_p (c2)) + ; + else if ((end_struct_ref1 != NULL) != (end_struct_ref2 != NULL)) + return flags | ACCESS_PATH; + if (end_struct_ref1 + && TYPE_MAIN_VARIANT (TREE_TYPE (end_struct_ref1)) + != TYPE_MAIN_VARIANT (TREE_TYPE (end_struct_ref2))) + return flags | ACCESS_PATH; + + /* Now compare all handled components of the access path. + We have three oracles that cares about access paths: + - aliasing_component_refs_p + - nonoverlapping_refs_since_match_p + - nonoverlapping_component_refs_p + We need to match things these oracles compare. + + It is only necessary to check types for compatibility + and offsets. Rest of what oracles compares are actual + addresses. Those are already known to be same: + - for constant accesses we check offsets + - for variable accesses we already matched + the path lexically with operand_equal_p. */ + while (true) + { + bool comp1 = handled_component_p (c1); + bool comp2 = handled_component_p (c2); + + if (comp1 != comp2) + return flags | ACCESS_PATH; + if (!comp1) + break; + + if (TREE_CODE (c1) != TREE_CODE (c2)) + return flags | ACCESS_PATH; + + /* aliasing_component_refs_p attempts to find type match within + the paths. For that reason both types needs to be equal + with respect to same_type_for_tbaa_p. */ + if (!types_equal_for_same_type_for_tbaa_p (TREE_TYPE (c1), + TREE_TYPE (c2), + lto_streaming_safe)) + return flags | ACCESS_PATH; + if (component_ref_to_zero_sized_trailing_array_p (c1) + != component_ref_to_zero_sized_trailing_array_p (c2)) + return flags | ACCESS_PATH; + + /* aliasing_matching_component_refs_p compares + offsets within the path. Other properties are ignored. + Do not bother to verify offsets in variable accesses. Here we + already compared them by operand_equal_p so they are + structurally same. */ + if (!known_eq (ref1->size, ref1->max_size)) + { + poly_int64 offadj1, sztmc1, msztmc1; + bool reverse1; + get_ref_base_and_extent (c1, &offadj1, &sztmc1, &msztmc1, &reverse1); + poly_int64 offadj2, sztmc2, msztmc2; + bool reverse2; + get_ref_base_and_extent (c2, &offadj2, &sztmc2, &msztmc2, &reverse2); + if (!known_eq (offadj1, offadj2)) + return flags | ACCESS_PATH; + } + c1 = TREE_OPERAND (c1, 0); + c2 = TREE_OPERAND (c2, 0); + } + /* Finally test the access type. */ + if (!types_equal_for_same_type_for_tbaa_p (TREE_TYPE (c1), + TREE_TYPE (c2), + lto_streaming_safe)) + return flags | ACCESS_PATH; + return flags; +} + +/* Hash REF to HSTATE. If LTO_STREAMING_SAFE do not use alias sets + and canonical types. */ +void +ao_compare::hash_ao_ref (ao_ref *ref, bool lto_streaming_safe, bool tbaa, + inchash::hash &hstate) +{ + tree base = ao_ref_base (ref); + tree tbase = base; + + if (!known_eq (ref->size, ref->max_size)) + { + tree r = ref->ref; + if (TREE_CODE (r) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (r, 1))) + { + tree field = TREE_OPERAND (r, 1); + hash_operand (DECL_FIELD_OFFSET (field), hstate, 0); + hash_operand (DECL_FIELD_BIT_OFFSET (field), hstate, 0); + hash_operand (DECL_SIZE (field), hstate, 0); + r = TREE_OPERAND (r, 0); + } + if (TREE_CODE (r) == BIT_FIELD_REF) + { + hash_operand (TREE_OPERAND (r, 1), hstate, 0); + hash_operand (TREE_OPERAND (r, 2), hstate, 0); + r = TREE_OPERAND (r, 0); + } + hash_operand (TYPE_SIZE (TREE_TYPE (ref->ref)), hstate, 0); + hash_operand (r, hstate, OEP_ADDRESS_OF); + } + else + { + hash_operand (tbase, hstate, OEP_ADDRESS_OF); + hstate.add_poly_int (ref->offset); + hstate.add_poly_int (ref->size); + hstate.add_poly_int (ref->max_size); + } + if (!lto_streaming_safe && tbaa) + { + hstate.add_int (ao_ref_alias_set (ref)); + hstate.add_int (ao_ref_base_alias_set (ref)); + } +} diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h index 1561ead..830ac1b 100644 --- a/gcc/tree-ssa-alias.h +++ b/gcc/tree-ssa-alias.h @@ -114,6 +114,8 @@ extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree); extern tree ao_ref_base (ao_ref *); extern alias_set_type ao_ref_alias_set (ao_ref *); extern alias_set_type ao_ref_base_alias_set (ao_ref *); +extern tree ao_ref_alias_ptr_type (ao_ref *); +extern tree ao_ref_base_alias_ptr_type (ao_ref *); extern bool ptr_deref_may_alias_global_p (tree); extern bool ptr_derefs_may_alias_p (tree, tree); extern bool ptrs_compare_unequal (tree, tree); -- cgit v1.1 From 953587a2b0fb171b94685f2808e906adb66d4f0b Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 13 Nov 2020 15:35:33 +0000 Subject: MSP430: Implement TARGET_MEMORY_MOVE_COST The cycle and size cost of a MOV instruction in different addressing modes can be used to calculate the TARGET_MEMORY_MOVE_COST relative to TARGET_REGISTER_MOVE_COST. gcc/ChangeLog: * config/msp430/msp430.c (struct single_op_cost): New struct. (struct double_op_cost): Likewise. (TARGET_REGISTER_MOVE_COST): Don't define but add comment. (TARGET_MEMORY_MOVE_COST): Define to... (msp430_memory_move_cost): New function. (BRANCH_COST): Don't define but add comment. --- gcc/config/msp430/msp430.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) (limited to 'gcc') diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index de4b16b..580e87f 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -1031,6 +1031,135 @@ msp430_legitimate_constant (machine_mode mode, rtx x) } +/* Describing Relative Costs of Operations + To model the cost of an instruction, use the number of cycles when + optimizing for speed, and the number of words when optimizing for size. + The cheapest instruction will execute in one cycle and cost one word. + The cycle and size costs correspond to 430 ISA instructions, not 430X + instructions or 430X "address" instructions. The relative costs of 430X + instructions is accurately modeled with the 430 costs. The relative costs + of some "address" instructions can differ, but these are not yet handled. + Adding support for this could improve performance/code size. */ + +struct single_op_cost +{ + const int reg; + /* Indirect register (@Rn) or indirect autoincrement (@Rn+). */ + const int ind; + const int mem; +}; + +static const struct single_op_cost cycle_cost_single_op = +{ + 1, 3, 4 +}; + +static const struct single_op_cost size_cost_single_op = +{ + 1, 1, 2 +}; + +/* When the destination of an insn is memory, the cost is always the same + regardless of whether that memory is accessed using indirect register, + indexed or absolute addressing. + When the source operand is memory, indirect register and post-increment have + the same cost, which is lower than indexed and absolute, which also have + the same cost. */ +struct double_op_cost +{ + /* Source operand is a register. */ + const int r2r; + const int r2pc; + const int r2m; + + /* Source operand is memory, using indirect register (@Rn) or indirect + autoincrement (@Rn+) addressing modes. */ + const int ind2r; + const int ind2pc; + const int ind2m; + + /* Source operand is an immediate. */ + const int imm2r; + const int imm2pc; + const int imm2m; + + /* Source operand is memory, using indexed (x(Rn)) or absolute (&ADDR) + addressing modes. */ + const int mem2r; + const int mem2pc; + const int mem2m; +}; + +/* These structures describe the cost of MOV, BIT and CMP instructions, in terms + of clock cycles or words. */ +static const struct double_op_cost cycle_cost_double_op_mov = +{ + 1, 3, 3, + 2, 4, 4, + 2, 3, 4, + 3, 5, 5 +}; + +/* Cycle count when memory is the destination operand is one larger than above + for instructions that aren't MOV, BIT or CMP. */ +static const struct double_op_cost cycle_cost_double_op = +{ + 1, 3, 4, + 2, 4, 5, + 2, 3, 5, + 3, 5, 6 +}; + +static const struct double_op_cost size_cost_double_op = +{ + 1, 1, 2, + 1, 1, 2, + 2, 2, 3, + 2, 2, 3 +}; + +/* TARGET_REGISTER_MOVE_COST + There is only one class of general-purpose, non-fixed registers, and the + relative cost of moving data between them is always the same. + Therefore, the default of 2 is optimal. */ + +#undef TARGET_MEMORY_MOVE_COST +#define TARGET_MEMORY_MOVE_COST msp430_memory_move_cost + +/* Return the cost of moving data between registers and memory. + The returned cost must be relative to the default TARGET_REGISTER_MOVE_COST + of 2. + IN is false if the value is to be written to memory. */ +static int +msp430_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED, + reg_class_t rclass ATTRIBUTE_UNUSED, + bool in) +{ + int cost; + const struct double_op_cost *cost_p; + /* Optimize with a code size focus by default, unless -O2 or above is + specified. */ + bool speed = (!optimize_size && optimize >= 2); + + cost_p = (speed ? &cycle_cost_double_op_mov : &size_cost_double_op); + + if (in) + /* Reading from memory using indirect addressing is assumed to be the more + common case. */ + cost = cost_p->ind2r; + else + cost = cost_p->r2m; + + /* All register to register moves cost 1 cycle or 1 word, so multiply by 2 + to get the costs relative to TARGET_REGISTER_MOVE_COST of 2. */ + return 2 * cost; +} + +/* BRANCH_COST + Changing from the default of 1 doesn't affect code generation, presumably + because there are no conditional move insns - when a condition is involved, + the only option is to use a cbranch. */ + #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS msp430_rtx_costs -- cgit v1.1 From f62dd3982398d031bc26c853522c5f4e20ef08fc Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 13 Nov 2020 15:35:42 +0000 Subject: MSP430: Implement TARGET_RTX_COSTS Costs of MSP430 instructions are mostly just a function of the type and number of operands; knowledge of the specific instruction often isn't required to calculate the cost. In these cases, TARGET_RTX_COSTS just needs to examine the operands to calculate the cost of the expression. For more complicated operations where library helper functions are required, if the cost cannot be accurately calculated, it is estimated and disparaged relative to the cost of a single instruction. gcc/ChangeLog: * config/msp430/msp430.c (use_helper_for_const_shift): Add forward declaration. Remove unused argument. (struct msp430_multlib_costs): New struct. (msp430_is_mem_indirect): New function. (msp430_costs): Likewise. (msp430_shift_costs): Likewise. (msp430_muldiv_costs): Likewise. (msp430_get_inner_dest_code): Likewise. (msp430_single_op_cost): Likewise. (msp430_rtx_costs): Rewrite from scratch. (msp430_expand_shift): Adjust use_helper_for_const_shift call. --- gcc/config/msp430/msp430.c | 502 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 485 insertions(+), 17 deletions(-) (limited to 'gcc') diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 580e87f..9f76351 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -49,6 +49,9 @@ #include "msp430-devices.h" #include "incpath.h" #include "prefix.h" +#include "insn-config.h" +#include "insn-attr.h" +#include "recog.h" /* This file should be included last. */ #include "target-def.h" @@ -56,6 +59,7 @@ static void msp430_compute_frame_info (void); static bool use_32bit_hwmult (void); +static bool use_helper_for_const_shift (machine_mode mode, HOST_WIDE_INT amt); @@ -1118,6 +1122,28 @@ static const struct double_op_cost size_cost_double_op = 2, 2, 3 }; +struct msp430_multlib_costs +{ + const int mulhi; + const int mulsi; + const int muldi; +}; + +/* There is no precise size cost when using libcalls, instead it is disparaged + relative to other instructions. + The cycle costs are from the CALL to the RET, inclusive. + FIXME muldi cost is not accurate. */ +static const struct msp430_multlib_costs cycle_cost_multlib_32bit = +{ + 27, 33, 66 +}; + +/* 32bit multiply takes a few more instructions on 16bit hwmult. */ +static const struct msp430_multlib_costs cycle_cost_multlib_16bit = +{ + 27, 42, 66 +}; + /* TARGET_REGISTER_MOVE_COST There is only one class of general-purpose, non-fixed registers, and the relative cost of moving data between them is always the same. @@ -1160,29 +1186,469 @@ msp430_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED, because there are no conditional move insns - when a condition is involved, the only option is to use a cbranch. */ -#undef TARGET_RTX_COSTS -#define TARGET_RTX_COSTS msp430_rtx_costs +/* For X, which must be a MEM RTX, return TRUE if it is an indirect memory + reference, @Rn or @Rn+. */ +static bool +msp430_is_mem_indirect (rtx x) +{ + gcc_assert (GET_CODE (x) == MEM); + rtx op0 = XEXP (x, 0); + return (GET_CODE (op0) == REG || GET_CODE (op0) == POST_INC); +} + +/* Costs of MSP430 instructions are generally based on the addressing mode + combination of the source and destination operands. + Given source operand SRC (which may be NULL to indicate a single-operand + instruction) and destination operand DST return the cost of this + expression. */ +static int +msp430_costs (rtx src, rtx dst, bool speed, rtx outer_rtx) +{ + enum rtx_code src_code = GET_CODE (src); + enum rtx_code dst_code = GET_CODE (dst); + enum rtx_code outer_code = GET_CODE (outer_rtx); + machine_mode outer_mode = GET_MODE (outer_rtx); + const struct double_op_cost *cost_p; + cost_p = (speed ? &cycle_cost_double_op : &size_cost_double_op); + + if (outer_code == TRUNCATE + && (outer_mode == QImode + || outer_mode == HImode + || outer_mode == PSImode)) + /* Truncation to these modes is normally free as a side effect of the + instructions themselves. */ + return 0; + + if (dst_code == SYMBOL_REF + || dst_code == LABEL_REF + || dst_code == CONST_INT) + /* Catch RTX like (minus (const_int 0) (reg)) but don't add any cost. */ + return 0; + + switch (src_code) + { + case REG: + return (dst_code == REG ? cost_p->r2r + : (dst_code == PC ? cost_p->r2pc : cost_p->r2m)); + + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + return (dst_code == REG ? cost_p->imm2r + : (dst_code == PC ? cost_p->imm2pc : cost_p->imm2m)); + + + case MEM: + if (msp430_is_mem_indirect (src)) + return (dst_code == REG ? cost_p->ind2r : (dst_code == PC + ? cost_p->ind2pc + : cost_p->ind2m)); + else + return (dst_code == REG ? cost_p->mem2r : (dst_code == PC + ? cost_p->mem2pc + : cost_p->mem2m)); + default: + return cost_p->mem2m; + } +} + +/* Given source operand SRC and destination operand DST from the shift or + rotate RTX OUTER_RTX, return the cost of performing that shift, assuming + optimization for speed when SPEED is true. */ +static int +msp430_shift_costs (rtx src, rtx dst, bool speed, rtx outer_rtx) +{ + int amt; + enum rtx_code src_code = GET_CODE (src); + enum rtx_code dst_code = GET_CODE (dst); + const struct single_op_cost *cost_p; + + cost_p = (speed ? &cycle_cost_single_op : &size_cost_single_op); + + if (src_code != CONST_INT) + /* The size or speed cost when the shift amount is unknown cannot be + accurately calculated, so just disparage it slightly. */ + return 2 * msp430_costs (src, dst, speed, outer_rtx); -static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED, - machine_mode mode, - int outer_code ATTRIBUTE_UNUSED, - int opno ATTRIBUTE_UNUSED, - int * total, - bool speed ATTRIBUTE_UNUSED) + if (use_helper_for_const_shift (GET_MODE (outer_rtx), amt = INTVAL (src))) + { + /* GCC sometimes tries to perform shifts in some very inventive ways, + resulting in much larger code size usage than necessary, if + they are disparaged too much here. So in general, if + use_helper_for_const_shift thinks a helper should be used, obey + that and don't disparage the shift any more than a regular + instruction, even though the shift may actually cost more. + This ensures that the RTL generated at the initial expand pass has the + expected shift instructions, which can be mapped to the helper + functions. */ + return msp430_costs (src, dst, speed, outer_rtx); + } + + if (!msp430x) + { + /* Each shift by one place will be emitted individually. */ + switch (dst_code) + { + case REG: + case CONST_INT: + return amt * cost_p->reg; + case MEM: + if (msp430_is_mem_indirect (dst)) + return amt * cost_p->ind; + else + return amt * cost_p->mem; + default: + return amt * cost_p->mem; + } + } + + /* RRAM, RRCM, RRUM, RLAM are used for shift counts <= 4, otherwise, the 'X' + versions are used. + Instructions which shift a MEM operand will never actually be output. It + will always be copied into a register to allow for efficient shifting. So + the cost just takes into account the cost of an additional copy in that + case. */ + return (amt <= 4 ? (speed ? amt : 1) : (speed ? amt + 1 : 2) + + (dst_code == REG ? 0 + : msp430_costs (dst, gen_rtx_REG (HImode, 10), speed, outer_rtx))); +} + +/* Given source operand SRC and destination operand DST from the MULT/DIV/MOD + RTX OUTER_RTX, return the cost of performing that operation, assuming + optimization for speed when SPEED is true. */ +static int +msp430_muldiv_costs (rtx src, rtx dst, bool speed, rtx outer_rtx, + machine_mode outer_mode) { - int code = GET_CODE (x); + enum rtx_code outer_code = GET_CODE (outer_rtx); + const struct msp430_multlib_costs *cost_p; + bool hwmult_16bit = (msp430_has_hwmult () && !(msp430_use_f5_series_hwmult () + || use_32bit_hwmult ())); + cost_p = (hwmult_16bit + ? &cycle_cost_multlib_32bit + : &cycle_cost_multlib_16bit); + + int factor = 1; + /* Only used in some calculations. */ + int mode_factor = 1; + if (outer_mode == SImode) + mode_factor = 2; + else if (outer_mode == PSImode) + /* PSImode multiplication is performed using SImode operands, so has extra + cost to factor in the conversions necessary before/after the + operation. */ + mode_factor = 3; + else if (outer_mode == DImode) + mode_factor = 4; + + if (!speed) + { + /* The codesize cost of using a helper function to perform the + multiplication or division cannot be accurately calculated, since the + cost depends on how many times the operation is performed in the + entire program. */ + if (outer_code != MULT) + /* Division is always expensive. */ + factor = 7; + else if (((hwmult_16bit && outer_mode != DImode) + || use_32bit_hwmult () || msp430_use_f5_series_hwmult ())) + /* When the hardware multiplier is available, only disparage + slightly. */ + factor = 2; + else + factor = 5; + return factor * mode_factor * msp430_costs (src, dst, speed, outer_rtx); + } + + /* When there is hardware multiply support, there is a relatively low, fixed + cycle cost to performing any multiplication, but when there is no hardware + multiply support it is very costly. That precise cycle cost has not been + calculated here. + Division is extra slow since it always uses a software library. + The 16-bit hardware multiply library cannot be used to produce 64-bit + results. */ + if (outer_code != MULT || !msp430_has_hwmult () + || (outer_mode == DImode && hwmult_16bit)) + { + factor = (outer_code == MULT ? 50 : 70); + return factor * mode_factor * msp430_costs (src, dst, speed, outer_rtx); + } + + switch (outer_mode) + { + case E_QImode: + case E_HImode: + /* Include the cost of copying the operands into and out of the hardware + multiply routine. */ + return cost_p->mulhi + (3 * msp430_costs (src, dst, speed, outer_rtx)); + + case E_PSImode: + /* Extra factor for the conversions necessary to do PSI->SI before the + operation. */ + factor = 2; + /* fallthru. */ + case E_SImode: + return factor * (cost_p->mulsi + + (6 * msp430_costs (src, dst, speed, outer_rtx))); + + case E_DImode: + default: + return cost_p->muldi + (12 * msp430_costs (src, dst, speed, outer_rtx)); + } +} +/* Recurse within X to find the actual destination operand of the expression. + For example: + (plus (ashift (minus (ashift (reg) + (const_int) ...... + should return the reg RTX. */ +static rtx +msp430_get_inner_dest_code (rtx x) +{ + enum rtx_code code = GET_CODE (x); + rtx op0 = XEXP (x, 0); switch (code) { - case SIGN_EXTEND: - if (mode == SImode && outer_code == SET) + case REG: + case SYMBOL_REF: + case CONST_INT: + case CONST: + case LABEL_REF: + return x; + + case MEM: + /* Return the MEM expr not the inner REG for these cases. */ + switch (GET_CODE (op0)) { - *total = COSTS_N_INSNS (4); - return true; + case REG: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + case POST_INC: + return x; + + case PLUS: + /* return MEM (PLUS (REG) (CONST)) */ + if (GET_CODE (XEXP (op0, 0)) == REG) + { + if (GET_CODE (XEXP (op0, 1)) == CONST_INT + || GET_CODE (XEXP (op0, 1)) == CONST + || GET_CODE (XEXP (op0, 1)) == LABEL_REF + || GET_CODE (XEXP (op0, 1)) == SYMBOL_REF) + return x; + else + return msp430_get_inner_dest_code (op0); + } + return msp430_get_inner_dest_code (op0); + + default: + if (GET_RTX_FORMAT (code)[0] != 'e') + return x; + return msp430_get_inner_dest_code (op0); } break; + + default: + if (op0 == NULL_RTX) + gcc_unreachable (); + else + { + if (GET_RTX_FORMAT (code)[0] != 'e' + && code != ENTRY_VALUE) + return x; + return msp430_get_inner_dest_code (op0); + } + } +} + +/* Calculate the cost of an MSP430 single-operand instruction, for operand DST + within the RTX OUTER_RTX, optimizing for speed if SPEED is true. */ +static int +msp430_single_op_cost (rtx dst, bool speed, rtx outer_rtx) +{ + enum rtx_code dst_code = GET_CODE (dst); + const struct single_op_cost *cost_p; + const struct double_op_cost *double_op_cost_p; + + cost_p = (speed ? &cycle_cost_single_op : &size_cost_single_op); + double_op_cost_p = (speed ? &cycle_cost_double_op : &size_cost_double_op); + + switch (dst_code) + { + case REG: + return cost_p->reg; + case MEM: + if (msp430_is_mem_indirect (dst)) + return cost_p->ind; + else + return cost_p->mem; + + case CONST_INT: + case CONST_FIXED: + case CONST_DOUBLE: + case SYMBOL_REF: + case CONST: + /* A constant value would need to be copied into a register first. */ + return double_op_cost_p->imm2r + cost_p->reg; + + default: + return cost_p->mem; + } +} + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS msp430_rtx_costs + +/* This target hook describes the relative costs of RTL expressions. + The function recurses to just before the lowest level of the expression, + when both of the operands of the expression can be examined at the same time. + This is because the cost of the expression depends on the specific + addressing mode combination of the operands. + The hook returns true when all subexpressions of X have been processed, and + false when rtx_cost should recurse. */ +static bool +msp430_rtx_costs (rtx x, + machine_mode mode, + int outer_code ATTRIBUTE_UNUSED, + int opno ATTRIBUTE_UNUSED, + int * total, + bool speed) +{ + enum rtx_code code = GET_CODE (x); + rtx dst, src; + rtx dst_inner, src_inner; + + *total = 0; + dst = XEXP (x, 0); + if (GET_RTX_LENGTH (code) == 1) + /* Some RTX that are single-op in GCC are double-op when translated to + MSP430 instructions e.g NOT, NEG, ZERO_EXTEND. */ + src = dst; + else + src = XEXP (x, 1); + + + switch (code) + { + case SET: + /* Ignoring SET improves codesize. */ + if (!speed) + return true; + /* fallthru. */ + case PLUS: + if (outer_code == MEM) + /* Do not add any cost for the plus itself, but recurse in case there + are more complicated RTX inside. */ + return false; + /* fallthru. */ + case MINUS: + case AND: + case IOR: + case XOR: + case NOT: + case ZERO_EXTEND: + case TRUNCATE: + case NEG: + case ZERO_EXTRACT: + case SIGN_EXTRACT: + case IF_THEN_ELSE: + dst_inner = msp430_get_inner_dest_code (dst); + src_inner = msp430_get_inner_dest_code (src); + *total = COSTS_N_INSNS (msp430_costs (src_inner, dst_inner, speed, x)); + if (mode == SImode) + *total *= 2; + if (mode == DImode) + *total *= 4; + return false; + + case ROTATE: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + dst_inner = msp430_get_inner_dest_code (dst); + src_inner = msp430_get_inner_dest_code (src); + *total = COSTS_N_INSNS (msp430_shift_costs (src_inner, dst_inner, + speed, x)); + if (mode == SImode) + *total *= 2; + if (mode == DImode) + *total *= 4; + return false; + + case MULT: + case DIV: + case MOD: + case UDIV: + case UMOD: + dst_inner = msp430_get_inner_dest_code (dst); + src_inner = msp430_get_inner_dest_code (src); + *total = COSTS_N_INSNS (msp430_muldiv_costs (src_inner, dst_inner, speed, + x, mode)); + return false; + + case CALL: + case SIGN_EXTEND: + dst_inner = msp430_get_inner_dest_code (dst); + *total = COSTS_N_INSNS (msp430_single_op_cost (dst_inner, speed, x)); + if (mode == SImode) + *total *= 2; + if (mode == DImode) + *total *= 4; + return false; + + case CONST_INT: + case CONST_FIXED: + case CONST_DOUBLE: + case SYMBOL_REF: + case CONST: + case LABEL_REF: + case REG: + case PC: + case POST_INC: + if (mode == SImode) + *total = COSTS_N_INSNS (2); + else if (mode == DImode) + *total = COSTS_N_INSNS (4); + return true; + + case MEM: + /* PSImode operands are expensive when in memory. */ + if (mode == PSImode) + *total = COSTS_N_INSNS (1); + else if (mode == SImode) + *total = COSTS_N_INSNS (2); + else if (mode == DImode) + *total = COSTS_N_INSNS (4); + /* Recurse into the MEM. */ + return false; + + case EQ: + case NE: + case GT: + case GTU: + case GE: + case GEU: + case LT: + case LTU: + case LE: + case LEU: + /* Conditions are mostly equivalent, changing their relative + costs has no effect. */ + return false; + + case ASM_OPERANDS: + case ASM_INPUT: + case CLOBBER: + case COMPARE: + case CONCAT: + case ENTRY_VALUE: + /* Other unhandled expressions. */ + return false; + + default: + return false; } - return false; } /* Function Entry and Exit */ @@ -2947,8 +3413,7 @@ msp430_expand_helper (rtx *operands, const char *helper_name, /* Return TRUE if the helper function should be used and FALSE if the shifts insns should be emitted inline. */ static bool -use_helper_for_const_shift (enum rtx_code code, machine_mode mode, - HOST_WIDE_INT amt) +use_helper_for_const_shift (machine_mode mode, HOST_WIDE_INT amt) { const int default_inline_shift = 4; /* We initialize the option to 65 so we know if the user set it or not. */ @@ -2959,6 +3424,9 @@ use_helper_for_const_shift (enum rtx_code code, machine_mode mode, the heuristic accordingly. */ int max_inline_32 = max_inline / 2; + if (mode == E_DImode) + return true; + /* Don't use helpers for these modes on 430X, when optimizing for speed, or when emitting a small number of insns. */ if ((mode == E_QImode || mode == E_HImode || mode == E_PSImode) @@ -2996,7 +3464,7 @@ msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands) constant. */ if (!CONST_INT_P (operands[2]) || mode == E_DImode - || use_helper_for_const_shift (code, mode, INTVAL (operands[2]))) + || use_helper_for_const_shift (mode, INTVAL (operands[2]))) { const char *helper_name = NULL; /* The const variants of mspabi shifts have significantly larger code -- cgit v1.1 From 546c8f955804ad74b0382b012f64e621a02eebde Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 13 Nov 2020 15:35:47 +0000 Subject: MSP430: Add defaulting to the insn length attribute The length of MSP430 instructions is mostly just a function of the type and number of operands. Setting the "type" attribute on all insns describes the number of operands, and the position of the source and destination operands. In most cases, defaulting in the "length" and "extension" attribute definitions can then be used to calculate the total length of the instruction by using the value of the "type" attribute to examine the operands. gcc/ChangeLog: * config/msp430/msp430-protos.h (msp430x_extendhisi): Return int instead of char *. (msp430_output_asm_shift_insns): Likewise. Add new return_length argument. (msp430x_insn_required): Add prototype. * config/msp430/msp430.c (msp430_output_asm_shift_insns): Return the total length, in bytes, of the emitted instructions. (msp430x_insn_required): New function. (msp430x_extendhisi): Return the total length, in bytes, of the emitted instructions. * config/msp430/msp430.h (ADJUST_INSN_LENGTH): Define. * config/msp430/msp430.md: New define_attr "type". New define_attr "extension". New define_attr "length_multiplier". New define_attr "extra_length". Rewrite define_attr "length". Set type, extension, length, length_multiplier or extra_length insn attributes on all insns, as appropriate. (andneghi3): Rewrite using constraints instead of C code to decide output insns. * config/msp430/predicates.md (msp430_cheap_operand): New predicate. (msp430_high_memory_operand): New predicate. --- gcc/config/msp430/msp430-protos.h | 5 +- gcc/config/msp430/msp430.c | 162 ++++++++++---- gcc/config/msp430/msp430.h | 10 + gcc/config/msp430/msp430.md | 437 +++++++++++++++++++++++++++++++------- gcc/config/msp430/predicates.md | 13 ++ 5 files changed, 506 insertions(+), 121 deletions(-) (limited to 'gcc') diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index 0b4d9a4..33ad1ad 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -26,7 +26,7 @@ void msp430_expand_eh_return (rtx); void msp430_expand_epilogue (int); void msp430_expand_helper (rtx *operands, const char *, bool); void msp430_expand_prologue (void); -const char * msp430x_extendhisi (rtx *); +int msp430x_extendhisi (rtx *, bool); void msp430_fixup_compare_operands (machine_mode, rtx *); int msp430_hard_regno_nregs_has_padding (int, machine_mode); int msp430_hard_regno_nregs_with_padding (int, machine_mode); @@ -49,10 +49,11 @@ rtx msp430_subreg (machine_mode, rtx, machine_mode, int); bool msp430_use_f5_series_hwmult (void); bool msp430_has_hwmult (void); bool msp430_op_not_in_high_mem (rtx op); +bool msp430x_insn_required (rtx op); #ifdef RTX_CODE int msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands); -const char * msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands); +int msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands, bool); #endif #endif /* GCC_MSP430_PROTOS_H */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 9f76351..cc3472e 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -3520,18 +3520,22 @@ msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands) For 430X it is inneficient to do so for any modes except SI and DI, since we can make use of R*M insns or RPT with 430X insns, so this function is only used for SImode in that case. */ -const char * +int msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, - rtx *operands) + rtx *operands, bool return_length) { int i; int amt; int max_shift = GET_MODE_BITSIZE (mode) - 1; + int length = 0; + gcc_assert (CONST_INT_P (operands[2])); amt = INTVAL (operands[2]); if (amt == 0 || amt > max_shift) { + if (return_length) + return 0; switch (code) { case ASHIFT: @@ -3549,17 +3553,28 @@ msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, default: gcc_unreachable (); } - return ""; + return 0; } if (code == ASHIFT) { if (!msp430x && mode == HImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RLA.W\t%0", operands); + { + if (return_length) + length = 2 + (MEM_P (operands[0]) ? 2 : 0); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RLA.W\t%0", operands); + } else if (mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands); + { + if (return_length) + length = 4 + (MEM_P (operands[0]) ? 4 : 0) + + (4 * msp430x_insn_required (operands[0])); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands); + } else /* Catch unhandled cases. */ gcc_unreachable (); @@ -3567,33 +3582,61 @@ msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, else if (code == ASHIFTRT) { if (!msp430x && mode == HImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RRA.W\t%0", operands); + { + if (return_length) + length = 2 + (MEM_P (operands[0]) ? 2 : 0); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RRA.W\t%0", operands); + } else if (mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + { + if (return_length) + length = 4 + (MEM_P (operands[0]) ? 4 : 0) + + (4 * msp430x_insn_required (operands[0])); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + } else gcc_unreachable (); } else if (code == LSHIFTRT) { if (!msp430x && mode == HImode) - for (i = 0; i < amt; i++) - output_asm_insn ("CLRC { RRC.W\t%0", operands); + { + if (return_length) + length = 4 + (MEM_P (operands[0]) ? 2 : 0); + else + for (i = 0; i < amt; i++) + output_asm_insn ("CLRC { RRC.W\t%0", operands); + } else if (mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + { + if (return_length) + length = 6 + (MEM_P (operands[0]) ? 4 : 0) + + (4 * msp430x_insn_required (operands[0])); + else + for (i = 0; i < amt; i++) + output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", + operands); + } /* FIXME: Why doesn't "RRUX.W\t%H0 { RRC%X0.W\t%L0" work for msp430x? It causes execution timeouts e.g. pr41963.c. */ #if 0 else if (msp430x && mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands); + { + if (return_length) + length = 2; + else + for (i = 0; i < amt; i++) + output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands); + } #endif else gcc_unreachable (); } - return ""; + return length * amt; } /* Called by cbranch4 to coerce operands into usable forms. */ @@ -4115,6 +4158,20 @@ msp430_op_not_in_high_mem (rtx op) return false; } +/* Based on the operand OP, is a 430X insn required to handle it? + There are only 3 conditions for which a 430X insn is required: + - PSImode operand + - memory reference to a symbol which could be in upper memory + (so its address is > 0xFFFF) + - absolute address which has VOIDmode, i.e. (mem:HI (const_int)) + Use a 430 insn if none of these conditions are true. */ +bool +msp430x_insn_required (rtx op) +{ + return (GET_MODE (op) == PSImode + || !msp430_op_not_in_high_mem (op)); +} + #undef TARGET_PRINT_OPERAND #define TARGET_PRINT_OPERAND msp430_print_operand @@ -4455,35 +4512,52 @@ msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED, /* Generate a sequence of instructions to sign-extend an HI value into an SI value. Handles the tricky case where - we are overwriting the destination. */ - -const char * -msp430x_extendhisi (rtx * operands) + we are overwriting the destination. + Return the number of bytes used by the emitted instructions. + If RETURN_LENGTH is true then do not emit the assembly instruction + sequence. */ +int +msp430x_extendhisi (rtx * operands, bool return_length) { if (REGNO (operands[0]) == REGNO (operands[1])) - /* Low word of dest == source word. 8-byte sequence. */ - return "BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; - - if (! msp430x) - /* Note: This sequence is approximately the same length as invoking a helper - function to perform the sign-extension, as in: - - MOV.W %1, %L0 - MOV.W %1, r12 - CALL __mspabi_srai_15 - MOV.W r12, %H0 - - but this version does not involve any function calls or using argument - registers, so it reduces register pressure. 10-byte sequence. */ - return "MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 " - "{ INV.W\t%H0, %H0"; - - if (REGNO (operands[0]) + 1 == REGNO (operands[1])) - /* High word of dest == source word. 6-byte sequence. */ - return "MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0"; + { + /* Low word of dest == source word. */ + if (!return_length) + output_asm_insn ("BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0", + operands); + return 8; + } + else if (! msp430x) + { + /* Note: This sequence is approximately the same length as invoking a + helper function to perform the sign-extension, as in: + + MOV.W %1, %L0 + MOV.W %1, r12 + CALL __mspabi_srai_15 + MOV.W r12, %H0 + + but this version does not involve any function calls or using argument + registers, so it reduces register pressure. */ + if (!return_length) + output_asm_insn ("MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0", + operands); + return 10; + } + else if (REGNO (operands[0]) + 1 == REGNO (operands[1])) + { + /* High word of dest == source word. */ + if (!return_length) + output_asm_insn ("MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0", + operands); + return 6; + } - /* No overlap between dest and source. 8-byte sequence. */ - return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; + /* No overlap between dest and source. */ + if (!return_length) + output_asm_insn ("MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0", + operands); + return 8; } /* Stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index 2500771..c2fcaef 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -530,3 +530,13 @@ void msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED, #define SYMBOL_FLAG_LOW_MEM (SYMBOL_FLAG_MACH_DEP << 0) + +#define ADJUST_INSN_LENGTH(insn, length) \ + do \ + { \ + if (recog_memoized (insn) >= 0) \ + { \ + length += get_attr_extra_length (insn); \ + length *= get_attr_length_multiplier (insn); \ + } \ + } while (0) diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index ad244bb..65e9517 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -58,8 +58,100 @@ UNS_DELAY_END ]) -;; This is an approximation. -(define_attr "length" "" (const_int 4)) +;; Instruction length is calculated by examining the type and number of +;; operands. +;; Whether the insn uses the 430X extension word, or is a 430X address +;; instruction also has an effect. +;; "Cheap" source operands do not contribute to the overall length of the insn +;; and are register (Rn), indirect post-increment (@Rn+) and indirect register +;; (@Rn). +;; The lengths of instructions in bytes are: +;; Single-op 430: Cheap op == 2 +;; (also CALLA) Other op == 4 +;; Double-op 430: Source is not cheap == 2 +;; (also MOVA, Dest is register == 2 +;; CMPA, ADDA, Dest is not a register == 4 +;; SUBA) (sum the source and dest cost) +;; Single-op 430X: For insn names ending in 'X' add 2 to single-op 430 cost. +;; Double-op 430X: Insn name ends in 'M' == 2 +;; Others have the same cost as double-op 430 but add 2. +;; +;; The insn type describes whether it is a single or double operand MSP430 +;; instruction (some single-operand GCC instructions are actually +;; double-operand on the target). +;; "triple" and "cmp" types use the costs of a double operand type but +;; instead assume that the src operand is in op2, and also cmp types assume the +;; dst operand is in op1. +;; This attribute also describes which operands are safe to examine +;; when calculating the length or extension. GCC will segfault trying to +;; examine a non-existant operand of an insn. +(define_attr "type" "none,single,double,triple,cmp" (const_string "none")) + +;; The M extension is for instructions like RRAM - they always +;; only, and the operand must be a register. +(define_attr "extension" "none,x,a,m" + (cond [(eq_attr "type" "none") + (const_string "none") + (match_operand 0 "msp430_high_memory_operand" "") + (const_string "x") + (and (eq_attr "type" "double") + (match_operand 1 "msp430_high_memory_operand" "")) + (const_string "x") + (and (ior (eq_attr "type" "triple") (eq_attr "type" "cmp")) + (ior (match_operand 1 "msp430_high_memory_operand" "") + (match_operand 2 "msp430_high_memory_operand" ""))) + (const_string "x")] + (const_string "none"))) + +;; Multiply the default length by this constant value. +(define_attr "length_multiplier" "" (const_int 1)) + +;; Add an additional amount to the total length of the insn. +(define_attr "extra_length" "" (const_int 0)) + +;; FIXME for some reason if we move the addition of 2 for extension == x to +;; ADJUST_INSN_LENGTH, codesize gets much worse. +(define_attr "length" "" + (cond [(eq_attr "extension" "m") + (const_int 2) + (eq_attr "type" "single") + (plus (if_then_else (match_operand 0 "msp430_cheap_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0))) + (eq_attr "type" "double") + (plus (plus (if_then_else (match_operand 0 "register_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (match_operand 1 "msp430_cheap_operand" "") + (const_int 0) + (const_int 2))) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0))) + (eq_attr "type" "triple") + (plus (plus (if_then_else (match_operand 0 "register_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (match_operand 2 "msp430_cheap_operand" "") + (const_int 0) + (const_int 2))) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0))) + (eq_attr "type" "cmp") + (plus (plus (if_then_else (match_operand 1 "register_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (match_operand 2 "msp430_cheap_operand" "") + (const_int 0) + (const_int 2))) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0)))] + (const_int 2))) (include "predicates.md") (include "constraints.md") @@ -97,35 +189,43 @@ (match_operand:HI 0 "register_operand" "r"))] "" "PUSH\t%0" - ) + [(set_attr "type" "single")] +) (define_insn "pusha" [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO))) (match_operand:PSI 0 "register_operand" "r"))] "TARGET_LARGE" "PUSHX.A\t%0" - ) + [(set_attr "type" "single") + (set_attr "extension" "x")] +) (define_insn "pushm" [(unspec_volatile [(match_operand 0 "register_operand" "r") (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)] "" "PUSHM%b0\t%1, %0" - ) + [(set_attr "type" "single") + (set_attr "extension" "m")] +) (define_insn "pop" [(set (match_operand:HI 0 "register_operand" "=r") (mem:HI (post_inc:HI (reg:HI SP_REGNO))))] "" "POP\t%0" - ) + [(set_attr "type" "single")] +) (define_insn "popa" [(set (match_operand:PSI 0 "register_operand" "=r") (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))] "TARGET_LARGE" "POPX.A\t%0" - ) + [(set_attr "type" "single") + (set_attr "extension" "x")] +) ;; This is nasty. Operand0 is bogus. It is only there so that we can get a ;; mode for the %b0 to work. We should use operand1 for this, but that does @@ -144,7 +244,9 @@ (match_operand 2 "immediate_operand" "i")] UNS_POPM)] "" "POPM%b0\t%2, r%J1" - ) + [(set_attr "type" "single") + (set_attr "extension" "m")] +) ;; The next two patterns are here to support a "feature" of how GCC implements ;; varargs. When a function uses varargs and the *second* to last named @@ -170,6 +272,10 @@ return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\"; return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\"; " + [(set (attr "length") + (if_then_else (match_test "TARGET_LARGE") + (const_int 8) + (const_int 6)))] ) (define_insn "swap_and_shrink" @@ -178,7 +284,12 @@ "* return TARGET_LARGE ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\" : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\"; - ") + " + [(set (attr "length") + (if_then_else (match_test "TARGET_LARGE") + (const_int 10) + (const_int 8)))] +) ; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a ; zero_extend anyway. Catch it here. @@ -189,6 +300,7 @@ "@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "movqi_topbyte" @@ -196,6 +308,8 @@ (subreg:QI (match_operand:PSI 1 "msp430_general_operand" "r") 2))] "msp430x" "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0" + [(set_attr "length" "6") + (set_attr "type" "double")] ) (define_insn "movqi" @@ -205,6 +319,7 @@ "@ MOV.B\t%1, %0 MOVX.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "movhi" @@ -215,6 +330,7 @@ MOV.B\t%1, %0 MOV.W\t%1, %0 MOVX.W\t%1, %0" + [(set_attr "type" "double")] ) (define_expand "movsi" @@ -222,7 +338,7 @@ (match_operand:SI 1 "general_operand"))] "" "" - ) +) (define_insn_and_split "movsi_s" [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") @@ -235,7 +351,8 @@ (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") (match_operand:HI 5 "general_operand"))] "msp430_split_movsi (operands);" - ) + [(set_attr "type" "double")] +) (define_insn_and_split "movsi_x" [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") @@ -248,6 +365,7 @@ (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") (match_operand:HI 5 "general_operand"))] "msp430_split_movsi (operands);" + [(set_attr "type" "double")] ) ;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them. @@ -260,7 +378,10 @@ MOV.W\t%1, %0 MOVA\t%1, %0 MOVA\t%1, %0 - MOVX.A\t%1, %0") + MOVX.A\t%1, %0" + [(set_attr "extension" "none,none,a,a,x") + (set_attr "type" "double")] +) ; This pattern is identical to the truncsipsi2 pattern except ; that it uses a SUBREG instead of a TRUNC. It is needed in @@ -274,6 +395,8 @@ (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))] "msp430x" "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0" + [(set_attr "length" "6") + (set_attr "type" "double")] ) ;; Produced when converting a pointer to an integer via a union, eg gcc.dg/pr47201.c. @@ -282,6 +405,8 @@ (subreg:HI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] "msp430x" "MOVA\t%1, %0" + [(set_attr "extension" "a") + (set_attr "type" "double")] ) ;;------------------------------------------------------------ @@ -295,6 +420,8 @@ "@ ADDA\t%2, %0 ADDX.A\t%2, %0" + [(set_attr "extension" "a,x") + (set_attr "type" "triple")] ) (define_insn "addqi3" @@ -305,6 +432,7 @@ "@ ADD.B\t%2, %0 ADDX.B\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "addhi3" @@ -315,6 +443,7 @@ "@ ADD.W\t%2, %0 ADDX.W\t%2, %0" + [(set_attr "type" "triple")] ) ; This pattern is needed in order to avoid reload problems. @@ -327,6 +456,13 @@ (match_operand 2 "general_operand" "rmi")))] "" "ADD%X2.W\t%L2, %L0 { ADDC%X2.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0" + [(set (attr "length") + (if_then_else (match_operand 2 "register_operand" "") + (const_int 10) + (if_then_else (match_operand 2 "msp430_high_memory_operand" "") + (const_int 18) + (const_int 14)))) + (set_attr "type" "triple")] ) (define_insn "addsi3" @@ -337,6 +473,8 @@ "@ ADD\t%L2, %L0 { ADDC\t%H2, %H0 ADDX\t%L2, %L0 { ADDCX\t%H2, %H0" + [(set_attr "length_multiplier" "2") + (set_attr "type" "triple")] ) ; Version of addhi that exposes the carry operations, for SImode adds. @@ -382,7 +520,8 @@ "@ ADD\t%2, %1 ; cy ADDX\t%2, %1 ; cy" - ) + [(set_attr "type" "triple")] +) (define_insn "addhi3_cy_i" [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=r,rm") @@ -397,7 +536,8 @@ "@ ADD\t%2, %1 ; cy ADD%X0\t%2, %1 ; cy" - ) + [(set_attr "type" "triple")] +) ; Version of addhi that adds the carry, for SImode adds. (define_insn "addchi4_cy" @@ -410,7 +550,8 @@ "@ ADDC\t%2, %1 ADDCX\t%2, %1" - ) + [(set_attr "type" "triple")] +) ; Split an SImode add into two HImode adds, keeping track of the carry ; so that gcc knows when it can and can't optimize away the two @@ -440,7 +581,7 @@ if (msp430_split_addsi (operands)) FAIL; " - ) +) ;; Alternatives 2 and 3 are to handle cases generated by reload. @@ -454,6 +595,9 @@ SUBX.A\t%2, %0 MOVX.A\t%1, %0 { SUBX.A\t%2, %0 MOVX.A\t%1, %0 { SUBA\t%2, %0" + [(set_attr "type" "triple") + (set_attr "extension" "a,x,x,x") + (set_attr "length_multiplier" "1,1,2,2")] ) ;; Alternatives 2 and 3 are to handle cases generated by reload. @@ -467,6 +611,8 @@ SUBX.B\t%2, %0 MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0 MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" + [(set_attr "length_multiplier" "1,1,2,2") + (set_attr "type" "triple")] ) ;; Alternatives 2 and 3 are to handle cases generated by reload. @@ -480,6 +626,8 @@ SUBX.W\t%2, %0 MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0 MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" + [(set_attr "length_multiplier" "1,1,2,2") + (set_attr "type" "triple")] ) (define_insn "subsi3" @@ -490,6 +638,8 @@ "@ SUB\t%L2, %L0 { SUBC\t%H2, %H0 SUBX\t%L2, %L0 { SUBCX\t%H2, %H0" + [(set_attr "length_multiplier" "2") + (set_attr "type" "triple")] ) (define_insn "*bic_cg" @@ -500,6 +650,8 @@ "@ BIC%x0%b0\t#%I2, %0 BIC%X0%b0\t#%I2, %0" + [(set_attr "length" "2") ; Smaller length achieved by using constant generator + (set_attr "type" "double")] ) (define_insn "bic3" @@ -510,6 +662,7 @@ "@ BIC%x0%b0\t%1, %0 BICX%b0\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "and3" @@ -521,6 +674,7 @@ AND%x0.B\t%2, %0 AND%x0%b0\t%2, %0 ANDX%b0\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "ior3" @@ -531,6 +685,7 @@ "@ BIS%x0%b0\t%2, %0 BISX%b0\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "xor3" @@ -541,6 +696,7 @@ "@ XOR%x0%b0\t%2, %0 XORX%b0\t%2, %0" + [(set_attr "type" "triple")] ) ;; Macro : XOR #~0, %0 @@ -551,6 +707,7 @@ "@ INV%x0%b0\t%0 INV%X0%b0\t%0" + [(set_attr "type" "double")] ) (define_insn "extendqihi2" @@ -560,6 +717,7 @@ "@ SXT%X0\t%0 SXT%X0\t%0" + [(set_attr "type" "single")] ) (define_insn "extendqipsi2" @@ -569,6 +727,8 @@ "@ SXT\t%0 SXTX.A\t%0" + [(set_attr "type" "single") + (set_attr "extension" "none,x")] ) ;; ------------------------ @@ -590,6 +750,7 @@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0 AND%X0\t#0xff, %0" + [(set_attr "type" "double")] ) (define_insn "zero_extendqipsi2" @@ -599,6 +760,7 @@ "@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "zero_extendqisi2" @@ -608,6 +770,9 @@ "@ CLR\t%H0 MOV%X1.B\t%1,%L0 { CLR\t%H0" + [(set_attr "extra_length" "2") + (set_attr "length_multiplier" "1,2") + (set_attr "type" "double")] ) (define_insn "zero_extendhipsi2" @@ -618,6 +783,7 @@ MOV.W\t%1, %0 MOV%X1\t%1, %0 MOVX.A\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "zero_extendhisi2" @@ -627,6 +793,8 @@ "@ MOV%X0.W\t#0,%H0 MOV.W\t%1,%L0 { MOV.W\t#0,%H0" + [(set_attr "length_multiplier" "1,2") + (set_attr "type" "double")] ) (define_insn "zero_extendhisipsi2" @@ -636,6 +804,8 @@ "@ AND.W\t#-1,%0 MOV.W\t%1,%0" + [(set_attr "length" "4,2") + (set_attr "type" "double")] ) ; Nasty - we are sign-extending a 20-bit PSI value in one register into @@ -671,6 +841,13 @@ else \ return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\"; MOVX.A %1, %0" + [(set (attr "length") + (cond [(match_test "REGNO (operands[1]) == SP_REGNO") + (const_int 18) + (eq_attr "alternative" "1") + (const_int 6)] + (const_int 10))) + (set_attr "type" "double")] ) ;; Below are unnamed insn patterns to catch pointer manipulation insns @@ -687,6 +864,7 @@ (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))] "msp430x" "MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "" @@ -696,6 +874,7 @@ "@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) ;; The next three insns emit identical assembly code. @@ -711,6 +890,9 @@ RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" + [(set_attr "length" "4,*,*") + (set_attr "extra_length" "0,4,6") + (set_attr "type" "double")] ) (define_insn "" @@ -722,6 +904,9 @@ RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" + [(set_attr "length" "4,*,*") + (set_attr "extra_length" "0,4,6") + (set_attr "type" "double")] ) ;; Same as above but with a NOP sign_extend round the subreg @@ -734,6 +919,9 @@ RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" + [(set_attr "length" "4,*,*") + (set_attr "extra_length" "0,4,6") + (set_attr "type" "double")] ) (define_insn "" @@ -741,6 +929,8 @@ (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))))] "msp430x" "MOV%X1.B %1, %L0 { CLR %H0" + [(set_attr "extra_length" "4") + (set_attr "type" "double")] ) (define_insn "" @@ -752,6 +942,9 @@ RLAM.W %2, %0 MOV%X1.B %1, %0 { RLAM.W %2, %0 MOV%X1.B %1, %0 { RPT %2 { RLAX.A %0" + [(set_attr "length" "2,*,*") + (set_attr "extra_length" "0,2,4") + (set_attr "type" "double")] ) ;; END msp430 pointer manipulation combine insn patterns @@ -771,13 +964,18 @@ (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] "" "MOVX\t%1, %0" + [(set_attr "extension" "m") + (set_attr "type" "double")] ) (define_insn "extendhisi2" [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))] "" - { return msp430x_extendhisi (operands); } + { msp430x_extendhisi (operands, 0); return ""; } + [(set (attr "length") + (symbol_ref "msp430x_extendhisi (operands, 1)")) + (set_attr "type" "double")] ) (define_insn "extendhipsi2" @@ -785,6 +983,9 @@ (subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))] "msp430x" "RLAM.A #4, %0 { RRAM.A #4, %0" + [(set_attr "length_multiplier" "2") + (set_attr "extension" "m") + (set_attr "type" "double")] ) ;; Look for cases where integer/pointer conversions are suboptimal due @@ -798,6 +999,9 @@ (const_int 1)))] "msp430x" "RLAM.A #4, %0 { RRAM.A #3, %0" + [(set_attr "length_multiplier" "2") + (set_attr "extension" "m") + (set_attr "type" "double")] ) (define_insn "extend_and_shift2_hipsi2" @@ -806,6 +1010,9 @@ (const_int 2)))] "msp430x" "RLAM.A #4, %0 { RRAM.A #2, %0" + [(set_attr "length_multiplier" "2") + (set_attr "extension" "m") + (set_attr "type" "double")] ) ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t). @@ -827,6 +1034,8 @@ else return \"MOV.W\t%1, %L0 { MOVX.A\t%1, %H0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\"; " + [(set_attr "length" "10") + (set_attr "type" "double")] ) ; See the movsipsi2 pattern above for another way that GCC performs this @@ -836,6 +1045,8 @@ (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] "" "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0" + [(set_attr "length" "6") + (set_attr "type" "single")] ) ;;------------------------------------------------------------ @@ -886,7 +1097,10 @@ (any_shift:HI (match_operand:HI 1 "general_operand" "0") (match_operand:HI 2 "const_int_operand" "n")))] "!msp430x" - "* return msp430_output_asm_shift_insns (, HImode, operands);" + "* msp430_output_asm_shift_insns (, HImode, operands, false); return \"\";" + [(set (attr "length") + (symbol_ref "msp430_output_asm_shift_insns (, HImode, operands, true)")) + (set_attr "type" "single")] ) ;; All 430 and 430X SImode constant shifts @@ -895,7 +1109,10 @@ (any_shift:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "const_int_operand" "n")))] "" - "* return msp430_output_asm_shift_insns (, SImode, operands);" + "* msp430_output_asm_shift_insns (, SImode, operands, false); return \"\";" + [(set (attr "length") + (symbol_ref "msp430_output_asm_shift_insns (, SImode, operands, true)")) + (set_attr "type" "single")] ) (define_insn "ashl3_430x" @@ -908,6 +1125,8 @@ RPT\t%2 { RLAX%b0\t%0 RPT\t#16 { RLAX%b0\t%0 { RPT\t%W2 { RLAX%b0\t%0 # undefined behavior left shift of %1 by %2" + [(set_attr "length" "2,4,8,0") + (set_attr "type" "single")] ) (define_insn "ashr3_430x" @@ -920,6 +1139,8 @@ RPT\t%2 { RRAX%b0\t%0 RPT\t#16 { RRAX%b0\t%0 { RPT\t%W2 { RRAX%b0\t%0 # undefined behavior arithmetic right shift of %1 by %2" + [(set_attr "length" "2,4,8,0") + (set_attr "type" "single")] ) (define_insn "lshr3_430x" @@ -932,6 +1153,8 @@ RPT\t%2 { RRUX%b0\t%0 RPT\t#16 { RRUX%b0\t%0 { RPT\t%W2 { RRUX%b0\t%0 # undefined behavior logical right shift of %1 by %2" + [(set_attr "length" "2,4,8,0") + (set_attr "type" "single")] ) ;;------------------------------------------------------------ @@ -941,39 +1164,43 @@ [(const_int 0)] "" "msp430_expand_prologue (); DONE;" - ) +) (define_expand "epilogue" [(const_int 0)] "" "msp430_expand_epilogue (0); DONE;" - ) +) (define_insn "epilogue_helper" [(set (pc) - (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)) + (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)) (return)] - "" + "!msp430x" "BR%Q0\t#__mspabi_func_epilog_%J0" - ) + [(set_attr "length" "2")] +) (define_insn "prologue_start_marker" [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] "" "; start of prologue" - ) + [(set_attr "length" "0")] +) (define_insn "prologue_end_marker" [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] "" "; end of prologue" - ) + [(set_attr "length" "0")] +) (define_insn "epilogue_start_marker" [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] "" "; start of epilogue" - ) + [(set_attr "length" "0")] +) ;; This makes the linker add a call to exit() after the call to main() ;; in crt0 @@ -981,7 +1208,8 @@ [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)] "" ".refsym\t__crt0_call_exit" - ) + [(set_attr "length" "0")] +) ;;------------------------------------------------------------ ;; Jumps @@ -998,6 +1226,8 @@ (match_operand 1 ""))] "" "CALL%Q0\t%0" + [(set_attr "extension" "none") + (set_attr "type" "single")] ) (define_expand "call_value" @@ -1014,12 +1244,15 @@ (match_operand 2 "")))] "" "CALL%Q0\t%1" + [(set_attr "extension" "none") + (set_attr "type" "single")] ) (define_insn "msp430_return" [(return)] "" { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); } + [(set_attr "length" "2")] ) ;; This pattern is NOT, as expected, a return pattern. It's called @@ -1045,13 +1278,15 @@ "reload_completed" [(const_int 0)] "msp430_expand_epilogue (1); DONE;" - ) + [(set_attr "length" "40")] +) (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "BR%Q0\t#%l0" + [(set_attr "length" "4")] ) ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs @@ -1061,6 +1296,10 @@ (match_operand 0 "nonimmediate_operand" "rYl"))] "" "BR%Q0\t%0" + [(set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_int 2) + (const_int 4)))] ) ;;------------------------------------------------------------ @@ -1077,14 +1316,14 @@ )] "" "msp430_fixup_compare_operands (mode, operands);" - ) +) (define_insn "cbranchpsi4_real" [(set (pc) (if_then_else (match_operator 0 "msp430_cmp_operator" [(match_operand:PSI 1 "msp430_general_dst_nonv_operand" "r,rYs,rm") (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) - (label_ref (match_operand 3 "" "")) + (label_ref (match_operand 3 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1093,7 +1332,9 @@ CMP%Q0\t%2, %1 { J%0\t%l3 CMPX.A\t%2, %1 { J%0\t%l3 CMPX.A\t%2, %1 { J%0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchqi4_real" [(set (pc) (if_then_else @@ -1108,7 +1349,9 @@ "@ CMP.B\t%2, %1 { J%0\t%l3 CMPX.B\t%2, %1 { J%0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchhi4_real" [(set (pc) (if_then_else @@ -1123,6 +1366,8 @@ "@ CMP.W\t%2, %1 { J%0\t%l3 CMPX.W\t%2, %1 { J%0\t%l3" + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] ) (define_insn "cbranchpsi4_reversed" @@ -1139,7 +1384,9 @@ CMP%Q0\t%1, %2 { J%R0\t%l3 CMPX.A\t%1, %2 { J%R0\t%l3 CMPX.A\t%1, %2 { J%R0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchqi4_reversed" [(set (pc) (if_then_else @@ -1154,7 +1401,9 @@ "@ CMP.B\t%1, %2 { J%R0\t%l3 CMPX.B\t%1, %2 { J%R0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchhi4_reversed" [(set (pc) (if_then_else @@ -1169,14 +1418,16 @@ "@ CMP.W\t%1, %2 { J%R0\t%l3 CMPX.W\t%1, %2 { J%R0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "*bitbranch4" [(set (pc) (if_then_else (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1184,14 +1435,16 @@ "@ BIT%x0%b0\t%1, %0 { JNE\t%l2 BITX%b0\t%1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch4" [(set (pc) (if_then_else (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1199,14 +1452,16 @@ "@ BIT%x0%b0\t%1, %0 { JEQ\t%l2 BITX%b0\t%1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch4" [(set (pc) (if_then_else (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] @@ -1214,14 +1469,16 @@ "@ BIT%x0%b0\t%1, %0 { JNE\t%l2 BITX%b0\t%1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch4" [(set (pc) (if_then_else (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] @@ -1229,7 +1486,9 @@ "@ BIT%x0%b0\t%1, %0 { JEQ\t%l2 BITX%b0\t%1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) ;;------------------------------------------------------------ ;; zero-extract versions of the above @@ -1240,7 +1499,7 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i,i")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1248,7 +1507,9 @@ "@ BIT%x0%b0\t%p1, %0 { JNE\t%l2 BIT%X0%b0\t%p1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch4_z" [(set (pc) (if_then_else @@ -1256,13 +1517,15 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] "" "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch4_z" [(set (pc) (if_then_else @@ -1270,13 +1533,15 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] "" "BIT%X0%b0\t%p1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch4_z" [(set (pc) (if_then_else @@ -1284,13 +1549,15 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] "" "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) ;;------------------------------------------------------------ ;; Misc @@ -1299,31 +1566,36 @@ [(const_int 0)] "1" "NOP" + [(set_attr "length" "2")] ) (define_insn "disable_interrupts" [(unspec_volatile [(const_int 0)] UNS_DINT)] "" "DINT \; NOP" - ) + [(set_attr "length" "2")] +) (define_insn "enable_interrupts" [(unspec_volatile [(const_int 0)] UNS_EINT)] "" "EINT" - ) + [(set_attr "length" "2")] +) (define_insn "push_intr_state" [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)] "" "PUSH\tSR" - ) + [(set_attr "length" "2")] +) (define_insn "pop_intr_state" [(unspec_volatile [(const_int 0)] UNS_POP_INTR)] "" "POP\tSR" - ) + [(set_attr "length" "2")] +) ;; Clear bits in the copy of the status register that is currently ;; saved on the stack at the top of the interrupt handler. @@ -1331,7 +1603,9 @@ [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)] "" "BIC.W\t%0, %O0(SP)" - ) + [(set_attr "type" "single") + (set_attr "extra_length" "2")] +) ;; Set bits in the copy of the status register that is currently ;; saved on the stack at the top of the interrupt handler. @@ -1339,30 +1613,33 @@ [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)] "" "BIS.W\t%0, %O0(SP)" - ) + [(set_attr "type" "single") + (set_attr "extra_length" "2")] +) ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int))) ;; very late on in the compilation and not splitting it into separate ;; instructions, so we provide a pattern to support it here. (define_insn "andneghi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (and:HI (neg:HI (match_operand:HI 1 "general_operand" "rm")) - (match_operand 2 "immediate_operand" "n")))] + [(set (match_operand:HI 0 "register_operand" "=r,r") + (and:HI (neg:HI (match_operand:HI 1 "general_operand" "0,rm")) + (match_operand 2 "immediate_operand" "n,n")))] "" - "* - if (REGNO (operands[0]) != REGNO (operands[1])) - return \"MOV%X1.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; - else - return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; - " - ) + "@ + INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0 + MOV%X1.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0" + [(set_attr "length" "12,14") + (set_attr "type" "double")] +) + (define_insn "delay_cycles_start" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_DELAY_START)] "" "; Begin %J0 cycle delay" - ) + [(set_attr "length" "0")] +) (define_insn "delay_cycles_end" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] @@ -1387,7 +1664,8 @@ JNE 1b POP r14 POP r13" - ) + [(set_attr "length" "32")] +) (define_insn "delay_cycles_32x" [(unspec_volatile [(match_operand 0 "immediate_operand" "i") @@ -1403,7 +1681,8 @@ TST.W r13 JNE 1b POPM.A #2,r14" - ) + [(set_attr "length" "28")] +) (define_insn "delay_cycles_16" [(unspec_volatile [(match_operand 0 "immediate_operand" "i") @@ -1415,7 +1694,8 @@ 1: SUB.W #1, r13 JNE 1b POP r13" - ) + [(set_attr "length" "14")] +) (define_insn "delay_cycles_16x" [(unspec_volatile [(match_operand 0 "immediate_operand" "i") @@ -1427,19 +1707,22 @@ 1: SUB.W #1, r13 JNE 1b POPM.A #1,r13" - ) + [(set_attr "length" "14")] +) (define_insn "delay_cycles_2" [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] "" "JMP .+2" - ) + [(set_attr "length" "2")] +) (define_insn "delay_cycles_1" [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] "" "NOP" - ) + [(set_attr "length" "2")] +) ; libgcc helper functions for widening multiplication aren't currently ; generated by gcc, so we can't catch them later and map them to the mspabi @@ -1494,6 +1777,7 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; " + [(set_attr "length" "24")] ) (define_insn "*umulhisi3_inline" @@ -1507,6 +1791,7 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; " + [(set_attr "length" "24")] ) (define_insn "mulsidi3" @@ -1520,6 +1805,7 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; " + [(set_attr "length" "40")] ) (define_insn "umulsidi3" @@ -1533,4 +1819,5 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0140 { MOV.W %H1, &0x0142 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; " + [(set_attr "length" "40")] ) diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md index 4bfa0c0..eb1f61d 100644 --- a/gcc/config/msp430/predicates.md +++ b/gcc/config/msp430/predicates.md @@ -131,3 +131,16 @@ (define_predicate "msp430_symbol_operand" (match_code "symbol_ref") ) + +; Used in length attribute tests - if a source operand is a reg, +; (mem (post_inc)), or (mem (reg)) then it is cheap compared to other operand +; types. +(define_predicate "msp430_cheap_operand" + (ior (match_code "reg") + (and (match_code "mem") + (ior (match_code "reg" "0") + (match_code "post_inc" "0"))))) + +; Used for insn attributes only. For insn patterns themselves, use constraints. +(define_predicate "msp430_high_memory_operand" + (match_test "msp430x_insn_required (op)")) -- cgit v1.1 From 54896b10dbe1d4ac90f097d566b7aa14807cec08 Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 13 Nov 2020 15:35:52 +0000 Subject: MSP430: Implement TARGET_INSN_COST The length of an insn can be used to calculate its cost, when optimizing for size. When optimizing for speed, this is a good estimate, since the cycle cost of an MSP430 instruction increases with its length. gcc/ChangeLog: * config/msp430/msp430.c (TARGET_INSN_COST): Define. (msp430_insn_cost): New function. * config/msp430/msp430.h (BRANCH_COST): Define. (LOGICAL_OP_NON_SHORT_CIRCUIT): Define. gcc/testsuite/ChangeLog: * gcc.target/msp430/rtx-cost-O3-default.c: New test. * gcc.target/msp430/rtx-cost-O3-f5series.c: New test. * gcc.target/msp430/rtx-cost-Os-default.c: New test. * gcc.target/msp430/rtx-cost-Os-f5series.c: New test. --- gcc/config/msp430/msp430.c | 25 ++++++++++--- gcc/config/msp430/msp430.h | 8 ++++ .../gcc.target/msp430/rtx-cost-O3-default.c | 42 +++++++++++++++++++++ .../gcc.target/msp430/rtx-cost-O3-f5series.c | 38 +++++++++++++++++++ .../gcc.target/msp430/rtx-cost-Os-default.c | 43 ++++++++++++++++++++++ .../gcc.target/msp430/rtx-cost-Os-f5series.c | 38 +++++++++++++++++++ 6 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/msp430/rtx-cost-O3-default.c create mode 100644 gcc/testsuite/gcc.target/msp430/rtx-cost-O3-f5series.c create mode 100644 gcc/testsuite/gcc.target/msp430/rtx-cost-Os-default.c create mode 100644 gcc/testsuite/gcc.target/msp430/rtx-cost-Os-f5series.c (limited to 'gcc') diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index cc3472e..e98de8d 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -1181,11 +1181,6 @@ msp430_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED, return 2 * cost; } -/* BRANCH_COST - Changing from the default of 1 doesn't affect code generation, presumably - because there are no conditional move insns - when a condition is involved, - the only option is to use a cbranch. */ - /* For X, which must be a MEM RTX, return TRUE if it is an indirect memory reference, @Rn or @Rn+. */ static bool @@ -1650,6 +1645,26 @@ msp430_rtx_costs (rtx x, return false; } } + +#undef TARGET_INSN_COST +#define TARGET_INSN_COST msp430_insn_cost + +static int +msp430_insn_cost (rtx_insn *insn, bool speed ATTRIBUTE_UNUSED) +{ + if (recog_memoized (insn) < 0) + return 0; + + /* The returned cost must be relative to COSTS_N_INSNS (1). An insn with a + length of 2 bytes is the smallest possible size and so must be equivalent + to COSTS_N_INSNS (1). */ + return COSTS_N_INSNS (get_attr_length (insn) / 2); + + /* FIXME Add more detailed costs when optimizing for speed. + For now the length of the instruction is a good approximiation and roughly + correlates with cycle cost. */ +} + /* Function Entry and Exit */ diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index c2fcaef..049151e 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -243,6 +243,14 @@ extern const char *msp430_get_linker_devices_include_path (int, const char **); #define HAS_LONG_COND_BRANCH 0 #define HAS_LONG_UNCOND_BRANCH 0 +/* The cost of a branch sequence is roughly 3 "cheap" instructions. */ +#define BRANCH_COST(speed_p, predictable_p) 3 + +/* Override the default BRANCH_COST heuristic to indicate that it is preferable + to retain short-circuit operations, this results in significantly better + codesize and performance. */ +#define LOGICAL_OP_NON_SHORT_CIRCUIT 0 + #define LOAD_EXTEND_OP(M) ZERO_EXTEND #define WORD_REGISTER_OPERATIONS 1 diff --git a/gcc/testsuite/gcc.target/msp430/rtx-cost-O3-default.c b/gcc/testsuite/gcc.target/msp430/rtx-cost-O3-default.c new file mode 100644 index 0000000..1bd6a14 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/rtx-cost-O3-default.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Verify the MSP430 cost model is working as expected for the default ISA + (msp430x) and hwmult (none), when compiling at -O3. */ + +char arr[2]; +char a; +char *ptr; + +/* +** foo: +** ... +** MOV.B \&a, \&arr\+1 +** MOV.* #arr\+2, \&ptr +** ... +*/ + +void +foo (void) +{ + arr[1] = a; + ptr = arr + 2; +} + +extern void ext (void); + +/* +** bar: +** ... +** CALL.* #ext +** CALL.* #ext +** ... +*/ + +void +bar (void) +{ + ext (); + ext (); +} diff --git a/gcc/testsuite/gcc.target/msp430/rtx-cost-O3-f5series.c b/gcc/testsuite/gcc.target/msp430/rtx-cost-O3-f5series.c new file mode 100644 index 0000000..1e48625 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/rtx-cost-O3-f5series.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -mhwmult=f5series" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Verify the MSP430 cost model is working as expected for the default ISA + (msp430x) and f5series hwmult, when compiling at -O3. */ + +volatile unsigned long a; +volatile unsigned int b; +volatile unsigned long c; +unsigned long res1; +unsigned long res2; +unsigned long res3; + +/* +** foo: +** ... +** MOV.B #16, R14 +** CALL.* #__mspabi_slll +** ... +** MOV.* \&res2.* +** ... +** RLA.*RLC.* +** ... +** MOV.* \&res3.* +** ... +** RLA.*RLC.* +** ... +*/ +void foo (void) +{ + /* Use the shift library function for this. */ + res1 = (a << 16) | b; + /* Emit 7 inline shifts for this. */ + res2 *= 128; + /* Perform this multiplication inline, using addition and shifts. */ + res3 *= 100; +} diff --git a/gcc/testsuite/gcc.target/msp430/rtx-cost-Os-default.c b/gcc/testsuite/gcc.target/msp430/rtx-cost-Os-default.c new file mode 100644 index 0000000..8f3d1b2 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/rtx-cost-Os-default.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Verify the MSP430 cost model is working as expected for the default ISA + (msp430x) and hwmult (none), when compiling at -Os. */ + +char arr[2]; +char a; +char *ptr; + +/* +** foo: +** ... +** MOV.B \&a, \&arr\+1 +** MOV.* #arr\+2, \&ptr +** ... +*/ + +void +foo (void) +{ + arr[1] = a; + ptr = arr + 2; +} + +extern void ext (void); + +/* +** bar: +** ... +** MOV.* #ext, R10 +** CALL.* R10 +** CALL.* R10 +** ... +*/ + +void +bar (void) +{ + ext (); + ext (); +} diff --git a/gcc/testsuite/gcc.target/msp430/rtx-cost-Os-f5series.c b/gcc/testsuite/gcc.target/msp430/rtx-cost-Os-f5series.c new file mode 100644 index 0000000..bb37f90 --- /dev/null +++ b/gcc/testsuite/gcc.target/msp430/rtx-cost-Os-f5series.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -mhwmult=f5series" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Verify the MSP430 cost model is working as expected for the default ISA + (msp430x) and f5series hwmult, when compiling at -Os. */ + +volatile unsigned long a; +volatile unsigned int b; +volatile unsigned long c; +unsigned long res1; +unsigned long res2; +unsigned long res3; + +/* +** foo: +** ... +** MOV.B #16, R14 +** CALL.* #__mspabi_slll +** ... +** MOV.B #7, R14 +** CALL.* #__mspabi_slll +** ... +** MOV.B #100, R14 +** MOV.B #0, R15 +** ... +** CALL.* #__mulsi2_f5 +** ... +*/ +void foo (void) +{ + /* Use the shift library function for this. */ + res1 = (a << 16) | b; + /* Likewise. */ + res2 *= 128; + /* Use the hardware multiply library function for this. */ + res3 *= 100; +} -- cgit v1.1 From a514934a0565255276adaa4fbd4aa35579ec33c6 Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 13 Nov 2020 15:36:01 +0000 Subject: MSP430: Skip index-1.c test To access the "n - 100000"th element of "a" in this test, GCC will generate the following code for msp430-elf with -mcpu=msp430x: RLAM.W #1, R12 MOV.W a-3392(R12), R12 Since there aren't actually 100,000 elements in a, this means that "a-3392" offset calculated by the linker can overflow, as the address of "a" can validly be less than 3392. The relocations used for -mcpu=msp430 and -mlarge are not as strict and the calculated value is allowed to wrap around the address space, avoiding relocation overflows. gcc/testsuite/ChangeLog: * gcc.c-torture/execute/index-1.c: Skip for the default MSP430 430X ISA. --- gcc/testsuite/gcc.c-torture/execute/index-1.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.c-torture/execute/index-1.c b/gcc/testsuite/gcc.c-torture/execute/index-1.c index b00090d..d96be4c 100644 --- a/gcc/testsuite/gcc.c-torture/execute/index-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/index-1.c @@ -1,3 +1,5 @@ +/* { dg-skip-if "strict reloc overflow checking" { msp430-*-* } { "*" } { "-mcpu=msp430" "-mlarge"} } */ + int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -- cgit v1.1 From 2935ff7eb7ac2bb089e61078162d3d68b5745281 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 13 Nov 2020 17:38:41 +0100 Subject: testsuite: move expected error location gcc/testsuite/ChangeLog: PR testsuite/97788 * g++.dg/ubsan/pr61272.C: Move expected error location. --- gcc/testsuite/g++.dg/ubsan/pr61272.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/ubsan/pr61272.C b/gcc/testsuite/g++.dg/ubsan/pr61272.C index 11dd1ec..cb4751e 100644 --- a/gcc/testsuite/g++.dg/ubsan/pr61272.C +++ b/gcc/testsuite/g++.dg/ubsan/pr61272.C @@ -12,10 +12,10 @@ namespace std }; namespace __gnu_cxx { - template < typename _Alloc > struct __alloc_traits:std::allocator_traits < _Alloc > // { dg-error "within this context" } + template < typename _Alloc > struct __alloc_traits:std::allocator_traits < _Alloc > { typedef std::allocator_traits < _Alloc > _Base_type; - using _Base_type::construct; + using _Base_type::construct; // { dg-error "within this context" } }; template < typename _Tp, typename _Alloc > struct _Vector_base { typedef typename __gnu_cxx::__alloc_traits < _Alloc >::template rebind < _Tp >::other _Tp_alloc_type; }; // { dg-error "no class template" } template < typename _Tp, typename _Alloc = std::allocator < _Tp > >class vector : protected _Vector_base < _Tp, _Alloc > { }; -- cgit v1.1 From 0d1189b4e618517b62f938a94c722123cc0ef5f5 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Fri, 13 Nov 2020 11:40:41 -0500 Subject: Add 3 new EVRP testcases. test new evrp functionality. gcc/testsuite/ * gcc.dg/tree-ssa/evrp20.c * gcc.dg/tree-ssa/evrp21.c * gcc.dg/tree-ssa/evrp22.c --- gcc/testsuite/gcc.dg/tree-ssa/evrp20.c | 19 +++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/evrp21.c | 28 ++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/evrp22.c | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp20.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp21.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp22.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp20.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp20.c new file mode 100644 index 0000000..7d4d55f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp20.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +void call (void); + +void foo (int base) +{ + unsigned i; + + // Ranger should be able to remove the (i > 123) comparison. + for (i = base; i < 10; i++) + if (i > 123) + { + call (); + return; + } +} + +/* { dg-final { scan-tree-dump-not "call" "evrp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp21.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp21.c new file mode 100644 index 0000000..dae788c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp21.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +extern void vrp_keep (void); +extern void vrp_kill (void); + +void +f2 (int s, int b) +{ + if (s > 4) + s = 4; + if (s < -16) + s = -16; + /* s in [-16, 4]. */ + b = (b & 1) + 1; + /* b in range [1, 2]. */ + b = s << b; + /* b in range [-64, 16]. */ + if (b == -2) + vrp_keep (); + if (b <= -65) + vrp_kill (); + if (b >= 17) + vrp_kill (); +} + +/* { dg-final { scan-tree-dump-times "vrp_keep \\(" 1 "evrp"} } */ +/* { dg-final { scan-tree-dump-times "vrp_kill \\(" 0 "evrp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp22.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp22.c new file mode 100644 index 0000000..3dd47e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp22.c @@ -0,0 +1,43 @@ +/* See backwards thru casts if the range fits the LHS type. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +extern void kill(int i); +extern void keep(int i); + +void +foo (int i) +{ + if (i >= 10) + { + if (i <= 100) + { + /* i has a range of [10, 100] */ + char c = (char) i; + if (c < 30) + { + /* If we wind back thru the cast with the range of c being [10,29] + * from the branch, and recognize that the range of i fits within + * a cast to c, then there is no missing information in a cast + * back to int. We can use the range calculated for 'c' with 'i' + * as well and Ranger should be able to kill the call. */ + if (i > 29) + kill (i); + } + } + /* i has a range of [10, MAX] */ + char d = (char) i; + if (d < 30) + { + /* Here, a cast to a char and back is NOT equivalent, so we cannot use + * the value of d to remove the call. */ + if (i > 29) + keep (i); + } + + } +} + +/* { dg-final { scan-tree-dump-times "kill \\(" 0 "evrp"} } */ +/* { dg-final { scan-tree-dump-times "keep \\(" 1 "evrp"} } */ + -- cgit v1.1 From 6f1ae1ecd351348eb33b515c5e23778651bee028 Mon Sep 17 00:00:00 2001 From: "Piotr H. Dabrowski" Date: Fri, 13 Nov 2020 12:27:16 -0500 Subject: Do not warn about unused macros while processing #pragma GCC optimize libcpp PR c++/91318 * include/cpplib.h: Added cpp_define_unused(), cpp_define_formatted_unused() * directives.c: Likewise. gcc/c-family PR c++/91318 * c-cppbuiltin.c: c_cpp_builtins_optimize_pragma(): use cpp_define_unused() --- gcc/c-family/c-cppbuiltin.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index e5ebb79..15f71e6 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -581,41 +581,41 @@ c_cpp_builtins_optimize_pragma (cpp_reader *pfile, tree prev_tree, /* Other target-independent built-ins determined by command-line options. */ if (!prev->x_optimize_size && cur->x_optimize_size) - cpp_define (pfile, "__OPTIMIZE_SIZE__"); + cpp_define_unused (pfile, "__OPTIMIZE_SIZE__"); else if (prev->x_optimize_size && !cur->x_optimize_size) cpp_undef (pfile, "__OPTIMIZE_SIZE__"); if (!prev->x_optimize && cur->x_optimize) - cpp_define (pfile, "__OPTIMIZE__"); + cpp_define_unused (pfile, "__OPTIMIZE__"); else if (prev->x_optimize && !cur->x_optimize) cpp_undef (pfile, "__OPTIMIZE__"); prev_fast_math = fast_math_flags_struct_set_p (prev); cur_fast_math = fast_math_flags_struct_set_p (cur); if (!prev_fast_math && cur_fast_math) - cpp_define (pfile, "__FAST_MATH__"); + cpp_define_unused (pfile, "__FAST_MATH__"); else if (prev_fast_math && !cur_fast_math) cpp_undef (pfile, "__FAST_MATH__"); if (!prev->x_flag_signaling_nans && cur->x_flag_signaling_nans) - cpp_define (pfile, "__SUPPORT_SNAN__"); + cpp_define_unused (pfile, "__SUPPORT_SNAN__"); else if (prev->x_flag_signaling_nans && !cur->x_flag_signaling_nans) cpp_undef (pfile, "__SUPPORT_SNAN__"); if (!prev->x_flag_errno_math && cur->x_flag_errno_math) cpp_undef (pfile, "__NO_MATH_ERRNO__"); else if (prev->x_flag_errno_math && !cur->x_flag_errno_math) - cpp_define (pfile, "__NO_MATH_ERRNO__"); + cpp_define_unused (pfile, "__NO_MATH_ERRNO__"); if (!prev->x_flag_finite_math_only && cur->x_flag_finite_math_only) { cpp_undef (pfile, "__FINITE_MATH_ONLY__"); - cpp_define (pfile, "__FINITE_MATH_ONLY__=1"); + cpp_define_unused (pfile, "__FINITE_MATH_ONLY__=1"); } else if (prev->x_flag_finite_math_only && !cur->x_flag_finite_math_only) { cpp_undef (pfile, "__FINITE_MATH_ONLY__"); - cpp_define (pfile, "__FINITE_MATH_ONLY__=0"); + cpp_define_unused (pfile, "__FINITE_MATH_ONLY__=0"); } } -- cgit v1.1 From 2e97d6443f0a862ce9b798084499635914e3b8c6 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 13 Nov 2020 18:30:11 +0100 Subject: ipa-cp: One more safe_add (PR 97816) The new behavior of safe_add triggered an ICE because of one use where it had not been used instead of a simple addition. I'll fix it with the following obvious patch so that periodic benchmarkers can continue working because a proper fix (see below) will need a review. The testcase showed me, however, that we can propagate time and cost from one lattice to another more than once even when that was not the intent. I'll address that as a follow-up after I verify it does not affect the IPA-CP heuristics too much or change the corresponding params accordingly. Bootstrapped and tested on x86_64-linux. gcc/ChangeLog: 2020-11-13 Martin Jambor PR ipa/97816 * ipa-cp.c (value_topo_info::propagate_effects): Use safe_add instead of a simple addition. --- gcc/ipa-cp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index f29f216..c3ee71e 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -3873,7 +3873,8 @@ value_topo_info::propagate_effects () for (val = base; val; val = val->scc_next) { time = time + val->local_time_benefit + val->prop_time_benefit; - size = safe_add (size, val->local_size_cost + val->prop_size_cost); + size = safe_add (size, safe_add (val->local_size_cost, + val->prop_size_cost)); } for (val = base; val; val = val->scc_next) -- cgit v1.1 From 67100cb50ea22e1fc855360b887959f874fafe2c Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 13 Nov 2020 18:57:06 +0100 Subject: openmp: Support allocate for C/C++ array section reductions This adds allocate clause support for array section reductions. Furthermore, it fixes one bug that would cause inscan reductions with allocate to be rejected by C, and for now just ignores allocate for inscan/task reductions, that will need slightly more work. 2020-11-13 Jakub Jelinek gcc/ * omp-low.c (scan_sharing_clauses): For now remove for reduction clauses with inscan or task modifiers decl from allocate_map. (lower_private_allocate): Handle TYPE_P (new_var). (lower_rec_input_clauses): Handle allocate clause for C/C++ array reductions. gcc/c/ * c-typeck.c (c_finish_omp_clauses): Don't clear OMP_CLAUSE_REDUCTION_INSCAN unless reduction_seen == -2. libgomp/ * testsuite/libgomp.c-c++-common/allocate-1.c (foo): Add tests for array reductions. (main): Adjust foo callers. --- gcc/c/c-typeck.c | 3 ++- gcc/omp-low.c | 72 +++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 20 deletions(-) (limited to 'gcc') diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index df1dad4..26a5f71 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -15199,7 +15199,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) OMP_CLAUSE_LINEAR_STEP (c)); remove = true; } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && reduction_seen == -2) OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; if (remove) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index ed805e2..eec3481 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1197,6 +1197,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) if (is_oacc_parallel_or_serial (ctx) || is_oacc_kernels (ctx)) ctx->local_reduction_clauses = tree_cons (NULL, c, ctx->local_reduction_clauses); + if ((OMP_CLAUSE_REDUCTION_INSCAN (c) + || OMP_CLAUSE_REDUCTION_TASK (c)) && ctx->allocate_map) + { + tree decl = OMP_CLAUSE_DECL (c); + /* For now. */ + if (ctx->allocate_map->get (decl)) + ctx->allocate_map->remove (decl); + } /* FALLTHRU */ case OMP_CLAUSE_IN_REDUCTION: @@ -4392,13 +4400,17 @@ lower_private_allocate (tree var, tree new_var, tree &allocator, if (allocator) return false; gcc_assert (allocate_ptr == NULL_TREE); - if (ctx->allocate_map && DECL_P (new_var)) + if (ctx->allocate_map + && (DECL_P (new_var) || (TYPE_P (new_var) && size))) if (tree *allocatorp = ctx->allocate_map->get (var)) allocator = *allocatorp; if (allocator == NULL_TREE) return false; if (!is_ref && omp_is_reference (var)) - return false; + { + allocator = NULL_TREE; + return false; + } if (TREE_CODE (allocator) != INTEGER_CST) allocator = build_outer_var_ref (allocator, ctx); @@ -4410,19 +4422,24 @@ lower_private_allocate (tree var, tree new_var, tree &allocator, allocator = var; } - tree ptr_type, align, sz; - if (is_ref) + tree ptr_type, align, sz = size; + if (TYPE_P (new_var)) + { + ptr_type = build_pointer_type (new_var); + align = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (new_var)); + } + else if (is_ref) { ptr_type = build_pointer_type (TREE_TYPE (TREE_TYPE (new_var))); align = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type))); - sz = size; } else { ptr_type = build_pointer_type (TREE_TYPE (new_var)); align = build_int_cst (size_type_node, DECL_ALIGN_UNIT (new_var)); - sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var)); + if (sz == NULL_TREE) + sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var)); } if (TREE_CODE (sz) != INTEGER_CST) { @@ -4855,7 +4872,23 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, tree type = TREE_TYPE (d); gcc_assert (TREE_CODE (type) == ARRAY_TYPE); tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + tree sz = v; const char *name = get_name (orig_var); + if (pass != 3 && !TREE_CONSTANT (v)) + { + tree t = maybe_lookup_decl (v, ctx); + if (t) + v = t; + else + v = maybe_lookup_decl_in_outer_ctx (v, ctx); + gimplify_expr (&v, ilist, NULL, is_gimple_val, fb_rvalue); + t = fold_build2_loc (clause_loc, PLUS_EXPR, + TREE_TYPE (v), v, + build_int_cst (TREE_TYPE (v), 1)); + sz = fold_build2_loc (clause_loc, MULT_EXPR, + TREE_TYPE (v), t, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + } if (pass == 3) { tree xv = create_tmp_var (ptr_type_node); @@ -4913,6 +4946,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, gimplify_assign (cond, x, ilist); x = xv; } + else if (lower_private_allocate (var, type, allocator, + allocate_ptr, ilist, ctx, + true, + TREE_CONSTANT (v) + ? TYPE_SIZE_UNIT (type) + : sz)) + x = allocate_ptr; else if (TREE_CONSTANT (v)) { x = create_tmp_var_raw (type, name); @@ -4924,20 +4964,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, { tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN); - tree t = maybe_lookup_decl (v, ctx); - if (t) - v = t; - else - v = maybe_lookup_decl_in_outer_ctx (v, ctx); - gimplify_expr (&v, ilist, NULL, is_gimple_val, fb_rvalue); - t = fold_build2_loc (clause_loc, PLUS_EXPR, - TREE_TYPE (v), v, - build_int_cst (TREE_TYPE (v), 1)); - t = fold_build2_loc (clause_loc, MULT_EXPR, - TREE_TYPE (v), t, - TYPE_SIZE_UNIT (TREE_TYPE (type))); tree al = size_int (TYPE_ALIGN (TREE_TYPE (type))); - x = build_call_expr_loc (clause_loc, atmp, 2, t, al); + x = build_call_expr_loc (clause_loc, atmp, 2, sz, al); } tree ptype = build_pointer_type (TREE_TYPE (type)); @@ -5199,6 +5227,12 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, gimple_seq_add_stmt (dlist, g); gimple_seq_add_stmt (dlist, gimple_build_label (end2)); } + if (allocator) + { + tree f = builtin_decl_explicit (BUILT_IN_GOMP_FREE); + g = gimple_build_call (f, 2, allocate_ptr, allocator); + gimple_seq_add_stmt (dlist, g); + } continue; } else if (pass == 2) -- cgit v1.1 From e3b3b59683c1e7d31a9d313dd97394abebf644be Mon Sep 17 00:00:00 2001 From: "Vladimir N. Makarov" Date: Fri, 13 Nov 2020 12:45:59 -0500 Subject: [PATCH] Implementation of asm goto outputs gcc/ * cfgexpand.c (expand_asm_stmt): Output asm goto with outputs too. Place insns after asm goto on edges. * doc/extend.texi: Reflect the changes in asm goto documentation. * gimple.c (gimple_build_asm_1): Remove an assert checking output absence for asm goto. * gimple.h (gimple_asm_label_op, gimple_asm_set_label_op): Take possible asm goto outputs into account. * ira.c (ira): Remove critical edges for potential asm goto output reloads. (ira_nullify_asm_goto): New function. * ira.h (ira_nullify_asm_goto): New prototype. * lra-assigns.c (lra_split_hard_reg_for): Use ira_nullify_asm_goto. Check that splitting is done inside a basic block. * lra-constraints.c (curr_insn_transform): Permit output reloads for any jump insn. * lra-spills.c (lra_final_code_change): Remove USEs added in ira for asm gotos. * lra.c (lra_process_new_insns): Place output reload insns after jumps in the beginning of destination BBs. * reload.c (find_reloads): Report error for asm gotos with outputs. Modify them to keep CFG consistency to avoid crashes. * tree-into-ssa.c (rewrite_stmt): Don't put debug stmt after asm goto. gcc/c/ * c-parser.c (c_parser_asm_statement): Parse outputs for asm goto too. * c-typeck.c (build_asm_expr): Remove an assert checking output absence for asm goto. gcc/cp * parser.c (cp_parser_asm_definition): Parse outputs for asm goto too. gcc/testsuite/ * c-c++-common/asmgoto-2.c: Permit output in asm goto. * gcc.c-torture/compile/asmgoto-2.c: New. * gcc.c-torture/compile/asmgoto-3.c: New. * gcc.c-torture/compile/asmgoto-4.c: New. * gcc.c-torture/compile/asmgoto-5.c: New. --- gcc/c/c-parser.c | 5 +- gcc/c/c-typeck.c | 4 -- gcc/cfgexpand.c | 39 ++++++++--- gcc/cp/parser.c | 3 +- gcc/doc/extend.texi | 49 ++++++++++++-- gcc/gimple.c | 4 -- gcc/gimple.h | 4 +- gcc/ira.c | 57 ++++++++++++++++ gcc/ira.h | 1 + gcc/lra-assigns.c | 17 ++--- gcc/lra-constraints.c | 8 +-- gcc/lra-spills.c | 8 +++ gcc/lra.c | 69 +++++++++++++++---- gcc/reload.c | 16 +++++ gcc/testsuite/c-c++-common/asmgoto-2.c | 2 +- gcc/testsuite/gcc.c-torture/compile/asmgoto-2.c | 65 ++++++++++++++++++ gcc/testsuite/gcc.c-torture/compile/asmgoto-3.c | 89 +++++++++++++++++++++++++ gcc/testsuite/gcc.c-torture/compile/asmgoto-4.c | 14 ++++ gcc/testsuite/gcc.c-torture/compile/asmgoto-5.c | 56 ++++++++++++++++ gcc/tree-into-ssa.c | 4 ++ 20 files changed, 455 insertions(+), 59 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/asmgoto-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/asmgoto-3.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/asmgoto-4.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/asmgoto-5.c (limited to 'gcc') diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index f4c4cf7..7540a15 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -7144,10 +7144,7 @@ c_parser_asm_statement (c_parser *parser) switch (section) { case 0: - /* For asm goto, we don't allow output operands, but reserve - the slot for a future extension that does allow them. */ - if (!is_goto) - outputs = c_parser_asm_operands (parser); + outputs = c_parser_asm_operands (parser); break; case 1: inputs = c_parser_asm_operands (parser); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 26a5f71..413109c 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10666,10 +10666,6 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, TREE_VALUE (tail) = input; } - /* ASMs with labels cannot have outputs. This should have been - enforced by the parser. */ - gcc_assert (outputs == NULL || labels == NULL); - args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels); /* asm statements without outputs, including simple ones, are treated diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 1b7bdbc..1df6f4b 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3371,20 +3371,21 @@ expand_asm_stmt (gasm *stmt) ARGVEC CONSTRAINTS OPNAMES)) If there is more than one, put them inside a PARALLEL. */ - if (nlabels > 0 && nclobbers == 0) - { - gcc_assert (noutputs == 0); - emit_jump_insn (body); - } - else if (noutputs == 0 && nclobbers == 0) + if (noutputs == 0 && nclobbers == 0) { /* No output operands: put in a raw ASM_OPERANDS rtx. */ - emit_insn (body); + if (nlabels > 0) + emit_jump_insn (body); + else + emit_insn (body); } else if (noutputs == 1 && nclobbers == 0) { ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0]; - emit_insn (gen_rtx_SET (output_rvec[0], body)); + if (nlabels > 0) + emit_jump_insn (gen_rtx_SET (output_rvec[0], body)); + else + emit_insn (gen_rtx_SET (output_rvec[0], body)); } else { @@ -3461,7 +3462,27 @@ expand_asm_stmt (gasm *stmt) if (after_md_seq) emit_insn (after_md_seq); if (after_rtl_seq) - emit_insn (after_rtl_seq); + { + if (nlabels == 0) + emit_insn (after_rtl_seq); + else + { + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs) + { + start_sequence (); + for (rtx_insn *curr = after_rtl_seq; + curr != NULL_RTX; + curr = NEXT_INSN (curr)) + emit_insn (copy_insn (PATTERN (curr))); + rtx_insn *copy = get_insns (); + end_sequence (); + insert_insn_on_edge (copy, e); + } + } + } free_temp_slots (); crtl->has_asm_statement = 1; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6b0447e..68f1cfa 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -20534,8 +20534,7 @@ cp_parser_asm_definition (cp_parser* parser) && cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE) && cp_lexer_next_token_is_not (parser->lexer, - CPP_CLOSE_PAREN) - && !goto_p) + CPP_CLOSE_PAREN)) { outputs = cp_parser_asm_operand_list (parser); if (outputs == error_mark_node) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4ddbf80..af25f66 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -9566,7 +9566,7 @@ asm @var{asm-qualifiers} ( @var{AssemblerTemplate} @r{[} : @var{Clobbers} @r{]} @r{]}) asm @var{asm-qualifiers} ( @var{AssemblerTemplate} - : + : @var{OutputOperands} : @var{InputOperands} : @var{Clobbers} : @var{GotoLabels}) @@ -9673,7 +9673,7 @@ there is no need for the output variables. Also, the optimizers may move code out of loops if they believe that the code will always return the same result (i.e.@: none of its input values change between calls). Using the @code{volatile} qualifier disables these optimizations. @code{asm} statements -that have no output operands, including @code{asm goto} statements, +that have no output operands and @code{asm goto} statements, are implicitly volatile. This i386 code demonstrates a case that does not use (or require) the @@ -10532,9 +10532,6 @@ case, consider using the @code{__builtin_unreachable} intrinsic after the using the @code{hot} and @code{cold} label attributes (@pxref{Label Attributes}). -An @code{asm goto} statement cannot have outputs. -This is due to an internal restriction of -the compiler: control transfer instructions cannot have outputs. If the assembler code does modify anything, use the @code{"memory"} clobber to force the optimizers to flush all register values to memory and reload them if @@ -10543,6 +10540,13 @@ necessary after the @code{asm} statement. Also note that an @code{asm goto} statement is always implicitly considered volatile. +Be careful when you set output operands inside @code{asm goto} only on +some possible control flow paths. If you don't set up the output on +given path and never use it on this path, it is okay. Otherwise, you +should use @samp{+} constraint modifier meaning that the operand is +input and output one. With this modifier you will have the correct +values on all possible paths from the @code{asm goto}. + To reference a label in the assembler template, prefix it with @samp{%l} (lowercase @samp{L}) followed by its (zero-based) position in @var{GotoLabels} plus the number of input @@ -10588,6 +10592,41 @@ error: @} @end example +The following example shows an @code{asm goto} that uses an output. + +@example +int foo(int count) +@{ + asm goto ("dec %0; jb %l[stop]" + : "+r" (count) + : + : + : stop); + return count; +stop: + return 0; +@} +@end example + +The following artificial example shows an @code{asm goto} that sets +up an output only on one path inside the @code{asm goto}. Usage of +constraint modifier @code{=} instead of @code{+} would be wrong as +@code{factor} is used on all paths from the @code{asm goto}. + +@example +int foo(int inp) +@{ + int factor = 0; + asm goto ("cmp %1, 10; jb %l[lab]; mov 2, %0" + : "+r" (factor) + : "r" (inp) + : + : lab); +lab: + return inp * factor; /* return 2 * inp or 0 if inp < 10 */ +@} +@end example + @anchor{x86Operandmodifiers} @subsubsection x86 Operand Modifiers diff --git a/gcc/gimple.c b/gcc/gimple.c index 1afed88..60afc54 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -611,10 +611,6 @@ gimple_build_asm_1 (const char *string, unsigned ninputs, unsigned noutputs, gasm *p; int size = strlen (string); - /* ASMs with labels cannot have outputs. This should have been - enforced by the front end. */ - gcc_assert (nlabels == 0 || noutputs == 0); - p = as_a ( gimple_build_with_ops (GIMPLE_ASM, ERROR_MARK, ninputs + noutputs + nclobbers + nlabels)); diff --git a/gcc/gimple.h b/gcc/gimple.h index 62b5a8a..d359f78 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -4025,7 +4025,7 @@ static inline tree gimple_asm_label_op (const gasm *asm_stmt, unsigned index) { gcc_gimple_checking_assert (index < asm_stmt->nl); - return asm_stmt->op[index + asm_stmt->ni + asm_stmt->nc]; + return asm_stmt->op[index + asm_stmt->no + asm_stmt->ni + asm_stmt->nc]; } /* Set LABEL_OP to be label operand INDEX in GIMPLE_ASM ASM_STMT. */ @@ -4035,7 +4035,7 @@ gimple_asm_set_label_op (gasm *asm_stmt, unsigned index, tree label_op) { gcc_gimple_checking_assert (index < asm_stmt->nl && TREE_CODE (label_op) == TREE_LIST); - asm_stmt->op[index + asm_stmt->ni + asm_stmt->nc] = label_op; + asm_stmt->op[index + asm_stmt->no + asm_stmt->ni + asm_stmt->nc] = label_op; } /* Return the string representing the assembly instruction in diff --git a/gcc/ira.c b/gcc/ira.c index 5443031..3c824e9 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -5401,6 +5401,48 @@ ira (FILE *f) int ira_max_point_before_emit; bool saved_flag_caller_saves = flag_caller_saves; enum ira_region saved_flag_ira_region = flag_ira_region; + basic_block bb; + edge_iterator ei; + edge e; + bool output_jump_reload_p = false; + + if (ira_use_lra_p) + { + /* First put potential jump output reloads on the output edges + as USE which will be removed at the end of LRA. The major + goal is actually to create BBs for critical edges for LRA and + populate them later by live info. In LRA it will be + difficult to do this. */ + FOR_EACH_BB_FN (bb, cfun) + { + rtx_insn *end = BB_END (bb); + if (!JUMP_P (end)) + continue; + extract_insn (end); + for (int i = 0; i < recog_data.n_operands; i++) + if (recog_data.operand_type[i] != OP_IN) + { + output_jump_reload_p = true; + FOR_EACH_EDGE (e, ei, bb->succs) + if (EDGE_CRITICAL_P (e) + && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)) + { + ira_assert (!(e->flags & EDGE_ABNORMAL)); + start_sequence (); + /* We need to put some no-op insn here. We can + not put a note as commit_edges insertion will + fail. */ + emit_insn (gen_rtx_USE (VOIDmode, const1_rtx)); + rtx_insn *insns = get_insns (); + end_sequence (); + insert_insn_on_edge (insns, e); + } + break; + } + } + if (output_jump_reload_p) + commit_edge_insertions (); + } if (flag_ira_verbose < 10) { @@ -5709,6 +5751,21 @@ ira (FILE *f) } } +/* Modify asm goto to avoid further trouble with this insn. We can + not replace the insn by USE as in other asm insns as we still + need to keep CFG consistency. */ +void +ira_nullify_asm_goto (rtx_insn *insn) +{ + ira_assert (JUMP_P (insn) && INSN_CODE (insn) < 0); + rtx tmp = extract_asm_operands (PATTERN (insn)); + PATTERN (insn) = gen_rtx_ASM_OPERANDS (VOIDmode, ggc_strdup (""), "", 0, + rtvec_alloc (0), + rtvec_alloc (0), + ASM_OPERANDS_LABEL_VEC (tmp), + ASM_OPERANDS_SOURCE_LOCATION(tmp)); +} + static void do_reload (void) { diff --git a/gcc/ira.h b/gcc/ira.h index c30f36a..0da06ee 100644 --- a/gcc/ira.h +++ b/gcc/ira.h @@ -213,6 +213,7 @@ extern void ira_register_new_scratch_op (rtx_insn *insn, int nop, int icode); extern bool ira_remove_insn_scratches (rtx_insn *insn, bool all_p, FILE *dump_file, rtx (*get_reg) (rtx original)); extern void ira_restore_scratches (FILE *dump_file); +extern void ira_nullify_asm_goto (rtx_insn *insn); /* ira-costs.c */ extern void ira_costs_c_finalize (void); diff --git a/gcc/lra-assigns.c b/gcc/lra-assigns.c index 40e323c..b040f7f 100644 --- a/gcc/lra-assigns.c +++ b/gcc/lra-assigns.c @@ -1715,8 +1715,8 @@ find_reload_regno_insns (int regno, rtx_insn * &start, rtx_insn * &finish) start_insn = lra_insn_recog_data[uid]->insn; n++; } - /* For reload pseudo we should have at most 3 insns referring for it: - input/output reload insns and the original insn. */ + /* For reload pseudo we should have at most 3 insns referring for + it: input/output reload insns and the original insn. */ if (n > 3) return false; if (n > 1) @@ -1792,7 +1792,8 @@ lra_split_hard_reg_for (void) { if (! find_reload_regno_insns (i, first, last)) continue; - if (spill_hard_reg_in_range (i, rclass, first, last)) + if (BLOCK_FOR_INSN (first) == BLOCK_FOR_INSN (last) + && spill_hard_reg_in_range (i, rclass, first, last)) { bitmap_clear (&failed_reload_pseudos); return true; @@ -1817,16 +1818,10 @@ lra_split_hard_reg_for (void) lra_asm_error_p = asm_p = true; error_for_asm (insn, "% operand has impossible constraints"); - /* Avoid further trouble with this insn. - For asm goto, instead of fixing up all the edges - just clear the template and clear input operands - (asm goto doesn't have any output operands). */ + /* Avoid further trouble with this insn. */ if (JUMP_P (insn)) { - rtx asm_op = extract_asm_operands (PATTERN (insn)); - ASM_OPERANDS_TEMPLATE (asm_op) = ggc_strdup (""); - ASM_OPERANDS_INPUT_VEC (asm_op) = rtvec_alloc (0); - ASM_OPERANDS_INPUT_CONSTRAINT_VEC (asm_op) = rtvec_alloc (0); + ira_nullify_asm_goto (insn); lra_update_insn_regno_info (insn); } else diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index fbc47ba..f034c77 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -3954,10 +3954,10 @@ curr_insn_transform (bool check_only_p) no_input_reloads_p = no_output_reloads_p = false; goal_alt_number = -1; change_p = sec_mem_p = false; - /* JUMP_INSNs and CALL_INSNs are not allowed to have any output - reloads; neither are insns that SET cc0. Insns that use CC0 are - not allowed to have any input reloads. */ - if (JUMP_P (curr_insn) || CALL_P (curr_insn)) + /* CALL_INSNs are not allowed to have any output reloads; neither + are insns that SET cc0. Insns that use CC0 are not allowed to + have any input reloads. */ + if (CALL_P (curr_insn)) no_output_reloads_p = true; if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (curr_insn))) diff --git a/gcc/lra-spills.c b/gcc/lra-spills.c index 8082a5b..85c3664 100644 --- a/gcc/lra-spills.c +++ b/gcc/lra-spills.c @@ -788,6 +788,14 @@ lra_final_code_change (void) { rtx pat = PATTERN (insn); + if (GET_CODE (pat) == USE && XEXP (pat, 0) == const1_rtx) + { + /* Remove markers to eliminate critical edges for jump insn + output reloads (see code in ira.c::ira). */ + lra_invalidate_insn_data (insn); + delete_insn (insn); + continue; + } if (GET_CODE (pat) == CLOBBER && LRA_TEMP_CLOBBER_P (pat)) { /* Remove clobbers temporarily created in LRA. We don't diff --git a/gcc/lra.c b/gcc/lra.c index 664f1b5..673554d 100644 --- a/gcc/lra.c +++ b/gcc/lra.c @@ -1852,8 +1852,6 @@ void lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after, const char *title) { - rtx_insn *last; - if (before == NULL_RTX && after == NULL_RTX) return; if (lra_dump_file != NULL) @@ -1864,12 +1862,6 @@ lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after, fprintf (lra_dump_file," %s before:\n", title); dump_rtl_slim (lra_dump_file, before, NULL, -1, 0); } - if (after != NULL_RTX) - { - fprintf (lra_dump_file, " %s after:\n", title); - dump_rtl_slim (lra_dump_file, after, NULL, -1, 0); - } - fprintf (lra_dump_file, "\n"); } if (before != NULL_RTX) { @@ -1883,12 +1875,63 @@ lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after, { if (cfun->can_throw_non_call_exceptions) copy_reg_eh_region_note_forward (insn, after, NULL); - for (last = after; NEXT_INSN (last) != NULL_RTX; last = NEXT_INSN (last)) - ; - emit_insn_after (after, insn); - push_insns (last, insn); - setup_sp_offset (after, last); + if (! JUMP_P (insn)) + { + rtx_insn *last; + + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " %s after:\n", title); + dump_rtl_slim (lra_dump_file, after, NULL, -1, 0); + } + for (last = after; + NEXT_INSN (last) != NULL_RTX; + last = NEXT_INSN (last)) + ; + emit_insn_after (after, insn); + push_insns (last, insn); + setup_sp_offset (after, last); + } + else + { + /* Put output reload insns on successor BBs: */ + edge_iterator ei; + edge e; + + FOR_EACH_EDGE (e, ei, BLOCK_FOR_INSN (insn)->succs) + if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)) + { + /* We already made the edge no-critical in ira.c::ira */ + lra_assert (!EDGE_CRITICAL_P (e)); + rtx_insn *tmp = BB_HEAD (e->dest); + if (LABEL_P (tmp)) + tmp = NEXT_INSN (tmp); + if (NOTE_INSN_BASIC_BLOCK_P (tmp)) + tmp = NEXT_INSN (tmp); + start_sequence (); + for (rtx_insn *curr = after; + curr != NULL_RTX; + curr = NEXT_INSN (curr)) + emit_insn (copy_insn (PATTERN (curr))); + rtx_insn *copy = get_insns (), *last = get_last_insn (); + end_sequence (); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " %s after in bb%d:\n", title, + e->dest->index); + dump_rtl_slim (lra_dump_file, copy, NULL, -1, 0); + } + emit_insn_before (copy, tmp); + push_insns (last, PREV_INSN (copy)); + setup_sp_offset (copy, last); + /* We can ignore BB live info here as it and reg notes + will be updated before the next assignment + sub-pass. */ + } + } } + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n"); if (cfun->can_throw_non_call_exceptions) { rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); diff --git a/gcc/reload.c b/gcc/reload.c index 78b4049..445f9bd 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -2656,6 +2656,22 @@ find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known, hard_regs_live_known = live_known; static_reload_reg_p = reload_reg_p; + if (JUMP_P (insn) && INSN_CODE (insn) < 0) + { + extract_insn (insn); + for (i = 0; i < recog_data.n_operands; i++) + if (recog_data.operand_type[i] != OP_IN) + break; + if (i < recog_data.n_operands) + { + error_for_asm (insn, + "the target does not support asm goto " + "with outputs in %"); + ira_nullify_asm_goto (insn); + return 0; + } + } + /* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads; neither are insns that SET cc0. Insns that use CC0 are not allowed to have any input reloads. */ diff --git a/gcc/testsuite/c-c++-common/asmgoto-2.c b/gcc/testsuite/c-c++-common/asmgoto-2.c index 5bf4572..fb81cde 100644 --- a/gcc/testsuite/c-c++-common/asmgoto-2.c +++ b/gcc/testsuite/c-c++-common/asmgoto-2.c @@ -7,7 +7,7 @@ foo (void) __label__ lab; int i = 0; asm goto ("" : : : : lab); - asm goto ("" : "=r" (i) : : : lab); /* { dg-error "expected" } */ + asm goto ("" : "=r" (i) : : : lab); asm goto ("" : : : : ); /* { dg-error "expected" } */ asm goto ("" : : : "memory"); /* { dg-error "expected" } */ asm goto ("" : : : ); /* { dg-error "expected" } */ diff --git a/gcc/testsuite/gcc.c-torture/compile/asmgoto-2.c b/gcc/testsuite/gcc.c-torture/compile/asmgoto-2.c new file mode 100644 index 0000000..f1b30c0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/asmgoto-2.c @@ -0,0 +1,65 @@ +/* This test should be switched off for a new target with less than 4 allocatable registers */ +/* { dg-do compile } */ +int +foo (void) +{ + int x, y, z, v; + + asm goto ("": "=r" (x), "=r" (y), "=r" (z), "=r" (v) : : : lab, lab2, lab3, lab4); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; +} + +int +foo2 (void) +{ + int x = 0, y = 1, z = 2, v = 3; + + asm goto ("": "+r" (x), "+r" (y), "+r" (z), "+r" (v) : : : lab, lab2, lab3, lab4); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; +} + +int +foo3 (void) +{ + int x, y, z, v; + + asm goto ("": "=rm" (x), "=mr" (y), "=rm" (z), "=mr" (v) : : : lab, lab2, lab3, lab4); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; +} + +int +foo4 (void) +{ + int x, y, z, v; + + asm goto ("": "=r,m" (x), "=m,r" (y), "=r,m" (z), "=m,r" (v) : : : lab, lab2, lab3, lab4); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/asmgoto-3.c b/gcc/testsuite/gcc.c-torture/compile/asmgoto-3.c new file mode 100644 index 0000000..842b73e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/asmgoto-3.c @@ -0,0 +1,89 @@ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ + +int +foo (void) +{ + int x; + + asm goto ("": "=a" (x) : : : lab); + lab: + return x; +} + +int +foo2 (void) +{ + int x, y; + + asm goto ("": "=a" (x), "=d" (y) : : : lab, lab2); + lab: + return x; + lab2: + return y; +} + +int +foo3 (void) +{ + int x, y, z; + + asm goto ("": "=a" (x), "=d" (y), "=c" (z) : : : lab, lab2, lab3); + lab: + return x; + lab2: + return y; + lab3: + return z; +} + +int +foo4 (void) +{ + int x, y, z, v; + + asm goto ("": "=a" (x), "=d" (y), "=c" (z) , "=b" (v) : : : lab, lab2, lab3, lab4); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; +} + +int +foo5 (void) +{ + int x, y, z, v, w; + + asm goto ("": "=a" (x), "=d" (y), "=c" (z), "=b" (v), "=S" (w) : : : lab, lab2, lab3, lab4, lab5); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; + lab5: + return w; +} + +int +foo6 (void) +{ + int x = 0, y = 1, z = 2, v = 3, w = 4; + + asm goto ("": "+a" (x), "+d" (y), "+c" (z), "+b" (v), "+S" (w) : : : lab, lab2, lab3, lab4, lab5); + lab: + return x; + lab2: + return y; + lab3: + return z; + lab4: + return v; + lab5: + return w; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/asmgoto-4.c b/gcc/testsuite/gcc.c-torture/compile/asmgoto-4.c new file mode 100644 index 0000000..844157e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/asmgoto-4.c @@ -0,0 +1,14 @@ +/* Check that LRA really puts output reloads for p4 in two successors blocks */ +/* { dg-do compile { target { { i?86-*-* x86_64-*-* } && { ! ia32 } } } } */ +/* { dg-options "-O0 -fdump-rtl-reload" } */ + +int f (int *p1, int *p2, int *p3, int *p4) { + asm volatile goto ( + "" + : "=r" (*p2), "=a" (p4) + : "r" (*p2), "r" (p2) + : "r8", "r9" : lab, lab2); + lab: return p2 - p4; + lab2: return p3 - p4; +} +/* { dg-final { scan-rtl-dump-times "Inserting insn reload after in bb" 2 "reload" } } */ diff --git a/gcc/testsuite/gcc.c-torture/compile/asmgoto-5.c b/gcc/testsuite/gcc.c-torture/compile/asmgoto-5.c new file mode 100644 index 0000000..94c14dd --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/asmgoto-5.c @@ -0,0 +1,56 @@ +/* Test to generate output reload in asm goto on x86_64. */ +/* { dg-do compile } */ +/* { dg-skip-if "no O0" { { i?86-*-* x86_64-*-* } && { ! ia32 } } { "-O0" } { "" } } */ + +#if defined __x86_64__ +#define ASM(s) asm (s) +#else +#define ASM(s) +#endif + +int +foo (int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, + int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16) +{ + register int v0 ASM ("rax") = a3; + register int v1 ASM ("rbx") = a4; + register int v2 ASM ("rcx") = a5; + register int v3 ASM ("rdx") = a6; + register int v4 ASM ("rsi") = a7; + register int v5 ASM ("rdi") = a8; + register int v6 ASM ("r8") = a9; + register int v7 ASM ("r9") = a10; + register int v8 ASM ("r10") = a11; + register int v9 ASM ("r11") = a12; + register int v10 ASM ("r12") = a13; + register int v11 ASM ("r13") = a14; + register int v12 ASM ("r14") = a15; + register int v13 ASM ("r15") = a16; + int x; + + v0 += a0; + v1 += a1; + v2 += a2; + v0 |= a0; + v1 |= a1; + v2 |= a2; + v0 ^= a0; + v1 ^= a1; + v2 ^= a2; + v0 &= a0; + v1 &= a1; + v2 &= a2; + asm goto ("": "=r" (x) : : : lab); + a1 ^= a0; + a2 = a1; + a0 |= a2; + a0 |= x; + lab: + v0 += x + a0 + a1 + a2; + v1 -= a0 - a1 - a2; + v2 |= a0 | a1 | a2; + v3 |= a0 & a1 & a2; + v4 ^= a0 ^ a1 ^ a2; + return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + a0 + a1 + a2; +} + diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 1493b32..51c619d 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -1412,6 +1412,10 @@ rewrite_stmt (gimple_stmt_iterator *si) SET_DEF (def_p, name); register_new_def (DEF_FROM_PTR (def_p), var); + /* Do not insert debug stmts if the stmt ends the BB. */ + if (stmt_ends_bb_p (stmt)) + continue; + tracked_var = target_for_debug_bind (var); if (tracked_var) { -- cgit v1.1 From d50310408f54e38031f34931e591c63ff36fee09 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 10 Nov 2020 17:17:19 -0500 Subject: c++: Implement C++20 'using enum'. [PR91367] This feature allows the programmer to import enumerator names into the current scope so later mentions don't need to use the fully-qualified name. These usings are not subject to the usual restrictions on using-decls: in particular, they can move between class and non-class scopes, and between classes that are not related by inheritance. This last caused difficulty for our normal approach to using-decls within a class hierarchy, as we assume that the class where we looked up a used declaration is derived from the class where it was first declared. So to simplify things, in that case we make a clone of the CONST_DECL in the using class. Thanks to Nathan for the start of this work: in particular, the lookup_using_decl rewrite. The changes to dwarf2out revealed an existing issue with the D front-end: we were doing the wrong thing for importing a D CONST_DECL, because dwarf2out_imported_module_or_decl_1 was looking through it to its type, expecting it to be an enumerator, but in one case in thread.d, the constant had type int. Adding the ability to import a C++ enumerator also fixed that, but that led to a crash in force_decl_die, which didn't know what to do with a CONST_DECL. So now it does. Co-authored-by: Nathan Sidwell gcc/cp/ChangeLog: * cp-tree.h (USING_DECL_UNRELATED_P): New. (CONST_DECL_USING_P): New. * class.c (handle_using_decl): If USING_DECL_UNRELATED_P, clone the CONST_DECL. * name-lookup.c (supplement_binding_1): A clone hides its using-declaration. (lookup_using_decl): Rewrite to separate lookup and validation. (do_class_using_decl): Adjust. (finish_nonmember_using_decl): Adjust. * parser.c (make_location): Add cp_token overload. (finish_using_decl): Split out from... (cp_parser_using_declaration): ...here. Don't look through enums. (cp_parser_using_enum): New. (cp_parser_block_declaration): Call it. (cp_parser_member_declaration): Call it. * semantics.c (finish_id_expression_1): Handle enumerator used from class scope. gcc/ChangeLog: * dwarf2out.c (gen_enumeration_type_die): Call equate_decl_number_to_die for enumerators. (gen_member_die): Don't move enumerators to their enclosing class. (dwarf2out_imported_module_or_decl_1): Allow importing individual enumerators. (force_decl_die): Handle CONST_DECL. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/inh-ctor28.C: Adjust expected diagnostic. * g++.dg/cpp0x/inh-ctor33.C: Likewise. * g++.dg/cpp0x/using-enum-1.C: Add comment. * g++.dg/cpp0x/using-enum-2.C: Allowed in C++20. * g++.dg/cpp0x/using-enum-3.C: Likewise. * g++.dg/cpp1z/class-deduction69.C: Adjust diagnostic. * g++.dg/inherit/using5.C: Likewise. * g++.dg/cpp2a/using-enum-1.C: New test. * g++.dg/cpp2a/using-enum-2.C: New test. * g++.dg/cpp2a/using-enum-3.C: New test. * g++.dg/cpp2a/using-enum-4.C: New test. * g++.dg/cpp2a/using-enum-5.C: New test. * g++.dg/cpp2a/using-enum-6.C: New test. * g++.dg/debug/dwarf2/using-enum.C: New test. --- gcc/cp/class.c | 17 ++ gcc/cp/cp-tree.h | 11 ++ gcc/cp/name-lookup.c | 256 ++++++++++++++++--------- gcc/cp/parser.c | 145 +++++++++++--- gcc/cp/semantics.c | 14 +- gcc/dwarf2out.c | 16 +- gcc/testsuite/g++.dg/cpp0x/inh-ctor28.C | 2 +- gcc/testsuite/g++.dg/cpp0x/inh-ctor33.C | 2 +- gcc/testsuite/g++.dg/cpp0x/using-enum-1.C | 3 + gcc/testsuite/g++.dg/cpp0x/using-enum-2.C | 11 +- gcc/testsuite/g++.dg/cpp0x/using-enum-3.C | 15 +- gcc/testsuite/g++.dg/cpp1z/class-deduction69.C | 2 +- gcc/testsuite/g++.dg/cpp2a/using-enum-1.C | 62 ++++++ gcc/testsuite/g++.dg/cpp2a/using-enum-2.C | 48 +++++ gcc/testsuite/g++.dg/cpp2a/using-enum-3.C | 6 + gcc/testsuite/g++.dg/cpp2a/using-enum-4.C | 13 ++ gcc/testsuite/g++.dg/cpp2a/using-enum-5.C | 132 +++++++++++++ gcc/testsuite/g++.dg/cpp2a/using-enum-6.C | 5 + gcc/testsuite/g++.dg/debug/dwarf2/using-enum.C | 21 ++ gcc/testsuite/g++.dg/inherit/using5.C | 2 +- 20 files changed, 648 insertions(+), 135 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-6.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/using-enum.C (limited to 'gcc') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 7c34d94..ec47b06 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1331,6 +1331,23 @@ handle_using_decl (tree using_decl, tree t) add_method (t, *iter, true); alter_access (t, *iter, access); } + else if (USING_DECL_UNRELATED_P (using_decl)) + { + /* C++20 using enum can import non-inherited enumerators into class + scope. We implement that by making a copy of the CONST_DECL for which + CONST_DECL_USING_P is true. */ + gcc_assert (TREE_CODE (decl) == CONST_DECL); + + tree copy = copy_decl (decl); + DECL_CONTEXT (copy) = t; + DECL_ARTIFICIAL (copy) = true; + /* We emitted debug info for the USING_DECL above; make sure we don't + also emit anything for this clone. */ + DECL_IGNORED_P (copy) = true; + DECL_SOURCE_LOCATION (copy) = DECL_SOURCE_LOCATION (using_decl); + finish_member_declaration (copy); + DECL_ABSTRACT_ORIGIN (copy) = decl; + } else alter_access (t, decl, access); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 63724c0..9ae6ff5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -529,6 +529,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL) DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL) LABEL_DECL_CDTOR (in LABEL_DECL) + USING_DECL_UNRELATED_P (in USING_DECL) 3: DECL_IN_AGGR_P. 4: DECL_C_BIT_FIELD (in a FIELD_DECL) DECL_ANON_UNION_VAR_P (in a VAR_DECL) @@ -3409,6 +3410,16 @@ struct GTY(()) lang_decl { /* Non zero if the using decl refers to a dependent type. */ #define USING_DECL_TYPENAME_P(NODE) DECL_LANG_FLAG_1 (USING_DECL_CHECK (NODE)) +/* True if member using decl NODE refers to a non-inherited NODE. */ +#define USING_DECL_UNRELATED_P(NODE) DECL_LANG_FLAG_2 (USING_DECL_CHECK (NODE)) + +/* True iff the CONST_DECL is a class-scope clone from C++20 using enum, + created by handle_using_decl. */ +#define CONST_DECL_USING_P(NODE) \ + (TREE_CODE (NODE) == CONST_DECL \ + && TREE_CODE (TREE_TYPE (NODE)) == ENUMERAL_TYPE \ + && DECL_CONTEXT (NODE) != TREE_TYPE (NODE)) + /* In a FUNCTION_DECL, this is nonzero if this function was defined in the class definition. We have saved away the text of the function, but have not yet processed it. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 410ec59..bf05e7b 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2125,6 +2125,10 @@ supplement_binding_1 (cxx_binding *binding, tree decl) region to refer only to the namespace to which it already refers. */ ok = false; + else if (TREE_CODE (bval) == USING_DECL + && CONST_DECL_USING_P (decl)) + /* Let the clone hide the using-decl that introduced it. */ + binding->value = decl; else { if (!error_operand_p (bval)) @@ -4540,43 +4544,66 @@ push_class_level_binding (tree name, tree x) /* Process and lookup a using decl SCOPE::lookup.name, filling in lookup.values & lookup.type. Return true if ok. */ -static bool +static tree lookup_using_decl (tree scope, name_lookup &lookup) { tree current = current_scope (); bool dependent_p = false; + tree binfo = NULL_TREE; + base_kind b_kind = bk_not_base; + + /* Because C++20 breaks the invariant that only member using-decls + refer to members and only non-member using-decls refer to + non-members, we first do the lookups, and then do validation that + what we found is ok. */ + + if (TREE_CODE (scope) == ENUMERAL_TYPE + && cxx_dialect < cxx20 + && UNSCOPED_ENUM_P (scope) + && !TYPE_FUNCTION_SCOPE_P (scope)) + { + /* PR c++/60265 argued that since C++11 added explicit enum scope, we + should allow it as meaning the enclosing scope. I don't see any + justification for this in C++11, but let's keep allowing it. */ + tree ctx = CP_TYPE_CONTEXT (scope); + if (CLASS_TYPE_P (ctx) == CLASS_TYPE_P (current)) + scope = ctx; + } if (TREE_CODE (scope) == NAMESPACE_DECL) { /* Naming a namespace member. */ - if (TYPE_P (current)) + qualified_namespace_lookup (scope, &lookup); + + if (TYPE_P (current) + && (!lookup.value + || lookup.type + || cxx_dialect < cxx20 + || TREE_CODE (lookup.value) != CONST_DECL)) { error ("using-declaration for non-member at class scope"); - return false; + return NULL_TREE; } - - qualified_namespace_lookup (scope, &lookup); } else if (TREE_CODE (scope) == ENUMERAL_TYPE) { - error ("using-declaration may not name enumerator %<%E::%D%>", - scope, lookup.name); - return false; + /* Naming an enumeration member. */ + if (cxx_dialect < cxx20) + error ("% with enumeration scope %q#T " + "only available with %<-std=c++20%> or %<-std=gnu++20%>", + scope); + lookup.value = lookup_enumerator (scope, lookup.name); } else { - /* Naming a class member. */ - if (!TYPE_P (current)) - { - error ("using-declaration for member at non-class scope"); - return false; - } + /* Naming a class member. This is awkward in C++20, because we + might be naming an enumerator of an unrelated class. */ - /* Make sure the name is not invalid */ + /* You cannot using-decl a destructor. */ if (TREE_CODE (lookup.name) == BIT_NOT_EXPR) { error ("%<%T::%D%> names destructor", scope, lookup.name); - return false; + return NULL_TREE; } /* Using T::T declares inheriting ctors, even if T is a typedef. */ @@ -4584,91 +4611,150 @@ lookup_using_decl (tree scope, name_lookup &lookup) && (lookup.name == TYPE_IDENTIFIER (scope) || constructor_name_p (lookup.name, scope))) { + if (!TYPE_P (current)) + { + error ("non-member using-decl names constructor of %qT", scope); + return NULL_TREE; + } maybe_warn_cpp0x (CPP0X_INHERITING_CTORS); lookup.name = ctor_identifier; CLASSTYPE_NON_AGGREGATE (current) = true; } - /* Cannot introduce a constructor name. */ - if (constructor_name_p (lookup.name, current)) + if (!MAYBE_CLASS_TYPE_P (scope)) + ; + else if (TYPE_P (current)) { - error ("%<%T::%D%> names constructor in %qT", - scope, lookup.name, current); - return false; - } - - /* Member using decls finish processing when completing the - class. */ - /* From [namespace.udecl]: - - A using-declaration used as a member-declaration shall refer - to a member of a base class of the class being defined. + dependent_p = dependent_scope_p (scope); + if (!dependent_p) + { + binfo = lookup_base (current, scope, ba_any, &b_kind, tf_none); + gcc_checking_assert (b_kind >= bk_not_base); - In general, we cannot check this constraint in a template - because we do not know the entire set of base classes of the - current class type. Morover, if SCOPE is dependent, it might - match a non-dependent base. */ + if (lookup.name == ctor_identifier) + { + /* Even if there are dependent bases, SCOPE will not + be direct base, no matter. */ + if (b_kind < bk_proper_base || !binfo_direct_p (binfo)) + { + error ("%qT is not a direct base of %qT", scope, current); + return NULL_TREE; + } + } + else if (b_kind < bk_proper_base) + binfo = TYPE_BINFO (scope); + else if (IDENTIFIER_CONV_OP_P (lookup.name) + && dependent_type_p (TREE_TYPE (lookup.name))) + dependent_p = true; + } + } + else + binfo = TYPE_BINFO (scope); - dependent_p = dependent_scope_p (scope); if (!dependent_p) { - base_kind b_kind; - tree binfo = lookup_base (current, scope, ba_any, &b_kind, - tf_warning_or_error); - if (b_kind < bk_proper_base) + if (binfo) + lookup.value = lookup_member (binfo, lookup.name, /*protect=*/2, + /*want_type=*/false, tf_none); + + tree saved_value = lookup.value; + if (lookup.value + && b_kind < bk_proper_base) { - /* If there are dependent bases, scope might resolve at - instantiation time, even if it isn't exactly one of - the dependent bases. */ - if (b_kind == bk_same_type || !any_dependent_bases_p ()) + if (cxx_dialect >= cxx20 + && TREE_CODE (lookup.value) == CONST_DECL) { - error_not_base_type (scope, current); - return false; + /* Using an unrelated enum; check access here rather + than separately for class and non-class using. */ + perform_or_defer_access_check + (binfo, lookup.value, lookup.value, tf_warning_or_error); + /* And then if this is a copy from handle_using_decl, look + through to the original enumerator. */ + if (CONST_DECL_USING_P (lookup.value)) + lookup.value = DECL_ABSTRACT_ORIGIN (lookup.value); } - /* Treat as-if dependent. */ - dependent_p = true; + else + lookup.value = NULL_TREE; } - else if (lookup.name == ctor_identifier && !binfo_direct_p (binfo)) + + if (!lookup.value) { - error ("cannot inherit constructors from indirect base %qT", - scope); - return false; + if (!TYPE_P (current)) + { + error ("using-declaration for member at non-class scope"); + return NULL_TREE; + } + + if (b_kind < bk_proper_base) + { + if (b_kind == bk_not_base && any_dependent_bases_p ()) + /* Treat as-if dependent. */ + dependent_p = true; + else + { + auto_diagnostic_group g; + error_not_base_type (scope, current); + if (saved_value && DECL_IMPLICIT_TYPEDEF_P (saved_value) + && (TREE_CODE (TREE_TYPE (saved_value)) + == ENUMERAL_TYPE)) + inform (input_location, + "did you mean %?", + scope, lookup.name); + return NULL_TREE; + } + } } - else if (IDENTIFIER_CONV_OP_P (lookup.name) - && dependent_type_p (TREE_TYPE (lookup.name))) - dependent_p = true; - else - lookup.value = lookup_member (binfo, lookup.name, 0, - false, tf_warning_or_error); } } - if (!dependent_p) + /* Did we find anything sane? */ + if (dependent_p) + ; + else if (!lookup.value) { - if (!lookup.value) - { - error ("%qD has not been declared in %qE", lookup.name, scope); - return false; - } + error ("%qD has not been declared in %qD", lookup.name, scope); + return NULL_TREE; + } + else if (TREE_CODE (lookup.value) == TREE_LIST + /* We can (independently) have ambiguous implicit typedefs. */ + || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)) + { + error ("reference to %qD is ambiguous", lookup.name); + print_candidates (TREE_CODE (lookup.value) == TREE_LIST + ? lookup.value : lookup.type); + return NULL_TREE; + } + else if (TREE_CODE (lookup.value) == NAMESPACE_DECL) + { + error ("using-declaration may not name namespace %qD", lookup.value); + return NULL_TREE; + } - if (TREE_CODE (lookup.value) == TREE_LIST - /* We can (independently) have ambiguous implicit typedefs. */ - || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)) - { - error ("reference to %qD is ambiguous", lookup.name); - print_candidates (TREE_CODE (lookup.value) == TREE_LIST - ? lookup.value : lookup.type); - return false; - } + if (TYPE_P (current)) + { + /* In class scope. */ - if (TREE_CODE (lookup.value) == NAMESPACE_DECL) + /* Cannot introduce a constructor name. */ + if (constructor_name_p (lookup.name, current)) { - error ("using-declaration may not name namespace %qD", lookup.value); - return false; + error ("%<%T::%D%> names constructor in %qT", + scope, lookup.name, current); + return NULL_TREE; } + + if (lookup.value && BASELINK_P (lookup.value)) + /* The binfo from which the functions came does not matter. */ + lookup.value = BASELINK_FUNCTIONS (lookup.value); } - return true; + tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE); + USING_DECL_SCOPE (using_decl) = scope; + USING_DECL_DECLS (using_decl) = lookup.value; + DECL_DEPENDENT_P (using_decl) = dependent_p; + if (TYPE_P (current) && b_kind == bk_not_base) + USING_DECL_UNRELATED_P (using_decl) = true; + + return using_decl; } /* Process "using SCOPE::NAME" in a class scope. Return the @@ -4682,20 +4768,7 @@ do_class_using_decl (tree scope, tree name) return NULL_TREE; name_lookup lookup (name); - if (!lookup_using_decl (scope, lookup)) - return NULL_TREE; - - tree found = lookup.value; - if (found && BASELINK_P (found)) - /* The binfo from which the functions came does not matter. */ - found = BASELINK_FUNCTIONS (found); - - tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE); - USING_DECL_SCOPE (using_decl) = scope; - USING_DECL_DECLS (using_decl) = found; - DECL_DEPENDENT_P (using_decl) = !found; - - return using_decl; + return lookup_using_decl (scope, lookup); } @@ -5076,7 +5149,8 @@ finish_nonmember_using_decl (tree scope, tree name) name_lookup lookup (name); - if (!lookup_using_decl (scope, lookup)) + tree using_decl = lookup_using_decl (scope, lookup); + if (!using_decl) return; /* Emit debug info. */ @@ -5105,8 +5179,6 @@ finish_nonmember_using_decl (tree scope, tree name) } else { - tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE); - USING_DECL_SCOPE (using_decl) = scope; add_decl_expr (using_decl); cxx_binding *binding = find_local_binding (current_binding_level, name); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 68f1cfa..42f7052 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -808,6 +808,14 @@ make_location (location_t caret, location_t start, cp_lexer *lexer) return make_location (caret, start, t->location); } +/* Overload for make_location taking tokens instead of locations. */ + +static inline location_t +make_location (cp_token *caret, cp_token *start, cp_token *end) +{ + return make_location (caret->location, start->location, end->location); +} + /* nonzero if we are presently saving tokens. */ static inline int @@ -2233,6 +2241,8 @@ static bool cp_parser_using_declaration (cp_parser *, bool); static void cp_parser_using_directive (cp_parser *); +static void cp_parser_using_enum + (cp_parser *); static tree cp_parser_alias_declaration (cp_parser *); static void cp_parser_asm_definition @@ -13726,6 +13736,8 @@ cp_parser_block_declaration (cp_parser *parser, token2 = cp_lexer_peek_nth_token (parser->lexer, 2); if (token2->keyword == RID_NAMESPACE) cp_parser_using_directive (parser); + else if (token2->keyword == RID_ENUM) + cp_parser_using_enum (parser); /* If the second token after 'using' is '=', then we have an alias-declaration. */ else if (cxx_dialect >= cxx11 @@ -20010,6 +20022,31 @@ cp_parser_qualified_namespace_specifier (cp_parser* parser) return cp_parser_namespace_name (parser); } +/* Subroutine of cp_parser_using_declaration. */ + +static tree +finish_using_decl (tree qscope, tree identifier, bool typename_p = false) +{ + tree decl = NULL_TREE; + if (at_class_scope_p ()) + { + /* Create the USING_DECL. */ + decl = do_class_using_decl (qscope, identifier); + + if (check_for_bare_parameter_packs (decl)) + return error_mark_node; + + if (decl && typename_p) + USING_DECL_TYPENAME_P (decl) = 1; + + /* Add it to the list of members in this class. */ + finish_member_declaration (decl); + } + else + finish_nonmember_using_decl (qscope, identifier); + return decl; +} + /* Parse a using-declaration, or, if ACCESS_DECLARATION_P is true, an access declaration. @@ -20029,7 +20066,6 @@ cp_parser_using_declaration (cp_parser* parser, cp_token *token; bool typename_p = false; bool global_scope_p; - tree decl; tree identifier; tree qscope; int oldcount = errorcount; @@ -20088,9 +20124,6 @@ cp_parser_using_declaration (cp_parser* parser, /*is_declaration=*/true); if (!qscope) qscope = global_namespace; - else if (UNSCOPED_ENUM_P (qscope) - && !TYPE_FUNCTION_SCOPE_P (qscope)) - qscope = CP_TYPE_CONTEXT (qscope); cp_warn_deprecated_use_scopes (qscope); @@ -20138,25 +20171,13 @@ cp_parser_using_declaration (cp_parser* parser, "a template-id may not appear in a using-declaration"); else { - if (at_class_scope_p ()) - { - /* Create the USING_DECL. */ - decl = do_class_using_decl (qscope, identifier); - - if (decl && typename_p) - USING_DECL_TYPENAME_P (decl) = 1; + tree decl = finish_using_decl (qscope, identifier, typename_p); - if (check_for_bare_parameter_packs (decl)) - { - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - return false; - } - else - /* Add it to the list of members in this class. */ - finish_member_declaration (decl); + if (decl == error_mark_node) + { + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return false; } - else - finish_nonmember_using_decl (qscope, identifier); } if (!access_declaration_p @@ -20182,6 +20203,76 @@ cp_parser_using_declaration (cp_parser* parser, return true; } +/* C++20 using enum declaration. + + using-enum-declaration : + using elaborated-enum-specifier ; */ + +static void +cp_parser_using_enum (cp_parser *parser) +{ + cp_parser_require_keyword (parser, RID_USING, RT_USING); + + /* Using cp_parser_elaborated_type_specifier rejects typedef-names, which + breaks one of the motivating examples in using-enum-5.C. + cp_parser_simple_type_specifier seems to be closer to what we actually + want, though that hasn't been properly specified yet. */ + + /* Consume 'enum'. */ + gcc_checking_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_ENUM)); + cp_lexer_consume_token (parser->lexer); + + cp_token *start = cp_lexer_peek_token (parser->lexer); + + tree type = (cp_parser_simple_type_specifier + (parser, NULL, CP_PARSER_FLAGS_TYPENAME_OPTIONAL)); + + cp_token *end = cp_lexer_previous_token (parser->lexer); + + if (type == error_mark_node + || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + return; + } + if (TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + + /* The elaborated-enum-specifier shall not name a dependent type and the type + shall have a reachable enum-specifier. */ + const char *msg = nullptr; + if (cxx_dialect < cxx20) + msg = _("% " + "only available with %<-std=c++20%> or %<-std=gnu++20%>"); + else if (dependent_type_p (type)) + msg = _("% of dependent type %qT"); + else if (TREE_CODE (type) != ENUMERAL_TYPE) + msg = _("% of non-enumeration type %q#T"); + else if (!COMPLETE_TYPE_P (type)) + msg = _("% of incomplete type %qT"); + else if (OPAQUE_ENUM_P (type)) + msg = _("% of %qT before its enum-specifier"); + if (msg) + { + location_t loc = make_location (start, start, end); + auto_diagnostic_group g; + error_at (loc, msg, type); + loc = location_of (type); + if (cxx_dialect < cxx20 || loc == input_location) + ; + else if (OPAQUE_ENUM_P (type)) + inform (loc, "opaque-enum-declaration here"); + else + inform (loc, "declared here"); + } + + /* A using-enum-declaration introduces the enumerator names of the named + enumeration as if by a using-declaration for each enumerator. */ + if (TREE_CODE (type) == ENUMERAL_TYPE) + for (tree v = TYPE_VALUES (type); v; v = TREE_CHAIN (v)) + finish_using_decl (type, DECL_NAME (TREE_VALUE (v))); +} + /* Parse an alias-declaration. alias-declaration: @@ -25279,12 +25370,10 @@ cp_parser_member_declaration (cp_parser* parser) if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) { if (cxx_dialect < cxx11) - { - /* Parse the using-declaration. */ - cp_parser_using_declaration (parser, - /*access_declaration_p=*/false); - return; - } + /* Parse the using-declaration. */ + cp_parser_using_declaration (parser, /*access_declaration_p=*/false); + else if (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_ENUM)) + cp_parser_using_enum (parser); else { tree decl; @@ -25305,8 +25394,8 @@ cp_parser_member_declaration (cp_parser* parser) else cp_parser_using_declaration (parser, /*access_declaration_p=*/false); - return; } + return; } /* Check for @defs. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0389198..5ff70ff 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4019,9 +4019,17 @@ finish_id_expression_1 (tree id_expression, if (context != current_class_type) { tree path = currently_open_derived_class (context); - perform_or_defer_access_check (TYPE_BINFO (path), - decl, decl, - tf_warning_or_error); + if (!path) + /* PATH can be null for using an enum of an unrelated + class; we checked its access in lookup_using_decl. + + ??? Should this case make a clone instead, like + handle_using_decl? */ + gcc_assert (TREE_CODE (decl) == CONST_DECL); + else + perform_or_defer_access_check (TYPE_BINFO (path), + decl, decl, + tf_warning_or_error); } } diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 4452b9fa..0e8436e 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -22193,6 +22193,9 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die) dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link); tree value = TREE_VALUE (link); + if (DECL_P (value)) + equate_decl_number_to_die (value, enum_die); + gcc_assert (!ENUM_IS_OPAQUE (type)); add_name_attribute (enum_die, IDENTIFIER_POINTER (TREE_PURPOSE (link))); @@ -25247,6 +25250,10 @@ gen_member_die (tree type, dw_die_ref context_die) splice = false; } } + else if (child->die_tag == DW_TAG_enumerator) + /* Enumerators remain under their enumeration even if + their names are introduced in the enclosing scope. */ + splice = false; if (splice) splice_child_die (context_die, child); @@ -26158,6 +26165,13 @@ force_decl_die (tree decl) decl_die = comp_unit_die (); break; + case CONST_DECL: + /* Enumerators shouldn't need force_decl_die. */ + gcc_assert (DECL_CONTEXT (decl) == NULL_TREE + || TREE_CODE (DECL_CONTEXT (decl)) != ENUMERAL_TYPE); + gen_decl_die (decl, NULL, NULL, context_die); + break; + case TRANSLATION_UNIT_DECL: decl_die = comp_unit_die (); break; @@ -26743,7 +26757,7 @@ dwarf2out_imported_module_or_decl_1 (tree decl, else xloc = expand_location (input_location); - if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL) + if (TREE_CODE (decl) == TYPE_DECL) { at_import_die = force_type_die (TREE_TYPE (decl)); /* For namespace N { typedef void T; } using N::T; base_type_die diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor28.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor28.C index 90a06c6..59801a1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor28.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor28.C @@ -4,4 +4,4 @@ struct A {}; struct B : virtual A {}; struct C : virtual A {}; -struct D : B,C { using A::A; }; // { dg-error "indirect" } +struct D : B,C { using A::A; }; // { dg-error "not a direct base" } diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor33.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor33.C index 95b7812..4e61290 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor33.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor33.C @@ -10,7 +10,7 @@ public: class Y : public X { }; class Z : public Y { - using X::X; // { dg-error "cannot inherit constructors from indirect base .X." } + using X::X; // { dg-error ".X. is not a direct base of .Z." } }; int main() diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-1.C b/gcc/testsuite/g++.dg/cpp0x/using-enum-1.C index 9904d59..bf251ba 100644 --- a/gcc/testsuite/g++.dg/cpp0x/using-enum-1.C +++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-1.C @@ -1,6 +1,9 @@ // PR c++/60265 // { dg-do compile { target c++11 } } +// [namespace.udecl]/7 shall not name a scoped enumerator. +// (so unscoped enumerator is ok) + namespace A { enum E { V }; diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C b/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C index faa3817..8ea70d7 100644 --- a/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C +++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C @@ -1,20 +1,23 @@ // PR c++/60265 // { dg-do compile { target c++11 } } +// [namespace.udecl]/7 shall not name a scoped enumerator. +// (this changes in C++2a) + namespace A { enum class E { V }; - using E::V; // { dg-error "name enumerator" } + using E::V; // { dg-error "enum" "" { target { ! c++2a } } } } void foo() { - using A::E::V; // { dg-error "name enumerator" } + using A::E::V; // { dg-error "enum" "" { target { ! c++2a } } } } -using A::E::V; // { dg-error "name enumerator" } +using A::E::V; // { dg-error "enum" "" { target { ! c++2a } } } enum class F { U }; -using F::U; // { dg-error "name enumerator" } +using F::U; // { dg-error "enum" "" { target { ! c++2a } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C index ecc4ddc..34f8bf4 100644 --- a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C +++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C @@ -1,15 +1,24 @@ // PR c++/89511 // { dg-do compile { target c++11 } } +// [namespace.udecl] In a using-declaration used as a +// member-declaration, the nested-name-specifier shall name a base +// class of the class being defined +// (this changes in C++2a) + void f () { enum e { a }; - using e::a; // { dg-error "name enumerator" } + using e::a; // { dg-error "redeclaration" } + // { dg-error "enum" "" { target { ! c++2a } } .-1 } } +enum E { A }; + struct S { enum E { A }; - using E::A; // { dg-error "type .S. is not a base type for type .S." } + using E::A; // { dg-error "not a base" "" { target { ! c++2a } } } + // { dg-error "conflicts" "" { target c++2a } .-1 } }; namespace N { @@ -17,5 +26,5 @@ namespace N { } struct T { - using N::E::B; // { dg-error "using-declaration for non-member at class scope" } + using N::E::B; // { dg-error "enum" "" { target { ! c++2a } } } }; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction69.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction69.C index 8291f4a..d336366 100644 --- a/gcc/testsuite/g++.dg/cpp1z/class-deduction69.C +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction69.C @@ -6,7 +6,7 @@ namespace a { template using c = b; } template struct e : a::c { // { dg-error "incomplete" } - using a::c<>::c; // { dg-prune-output "not a base" } + using a::c<>::c; // { dg-prune-output "not a direct base" } }; template