On 08/01/2018 05:04 PM, Marc Glisse wrote: > On Wed, 1 Aug 2018, Martin Liška wrote: > >> On 08/01/2018 02:25 PM, Marc Glisse wrote: >>> On Wed, 1 Aug 2018, Martin Liška wrote: >>> >>>> On 07/27/2018 02:38 PM, Marc Glisse wrote: >>>>> On Fri, 27 Jul 2018, Martin Liška wrote: >>>>> >>>>>> So answer is yes, the builtin can be then removed. >>>>> >>>>> Good, thanks. While looking at how widely it is going to apply, I noticed >>>>> that the default, throwing operator new has attribute malloc and >>>>> everything, but the non-throwing variant declared in <new> doesn't, so it >>>>> won't benefit from the new predictor. I don't know if there is a good >>>>> reason for this disparity... >>>>> >>>> >>>> Well in case somebody uses operator new: >>>> >>>> int* p1 = new int; >>>> if (p1) >>>> delete p1; >>>> >>>> we optimize out that to if (true), even when one has used defined >>>> operator new. Thus it's probably OK. >>> >>> Throwing new is returns_nonnull (errors are reported with exceptions) so >>> that's fine, but non-throwing new is not: >>> >>> int* p1 = new(std::nothrow) int; >>> >>> Here errors are reported by returning 0, so it is common to test if p1 is 0 >>> and this is precisely the case that could benefit from a predictor but does >>> not have the attribute to do so (there are also consequences on aliasing). >> >> Then it can be handled with DECL_IS_OPERATOR_NEW, for those we can also set >> the newly introduced predictor. > > Independently of whether you extend the predictor to DECL_IS_OPERATOR_NEW, it > would be good for this nothrow operator new to get the aliasing benefits of > attribute malloc. I'll open a PR. > >>> (Jan's remark about functions with an inferred malloc attribute reminds me >>> that at some point, the code was adding attribute malloc for functions that >>> always return 0...) >> >> By inferred do you mean function that are marked as malloc in IPA pure-const >> (propagate_malloc)? > > Yes. > >> Example would be appreciated. > > I used the past tense, I am not claiming this still happens. >
Ok, so I'm sending updated version of the patch including DECL_IS_OPERATOR_NEW operator. In SPEC2006 it's seen 1021 times. There are some statistics about frequency of individual benchmarks: 400.perlbench: 4 401.bzip2: 4 403.gcc: 13 410.bwaves: 0 416.gamess: 0 429.mcf: 4 433.milc: 23 434.zeusmp: 0 435.gromacs: 13 436.cactusADM: 221 437.leslie3d: 84 444.namd: 1 445.gobmk: 15 447.dealII: 52 450.soplex: 87 453.povray: 20 454.calculix: 102 456.hmmer: 40 458.sjeng: 4 459.GemsFDTD: 0 462.libquantum: 19 464.h264ref: 166 465.tonto: 55 470.lbm: 1 471.omnetpp: 3 473.astar: 0 481.wrf: 47 482.sphinx3: 21 483.xalancbmk: 22 Ready for trunk? Martin
>From 8689ac0907c27709d81f72782eaa5a3a752a2991 Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Thu, 26 Jul 2018 15:25:00 +0200 Subject: [PATCH] Add malloc predictor (PR middle-end/83023). gcc/ChangeLog: 2018-07-26 Martin Liska <mli...@suse.cz> PR middle-end/83023 * predict.c (expr_expected_value_1): Handle DECL_IS_MALLOC, BUILT_IN_REALLOC and DECL_IS_OPERATOR_NEW. * predict.def (PRED_MALLOC_NONNULL): New predictor. gcc/testsuite/ChangeLog: 2018-07-26 Martin Liska <mli...@suse.cz> PR middle-end/83023 * gcc.dg/predict-16.c: New test. * g++.dg/predict-1.C: New test. --- gcc/predict.c | 12 +++++++++++ gcc/predict.def | 5 ++++- gcc/testsuite/g++.dg/predict-1.C | 15 +++++++++++++ gcc/testsuite/gcc.dg/predict-16.c | 36 +++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/predict-1.C create mode 100644 gcc/testsuite/gcc.dg/predict-16.c diff --git a/gcc/predict.c b/gcc/predict.c index 2ee8274fe61..ef6794edda5 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -2380,6 +2380,14 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, } return NULL; } + + if (DECL_IS_MALLOC (decl) || DECL_IS_OPERATOR_NEW (decl)) + { + if (predictor) + *predictor = PRED_MALLOC_NONNULL; + return boolean_true_node; + } + if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (decl)) { @@ -2420,6 +2428,10 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code, if (predictor) *predictor = PRED_COMPARE_AND_SWAP; return boolean_true_node; + case BUILT_IN_REALLOC: + if (predictor) + *predictor = PRED_MALLOC_NONNULL; + return boolean_true_node; default: break; } diff --git a/gcc/predict.def b/gcc/predict.def index 03900bf89b3..bf659704bfc 100644 --- a/gcc/predict.def +++ b/gcc/predict.def @@ -55,6 +55,10 @@ DEF_PREDICTOR (PRED_UNCONDITIONAL, "unconditional jump", PROB_ALWAYS, DEF_PREDICTOR (PRED_BUILTIN_UNPREDICTABLE, "__builtin_unpredictable", PROB_EVEN, PRED_FLAG_FIRST_MATCH) +/* Return value of malloc function is almost always non-null. */ +DEF_PREDICTOR (PRED_MALLOC_NONNULL, "malloc returned non-NULL", \ + PROB_VERY_LIKELY, PRED_FLAG_FIRST_MATCH) + /* Use number of loop iterations determined by # of iterations analysis to set probability. We don't want to use Dempster-Shaffer theory here, as the predictions is exact. */ @@ -173,7 +177,6 @@ DEF_PREDICTOR (PRED_HOT_LABEL, "hot label", HITRATE (85), 0) DEF_PREDICTOR (PRED_COLD_LABEL, "cold label", PROB_VERY_LIKELY, PRED_FLAG_FIRST_MATCH) - /* The following predictors are used in Fortran. */ /* Branch leading to an integer overflow are extremely unlikely. */ diff --git a/gcc/testsuite/g++.dg/predict-1.C b/gcc/testsuite/g++.dg/predict-1.C new file mode 100644 index 00000000000..8e2032f33a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/predict-1.C @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-profile_estimate" } */ + +#include <new> + +int *r; + +void test() +{ + r = new(std::nothrow) int; + if (r) + __builtin_memset (r, 0, sizeof(int)); +} + +/* { dg-final { scan-tree-dump "malloc returned non-NULL heuristics of edge\[^:\]*: 99.96%" "profile_estimate"} } */ diff --git a/gcc/testsuite/gcc.dg/predict-16.c b/gcc/testsuite/gcc.dg/predict-16.c new file mode 100644 index 00000000000..e1f331b909a --- /dev/null +++ b/gcc/testsuite/gcc.dg/predict-16.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-profile_estimate" } */ + +#include <stdlib.h> +#include <string.h> + +void *r; +void *r2; +void *r3; +void *r4; +void *r5; + +void *m (size_t s, int c) +{ + r = malloc (s); + if (r) + memset (r, 0, s); + + r2 = calloc (s, 0); + if (r2) + memset (r2, 0, s); + + r3 = __builtin_malloc (s); + if (r3) + memset (r3, 0, s); + + r4 = __builtin_calloc (s, 0); + if (r4) + memset (r4, 0, s); + + r5 = __builtin_realloc (r4, s); + if (r5) + memset (r4, 0, s); +} + +/* { dg-final { scan-tree-dump-times "malloc returned non-NULL heuristics of edge\[^:\]*: 99.96%" 5 "profile_estimate"} } */ -- 2.18.0