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

Reply via email to