public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
                   ` (2 preceding siblings ...)
  2014-11-13 20:39 ` [PATCH 7/9] Old libiberty fib_heap removed mliska
@ 2014-11-13 20:39 ` mliska
  2014-11-14  4:32   ` Jeff Law
  2014-11-19 18:42   ` H.J. Lu
  2014-11-13 20:39 ` [PATCH 5/9] bt-load is ported to fibonacci_heap mliska
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 38+ messages in thread
From: mliska @ 2014-11-13 20:39 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* bb-reorder.c (mark_bb_visited): New fibonacci_heap is used.
	(find_traces): Likewise.
	(find_traces_1_round): Likewise.
---
 gcc/bb-reorder.c | 54 +++++++++++++++++++++++++++---------------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index 1f7c3ee..b1223a7 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -120,6 +120,7 @@
 #include "ipa-ref.h"
 #include "cgraph.h"
 #include "except.h"
+#include "fibonacci_heap.h"
 
 /* The number of rounds.  In most cases there will only be 4 rounds, but
    when partitioning hot and cold basic blocks into separate sections of
@@ -153,6 +154,9 @@ static const int exec_threshold[N_ROUNDS] = {500, 200, 50, 0, 0};
    block the edge destination is not duplicated while connecting traces.  */
 #define DUPLICATION_THRESHOLD 100
 
+typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
+typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
+
 /* Structure to hold needed information for each basic block.  */
 typedef struct bbro_basic_block_data_def
 {
@@ -169,10 +173,10 @@ typedef struct bbro_basic_block_data_def
   int visited;
 
   /* Which heap is BB in (if any)?  */
-  fibheap_t heap;
+  bb_heap_t *heap;
 
   /* Which heap node is BB in (if any)?  */
-  fibnode_t node;
+  bb_heap_node_t *node;
 } bbro_basic_block_data;
 
 /* The current size of the following dynamic array.  */
@@ -210,7 +214,7 @@ static void find_traces (int *, struct trace *);
 static basic_block rotate_loop (edge, struct trace *, int);
 static void mark_bb_visited (basic_block, int);
 static void find_traces_1_round (int, int, gcov_type, struct trace *, int *,
-				 int, fibheap_t *, int);
+				 int, bb_heap_t **, int);
 static basic_block copy_bb (basic_block, edge, basic_block, int);
 static fibheapkey_t bb_to_key (basic_block);
 static bool better_edge_p (const_basic_block, const_edge, int, int, int, int,
@@ -238,7 +242,7 @@ mark_bb_visited (basic_block bb, int trace)
   bbd[bb->index].visited = trace;
   if (bbd[bb->index].heap)
     {
-      fibheap_delete_node (bbd[bb->index].heap, bbd[bb->index].node);
+      bbd[bb->index].heap->delete_node (bbd[bb->index].node);
       bbd[bb->index].heap = NULL;
       bbd[bb->index].node = NULL;
     }
@@ -283,7 +287,7 @@ find_traces (int *n_traces, struct trace *traces)
   int number_of_rounds;
   edge e;
   edge_iterator ei;
-  fibheap_t heap;
+  bb_heap_t *heap = new bb_heap_t (LONG_MIN);
 
   /* Add one extra round of trace collection when partitioning hot/cold
      basic blocks into separate sections.  The last round is for all the
@@ -292,14 +296,12 @@ find_traces (int *n_traces, struct trace *traces)
   number_of_rounds = N_ROUNDS - 1;
 
   /* Insert entry points of function into heap.  */
-  heap = fibheap_new ();
   max_entry_frequency = 0;
   max_entry_count = 0;
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
     {
       bbd[e->dest->index].heap = heap;
-      bbd[e->dest->index].node = fibheap_insert (heap, bb_to_key (e->dest),
-						    e->dest);
+      bbd[e->dest->index].node = heap->insert (bb_to_key (e->dest), e->dest);
       if (e->dest->frequency > max_entry_frequency)
 	max_entry_frequency = e->dest->frequency;
       if (e->dest->count > max_entry_count)
@@ -324,7 +326,7 @@ find_traces (int *n_traces, struct trace *traces)
 			   count_threshold, traces, n_traces, i, &heap,
 			   number_of_rounds);
     }
-  fibheap_delete (heap);
+  delete heap;
 
   if (dump_file)
     {
@@ -470,14 +472,14 @@ rotate_loop (edge back_edge, struct trace *trace, int trace_n)
 static void
 find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
 		     struct trace *traces, int *n_traces, int round,
-		     fibheap_t *heap, int number_of_rounds)
+		     bb_heap_t **heap, int number_of_rounds)
 {
   /* Heap for discarded basic blocks which are possible starting points for
      the next round.  */
-  fibheap_t new_heap = fibheap_new ();
+  bb_heap_t *new_heap = new bb_heap_t (LONG_MIN);
   bool for_size = optimize_function_for_size_p (cfun);
 
-  while (!fibheap_empty (*heap))
+  while (!(*heap)->empty ())
     {
       basic_block bb;
       struct trace *trace;
@@ -485,7 +487,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
       fibheapkey_t key;
       edge_iterator ei;
 
-      bb = (basic_block) fibheap_extract_min (*heap);
+      bb = (*heap)->extract_min ();
       bbd[bb->index].heap = NULL;
       bbd[bb->index].node = NULL;
 
@@ -503,7 +505,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
 	{
 	  int key = bb_to_key (bb);
 	  bbd[bb->index].heap = new_heap;
-	  bbd[bb->index].node = fibheap_insert (new_heap, key, bb);
+	  bbd[bb->index].node = new_heap->insert (key, bb);
 
 	  if (dump_file)
 	    fprintf (dump_file,
@@ -633,23 +635,23 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
 	      if (bbd[e->dest->index].heap)
 		{
 		  /* E->DEST is already in some heap.  */
-		  if (key != bbd[e->dest->index].node->key)
+		  if (key != bbd[e->dest->index].node->get_key ())
 		    {
 		      if (dump_file)
 			{
 			  fprintf (dump_file,
 				   "Changing key for bb %d from %ld to %ld.\n",
 				   e->dest->index,
-				   (long) bbd[e->dest->index].node->key,
+				   (long) bbd[e->dest->index].node->get_key (),
 				   key);
 			}
-		      fibheap_replace_key (bbd[e->dest->index].heap,
-					   bbd[e->dest->index].node, key);
+		      bbd[e->dest->index].heap->replace_key
+		        (bbd[e->dest->index].node, key);
 		    }
 		}
 	      else
 		{
-		  fibheap_t which_heap = *heap;
+		  bb_heap_t *which_heap = *heap;
 
 		  prob = e->probability;
 		  freq = EDGE_FREQUENCY (e);
@@ -671,8 +673,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
 		    }
 
 		  bbd[e->dest->index].heap = which_heap;
-		  bbd[e->dest->index].node = fibheap_insert (which_heap,
-								key, e->dest);
+		  bbd[e->dest->index].node = which_heap->insert (key, e->dest);
 
 		  if (dump_file)
 		    {
@@ -803,24 +804,23 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
 	  if (bbd[e->dest->index].heap)
 	    {
 	      key = bb_to_key (e->dest);
-	      if (key != bbd[e->dest->index].node->key)
+	      if (key != bbd[e->dest->index].node->get_key ())
 		{
 		  if (dump_file)
 		    {
 		      fprintf (dump_file,
 			       "Changing key for bb %d from %ld to %ld.\n",
 			       e->dest->index,
-			       (long) bbd[e->dest->index].node->key, key);
+			       (long) bbd[e->dest->index].node->get_key (), key);
 		    }
-		  fibheap_replace_key (bbd[e->dest->index].heap,
-				       bbd[e->dest->index].node,
-				       key);
+		  bbd[e->dest->index].heap->replace_key
+		    (bbd[e->dest->index].node, key);
 		}
 	    }
 	}
     }
 
-  fibheap_delete (*heap);
+  delete (*heap);
 
   /* "Return" the new heap.  */
   *heap = new_heap;
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 4/9] tracer ported to new fibonacci_heap data structure.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
@ 2014-11-13 20:39 ` mliska
  2014-11-14  4:31   ` Jeff Law
  2014-11-13 20:39 ` [PATCH 6/9] fibonacci_heap is used for var-tracking mliska
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: mliska @ 2014-11-13 20:39 UTC (permalink / raw)
  To: gcc-patches

2014-11-13  Martin Liska  <mliska@suse.cz>

	* tracer.c (tail_duplicate): New fibonacci_heap class is used.
---
 gcc/tracer.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/gcc/tracer.c b/gcc/tracer.c
index b3a412c..cecefdc 100644
--- a/gcc/tracer.c
+++ b/gcc/tracer.c
@@ -52,7 +52,6 @@
 #include "cfg.h"
 #include "cfganal.h"
 #include "basic-block.h"
-#include "fibheap.h"
 #include "flags.h"
 #include "params.h"
 #include "coverage.h"
@@ -67,6 +66,7 @@
 #include "tree-ssa.h"
 #include "tree-inline.h"
 #include "cfgloop.h"
+#include "fibonacci_heap.h"
 
 static int count_insns (basic_block);
 static bool ignore_bb_p (const_basic_block);
@@ -241,12 +241,14 @@ find_trace (basic_block bb, basic_block *trace)
 static bool
 tail_duplicate (void)
 {
-  fibnode_t *blocks = XCNEWVEC (fibnode_t, last_basic_block_for_fn (cfun));
+  auto_vec<fibonacci_node<long, basic_block_def>*> blocks;
+  blocks.safe_grow_cleared (last_basic_block_for_fn (cfun));
+
   basic_block *trace = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
   int *counts = XNEWVEC (int, last_basic_block_for_fn (cfun));
   int ninsns = 0, nduplicated = 0;
   gcov_type weighted_insns = 0, traced_insns = 0;
-  fibheap_t heap = fibheap_new ();
+  fibonacci_heap<long, basic_block_def> heap (LONG_MIN);
   gcov_type cover_insns;
   int max_dup_insns;
   basic_block bb;
@@ -271,8 +273,7 @@ tail_duplicate (void)
     {
       int n = count_insns (bb);
       if (!ignore_bb_p (bb))
-	blocks[bb->index] = fibheap_insert (heap, -bb->frequency,
-					    bb);
+	blocks[bb->index] = heap.insert (-bb->frequency, bb);
 
       counts [bb->index] = n;
       ninsns += n;
@@ -287,9 +288,9 @@ tail_duplicate (void)
   max_dup_insns = (ninsns * PARAM_VALUE (TRACER_MAX_CODE_GROWTH) + 50) / 100;
 
   while (traced_insns < cover_insns && nduplicated < max_dup_insns
-         && !fibheap_empty (heap))
+         && !heap.empty ())
     {
-      basic_block bb = (basic_block) fibheap_extract_min (heap);
+      basic_block bb = heap.extract_min ();
       int n, pos;
 
       if (!bb)
@@ -307,7 +308,7 @@ tail_duplicate (void)
       traced_insns += bb->frequency * counts [bb->index];
       if (blocks[bb->index])
 	{
-	  fibheap_delete_node (heap, blocks[bb->index]);
+	  heap.delete_node (blocks[bb->index]);
 	  blocks[bb->index] = NULL;
 	}
 
@@ -317,7 +318,7 @@ tail_duplicate (void)
 
 	  if (blocks[bb2->index])
 	    {
-	      fibheap_delete_node (heap, blocks[bb2->index]);
+	      heap.delete_node (blocks[bb2->index]);
 	      blocks[bb2->index] = NULL;
 	    }
 	  traced_insns += bb2->frequency * counts [bb2->index];
@@ -344,8 +345,7 @@ tail_duplicate (void)
 	      /* Reconsider the original copy of block we've duplicated.
 	         Removing the most common predecessor may make it to be
 	         head.  */
-	      blocks[bb2->index] =
-		fibheap_insert (heap, -bb2->frequency, bb2);
+	      blocks[bb2->index] = heap.insert (-bb2->frequency, bb2);
 
 	      if (dump_file)
 		fprintf (dump_file, "Duplicated %i as %i [%i]\n",
@@ -370,10 +370,8 @@ tail_duplicate (void)
 
   free_original_copy_tables ();
   sbitmap_free (bb_seen);
-  free (blocks);
   free (trace);
   free (counts);
-  fibheap_delete (heap);
 
   return changed;
 }
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 5/9] bt-load is ported to fibonacci_heap.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
                   ` (3 preceding siblings ...)
  2014-11-13 20:39 ` [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose mliska
@ 2014-11-13 20:39 ` mliska
  2014-11-14  4:34   ` Jeff Law
  2014-11-13 20:45 ` [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument mliska
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: mliska @ 2014-11-13 20:39 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* bt-load.c (add_btr_def): New fibonacci_heap is used.
	(migrate_btr_defs): Likewise.
---
 gcc/bt-load.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/gcc/bt-load.c b/gcc/bt-load.c
index 66bbf03..a9064bd 100644
--- a/gcc/bt-load.c
+++ b/gcc/bt-load.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "cfgloop.h"
 #include "rtl-iter.h"
+#include "fibonacci_heap.h"
 
 /* Target register optimizations - these are performed after reload.  */
 
@@ -122,23 +123,26 @@ typedef struct btr_def_s
   bitmap live_range;
 } *btr_def;
 
+typedef fibonacci_heap <long, btr_def_s> btr_heap_t;
+typedef fibonacci_node <long, btr_def_s> btr_heap_node_t;
+
 static int issue_rate;
 
 static int basic_block_freq (const_basic_block);
 static int insn_sets_btr_p (const rtx_insn *, int, int *);
 static void find_btr_def_group (btr_def_group *, btr_def);
-static btr_def add_btr_def (fibheap_t, basic_block, int, rtx_insn *,
+static btr_def add_btr_def (btr_heap_t *, basic_block, int, rtx_insn *,
 			    unsigned int, int, btr_def_group *);
 static btr_user new_btr_user (basic_block, int, rtx_insn *);
 static void dump_hard_reg_set (HARD_REG_SET);
 static void dump_btrs_live (int);
 static void note_other_use_this_block (unsigned int, btr_user);
-static void compute_defs_uses_and_gen (fibheap_t, btr_def *,btr_user *,
+static void compute_defs_uses_and_gen (btr_heap_t *, btr_def *,btr_user *,
 				       sbitmap *, sbitmap *, HARD_REG_SET *);
 static void compute_kill (sbitmap *, sbitmap *, HARD_REG_SET *);
 static void compute_out (sbitmap *bb_out, sbitmap *, sbitmap *, int);
 static void link_btr_uses (btr_def *, btr_user *, sbitmap *, sbitmap *, int);
-static void build_btr_def_use_webs (fibheap_t);
+static void build_btr_def_use_webs (btr_heap_t *);
 static int block_at_edge_of_live_range_p (int, btr_def);
 static void clear_btr_from_live_range (btr_def def);
 static void add_btr_to_live_range (btr_def, int);
@@ -290,7 +294,7 @@ find_btr_def_group (btr_def_group *all_btr_def_groups, btr_def def)
    block BB, instruction INSN, and insert it into ALL_BTR_DEFS.  Return
    the new definition.  */
 static btr_def
-add_btr_def (fibheap_t all_btr_defs, basic_block bb, int insn_luid,
+add_btr_def (btr_heap_t *all_btr_defs, basic_block bb, int insn_luid,
 	     rtx_insn *insn,
 	     unsigned int dest_reg, int other_btr_uses_before_def,
 	     btr_def_group *all_btr_def_groups)
@@ -310,7 +314,7 @@ add_btr_def (fibheap_t all_btr_defs, basic_block bb, int insn_luid,
   this_def->live_range = NULL;
   find_btr_def_group (all_btr_def_groups, this_def);
 
-  fibheap_insert (all_btr_defs, -this_def->cost, this_def);
+  all_btr_defs->insert (-this_def->cost, this_def);
 
   if (dump_file)
     fprintf (dump_file,
@@ -436,7 +440,7 @@ note_btr_set (rtx dest, const_rtx set ATTRIBUTE_UNUSED, void *data)
 }
 
 static void
-compute_defs_uses_and_gen (fibheap_t all_btr_defs, btr_def *def_array,
+compute_defs_uses_and_gen (btr_heap_t *all_btr_defs, btr_def *def_array,
 			   btr_user *use_array, sbitmap *btr_defset,
 			   sbitmap *bb_gen, HARD_REG_SET *btrs_written)
 {
@@ -767,7 +771,7 @@ link_btr_uses (btr_def *def_array, btr_user *use_array, sbitmap *bb_out,
 }
 
 static void
-build_btr_def_use_webs (fibheap_t all_btr_defs)
+build_btr_def_use_webs (btr_heap_t *all_btr_defs)
 {
   const int max_uid = get_max_uid ();
   btr_def  *def_array   = XCNEWVEC (btr_def, max_uid);
@@ -1393,7 +1397,7 @@ migrate_btr_def (btr_def def, int min_cost)
 static void
 migrate_btr_defs (enum reg_class btr_class, int allow_callee_save)
 {
-  fibheap_t all_btr_defs = fibheap_new ();
+  btr_heap_t all_btr_defs (LONG_MIN);
   int reg;
 
   gcc_obstack_init (&migrate_btrl_obstack);
@@ -1427,15 +1431,15 @@ migrate_btr_defs (enum reg_class btr_class, int allow_callee_save)
   btrs_live = XCNEWVEC (HARD_REG_SET, last_basic_block_for_fn (cfun));
   btrs_live_at_end = XCNEWVEC (HARD_REG_SET, last_basic_block_for_fn (cfun));
 
-  build_btr_def_use_webs (all_btr_defs);
+  build_btr_def_use_webs (&all_btr_defs);
 
-  while (!fibheap_empty (all_btr_defs))
+  while (!all_btr_defs.empty ())
     {
-      btr_def def = (btr_def) fibheap_extract_min (all_btr_defs);
-      int min_cost = -fibheap_min_key (all_btr_defs);
+      btr_def def = all_btr_defs.extract_min ();
+      int min_cost = -all_btr_defs.min_key ();
       if (migrate_btr_def (def, min_cost))
 	{
-	  fibheap_insert (all_btr_defs, -def->cost, (void *) def);
+	  all_btr_defs.insert (-def->cost, def);
 	  if (dump_file)
 	    {
 	      fprintf (dump_file,
@@ -1450,7 +1454,6 @@ migrate_btr_defs (enum reg_class btr_class, int allow_callee_save)
   free (btrs_live);
   free (btrs_live_at_end);
   obstack_free (&migrate_btrl_obstack, NULL);
-  fibheap_delete (all_btr_defs);
 }
 
 static void
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 7/9] Old libiberty fib_heap removed.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
  2014-11-13 20:39 ` [PATCH 4/9] tracer ported to new fibonacci_heap data structure mliska
  2014-11-13 20:39 ` [PATCH 6/9] fibonacci_heap is used for var-tracking mliska
@ 2014-11-13 20:39 ` mliska
  2014-11-13 23:54   ` Jan Hubicka
  2014-11-13 20:39 ` [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose mliska
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: mliska @ 2014-11-13 20:39 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* bb-reorder.c (find_traces_1_round): Old fibheap_t type removed.
	* bt-load.c: Include of fibheap.h is removed.
	* cgraphunit.c: Likewise.
	* config/i386/i386.c: Likewise.
	* ipa-inline.c: Likewise.
	* var-tracking.c: Likewise.

include/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* fibheap.h: Remove.

libiberty/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* Makefile.in: Remove.
	* fibheap.c: Remove.
---
 gcc/bb-reorder.c       |   7 +-
 gcc/bt-load.c          |   1 -
 gcc/cgraphunit.c       |   1 -
 gcc/config/i386/i386.c |   1 -
 gcc/ipa-inline.c       |   1 -
 gcc/var-tracking.c     |   1 -
 include/fibheap.h      |  95 ----------
 libiberty/Makefile.in  |  15 +-
 libiberty/fibheap.c    | 486 -------------------------------------------------
 9 files changed, 5 insertions(+), 603 deletions(-)
 delete mode 100644 include/fibheap.h
 delete mode 100644 libiberty/fibheap.c

diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index b1223a7..a1f352cc 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -87,7 +87,6 @@
 #include "regs.h"
 #include "flags.h"
 #include "output.h"
-#include "fibheap.h"
 #include "target.h"
 #include "hashtab.h"
 #include "hash-set.h"
@@ -216,7 +215,7 @@ static void mark_bb_visited (basic_block, int);
 static void find_traces_1_round (int, int, gcov_type, struct trace *, int *,
 				 int, bb_heap_t **, int);
 static basic_block copy_bb (basic_block, edge, basic_block, int);
-static fibheapkey_t bb_to_key (basic_block);
+static long bb_to_key (basic_block);
 static bool better_edge_p (const_basic_block, const_edge, int, int, int, int,
 			   const_edge);
 static bool connect_better_edge_p (const_edge, bool, int, const_edge,
@@ -484,7 +483,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
       basic_block bb;
       struct trace *trace;
       edge best_edge, e;
-      fibheapkey_t key;
+      long key;
       edge_iterator ei;
 
       bb = (*heap)->extract_min ();
@@ -885,7 +884,7 @@ copy_bb (basic_block old_bb, edge e, basic_block bb, int trace)
 
 /* Compute and return the key (for the heap) of the basic block BB.  */
 
-static fibheapkey_t
+static long 
 bb_to_key (basic_block bb)
 {
   edge e;
diff --git a/gcc/bt-load.c b/gcc/bt-load.c
index a9064bd..3002b62 100644
--- a/gcc/bt-load.c
+++ b/gcc/bt-load.c
@@ -25,7 +25,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "hard-reg-set.h"
 #include "regs.h"
-#include "fibheap.h"
 #include "target.h"
 #include "expr.h"
 #include "flags.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 25af234..87f0900 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -197,7 +197,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "diagnostic.h"
 #include "params.h"
-#include "fibheap.h"
 #include "intl.h"
 #include "hash-map.h"
 #include "plugin-api.h"
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index b70c56c..bac58b6 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -86,7 +86,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "sched-int.h"
 #include "sbitmap.h"
-#include "fibheap.h"
 #include "opts.h"
 #include "diagnostic.h"
 #include "dumpfile.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 1ce856f..aa5d029 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -102,7 +102,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "gimple-pretty-print.h"
 #include "params.h"
-#include "fibheap.h"
 #include "intl.h"
 #include "tree-pass.h"
 #include "coverage.h"
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 2278815..e7d4ff1 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -114,7 +114,6 @@
 #include "reload.h"
 #include "sbitmap.h"
 #include "alloc-pool.h"
-#include "fibheap.h"
 #include "regs.h"
 #include "expr.h"
 #include "tree-pass.h"
diff --git a/include/fibheap.h b/include/fibheap.h
deleted file mode 100644
index a3d09dd..0000000
--- a/include/fibheap.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* A Fibonacci heap datatype.
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009
-   Free Software Foundation, Inc.
-   Contributed by Daniel Berlin (dan@cgsoftware.com).
-
-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 2, 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 COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street - Fifth Floor,
-Boston, MA 02110-1301, USA.  */
-
-/* Fibonacci heaps are somewhat complex, but, there's an article in
-   DDJ that explains them pretty well:
-
-   http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms
-
-   Introduction to algorithms by Corman and Rivest also goes over them.
-
-   The original paper that introduced them is "Fibonacci heaps and their
-   uses in improved network optimization algorithms" by Tarjan and
-   Fredman (JACM 34(3), July 1987).
-
-   Amortized and real worst case time for operations:
-
-   ExtractMin: O(lg n) amortized. O(n) worst case.
-   DecreaseKey: O(1) amortized.  O(lg n) worst case. 
-   Insert: O(2) amortized. O(1) actual.  
-   Union: O(1) amortized. O(1) actual.  */
-
-#ifndef _FIBHEAP_H_
-#define _FIBHEAP_H_
-
-#include "ansidecl.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef long fibheapkey_t;
-
-typedef struct fibheap
-{
-  size_t nodes;
-  struct fibnode *min;
-  struct fibnode *root;
-} *fibheap_t;
-
-typedef struct fibnode
-{
-  struct fibnode *parent;
-  struct fibnode *child;
-  struct fibnode *left;
-  struct fibnode *right;
-  fibheapkey_t key;
-  void *data;
-#if defined (__GNUC__) && (!defined (SIZEOF_INT) || SIZEOF_INT < 4)
-  __extension__ unsigned long int degree : 31;
-  __extension__ unsigned long int mark : 1;
-#else
-  unsigned int degree : 31;
-  unsigned int mark : 1;
-#endif
-} *fibnode_t;
-
-extern fibheap_t fibheap_new (void);
-extern fibnode_t fibheap_insert (fibheap_t, fibheapkey_t, void *);
-extern int fibheap_empty (fibheap_t);
-extern fibheapkey_t fibheap_min_key (fibheap_t);
-extern fibheapkey_t fibheap_replace_key (fibheap_t, fibnode_t,
-                                         fibheapkey_t);
-extern void *fibheap_replace_key_data (fibheap_t, fibnode_t,
-                                       fibheapkey_t, void *);
-extern void *fibheap_extract_min (fibheap_t);
-extern void *fibheap_min (fibheap_t);
-extern void *fibheap_replace_data (fibheap_t, fibnode_t, void *);
-extern void *fibheap_delete_node (fibheap_t, fibnode_t);
-extern void fibheap_delete (fibheap_t);
-extern fibheap_t fibheap_union (fibheap_t, fibheap_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _FIBHEAP_H_ */
diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
index 1b0d8ae..39ceb3c 100644
--- a/libiberty/Makefile.in
+++ b/libiberty/Makefile.in
@@ -128,7 +128,7 @@ CFILES = alloca.c argv.c asprintf.c atexit.c				\
 	calloc.c choose-temp.c clock.c concat.c cp-demangle.c		\
 	 cp-demint.c cplus-dem.c crc32.c				\
 	d-demangle.c dwarfnames.c dyn-string.c				\
-	fdmatch.c ffs.c fibheap.c filename_cmp.c floatformat.c		\
+	fdmatch.c ffs.c filename_cmp.c floatformat.c		\
 	fnmatch.c fopen_unlocked.c					\
 	getcwd.c getopt.c getopt1.c getpagesize.c getpwd.c getruntime.c	\
          gettimeofday.c                                                 \
@@ -169,7 +169,7 @@ REQUIRED_OFILES =							\
 	./choose-temp.$(objext) ./concat.$(objext)			\
 	./cp-demint.$(objext) ./crc32.$(objext) ./d-demangle.$(objext)	\
 	./dwarfnames.$(objext) ./dyn-string.$(objext)			\
-	./fdmatch.$(objext) ./fibheap.$(objext)				\
+	./fdmatch.$(objext)						\
 	./filename_cmp.$(objext) ./floatformat.$(objext)		\
 	./fnmatch.$(objext) ./fopen_unlocked.$(objext)			\
 	./getopt.$(objext) ./getopt1.$(objext) ./getpwd.$(objext)	\
@@ -230,7 +230,6 @@ INSTALLED_HEADERS =                                                     \
 	$(INCDIR)/ansidecl.h                                            \
 	$(INCDIR)/demangle.h                                            \
 	$(INCDIR)/dyn-string.h                                          \
-	$(INCDIR)/fibheap.h                                             \
 	$(INCDIR)/floatformat.h                                         \
 	$(INCDIR)/hashtab.h                                             \
 	$(INCDIR)/libiberty.h                                           \
@@ -744,16 +743,6 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/ffs.c $(OUTPUT_OPTION)
 
-./fibheap.$(objext): $(srcdir)/fibheap.c config.h $(INCDIR)/ansidecl.h \
-	$(INCDIR)/fibheap.h $(INCDIR)/libiberty.h
-	if [ x"$(PICFLAG)" != x ]; then \
-	  $(COMPILE.c) $(PICFLAG) $(srcdir)/fibheap.c -o pic/$@; \
-	else true; fi
-	if [ x"$(NOASANFLAG)" != x ]; then \
-	  $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/fibheap.c -o noasan/$@; \
-	else true; fi
-	$(COMPILE.c) $(srcdir)/fibheap.c $(OUTPUT_OPTION)
-
 ./filename_cmp.$(objext): $(srcdir)/filename_cmp.c config.h $(INCDIR)/ansidecl.h \
 	$(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
 	$(INCDIR)/safe-ctype.h
diff --git a/libiberty/fibheap.c b/libiberty/fibheap.c
deleted file mode 100644
index a37ee4e..0000000
--- a/libiberty/fibheap.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/* A Fibonacci heap datatype.
-   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
-   Contributed by Daniel Berlin (dan@cgsoftware.com).
-   
-This file is part of GNU CC.
-   
-GNU CC 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 2, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street - Fifth Floor,
-Boston, MA 02110-1301, USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#include "libiberty.h"
-#include "fibheap.h"
-
-
-#define FIBHEAPKEY_MIN	LONG_MIN
-
-static void fibheap_ins_root (fibheap_t, fibnode_t);
-static void fibheap_rem_root (fibheap_t, fibnode_t);
-static void fibheap_consolidate (fibheap_t);
-static void fibheap_link (fibheap_t, fibnode_t, fibnode_t);
-static void fibheap_cut (fibheap_t, fibnode_t, fibnode_t);
-static void fibheap_cascading_cut (fibheap_t, fibnode_t);
-static fibnode_t fibheap_extr_min_node (fibheap_t);
-static int fibheap_compare (fibheap_t, fibnode_t, fibnode_t);
-static int fibheap_comp_data (fibheap_t, fibheapkey_t, void *, fibnode_t);
-static fibnode_t fibnode_new (void);
-static void fibnode_insert_after (fibnode_t, fibnode_t);
-#define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b)
-static fibnode_t fibnode_remove (fibnode_t);
-
-\f
-/* Create a new fibonacci heap.  */
-fibheap_t
-fibheap_new (void)
-{
-  return (fibheap_t) xcalloc (1, sizeof (struct fibheap));
-}
-
-/* Create a new fibonacci heap node.  */
-static fibnode_t
-fibnode_new (void)
-{
-  fibnode_t node;
-
-  node = (fibnode_t) xcalloc (1, sizeof *node);
-  node->left = node;
-  node->right = node;
-
-  return node;
-}
-
-static inline int
-fibheap_compare (fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a, fibnode_t b)
-{
-  if (a->key < b->key)
-    return -1;
-  if (a->key > b->key)
-    return 1;
-  return 0;
-}
-
-static inline int
-fibheap_comp_data (fibheap_t heap, fibheapkey_t key, void *data, fibnode_t b)
-{
-  struct fibnode a;
-
-  a.key = key;
-  a.data = data;
-
-  return fibheap_compare (heap, &a, b);
-}
-
-/* Insert DATA, with priority KEY, into HEAP.  */
-fibnode_t
-fibheap_insert (fibheap_t heap, fibheapkey_t key, void *data)
-{
-  fibnode_t node;
-
-  /* Create the new node.  */
-  node = fibnode_new ();
-
-  /* Set the node's data.  */
-  node->data = data;
-  node->key = key;
-
-  /* Insert it into the root list.  */
-  fibheap_ins_root (heap, node);
-
-  /* If their was no minimum, or this key is less than the min,
-     it's the new min.  */
-  if (heap->min == NULL || node->key < heap->min->key)
-    heap->min = node;
-
-  heap->nodes++;
-
-  return node;
-}
-
-/* Return the data of the minimum node (if we know it).  */
-void *
-fibheap_min (fibheap_t heap)
-{
-  /* If there is no min, we can't easily return it.  */
-  if (heap->min == NULL)
-    return NULL;
-  return heap->min->data;
-}
-
-/* Return the key of the minimum node (if we know it).  */
-fibheapkey_t
-fibheap_min_key (fibheap_t heap)
-{
-  /* If there is no min, we can't easily return it.  */
-  if (heap->min == NULL)
-    return 0;
-  return heap->min->key;
-}
-
-/* Union HEAPA and HEAPB into a new heap.  */
-fibheap_t
-fibheap_union (fibheap_t heapa, fibheap_t heapb)
-{
-  fibnode_t a_root, b_root, temp;
-
-  /* If one of the heaps is empty, the union is just the other heap.  */
-  if ((a_root = heapa->root) == NULL)
-    {
-      free (heapa);
-      return heapb;
-    }
-  if ((b_root = heapb->root) == NULL)
-    {
-      free (heapb);
-      return heapa;
-    }
-
-  /* Merge them to the next nodes on the opposite chain.  */
-  a_root->left->right = b_root;
-  b_root->left->right = a_root;
-  temp = a_root->left;
-  a_root->left = b_root->left;
-  b_root->left = temp;
-  heapa->nodes += heapb->nodes;
-
-  /* And set the new minimum, if it's changed.  */
-  if (fibheap_compare (heapa, heapb->min, heapa->min) < 0)
-    heapa->min = heapb->min;
-
-  free (heapb);
-  return heapa;
-}
-
-/* Extract the data of the minimum node from HEAP.  */
-void *
-fibheap_extract_min (fibheap_t heap)
-{
-  fibnode_t z;
-  void *ret = NULL;
-
-  /* If we don't have a min set, it means we have no nodes.  */
-  if (heap->min != NULL)
-    {
-      /* Otherwise, extract the min node, free the node, and return the
-         node's data.  */
-      z = fibheap_extr_min_node (heap);
-      ret = z->data;
-      free (z);
-    }
-
-  return ret;
-}
-
-/* Replace both the KEY and the DATA associated with NODE.  */
-void *
-fibheap_replace_key_data (fibheap_t heap, fibnode_t node,
-                          fibheapkey_t key, void *data)
-{
-  void *odata;
-  fibheapkey_t okey;
-  fibnode_t y;
-
-  /* If we wanted to, we could actually do a real increase by redeleting and
-     inserting. However, this would require O (log n) time. So just bail out
-     for now.  */
-  if (fibheap_comp_data (heap, key, data, node) > 0)
-    return NULL;
-
-  odata = node->data;
-  okey = node->key;
-  node->data = data;
-  node->key = key;
-  y = node->parent;
-
-  /* Short-circuit if the key is the same, as we then don't have to
-     do anything.  Except if we're trying to force the new node to
-     be the new minimum for delete.  */
-  if (okey == key && okey != FIBHEAPKEY_MIN)
-    return odata;
-
-  /* These two compares are specifically <= 0 to make sure that in the case
-     of equality, a node we replaced the data on, becomes the new min.  This
-     is needed so that delete's call to extractmin gets the right node.  */
-  if (y != NULL && fibheap_compare (heap, node, y) <= 0)
-    {
-      fibheap_cut (heap, node, y);
-      fibheap_cascading_cut (heap, y);
-    }
-
-  if (fibheap_compare (heap, node, heap->min) <= 0)
-    heap->min = node;
-
-  return odata;
-}
-
-/* Replace the DATA associated with NODE.  */
-void *
-fibheap_replace_data (fibheap_t heap, fibnode_t node, void *data)
-{
-  return fibheap_replace_key_data (heap, node, node->key, data);
-}
-
-/* Replace the KEY associated with NODE.  */
-fibheapkey_t
-fibheap_replace_key (fibheap_t heap, fibnode_t node, fibheapkey_t key)
-{
-  int okey = node->key;
-  fibheap_replace_key_data (heap, node, key, node->data);
-  return okey;
-}
-
-/* Delete NODE from HEAP.  */
-void *
-fibheap_delete_node (fibheap_t heap, fibnode_t node)
-{
-  void *ret = node->data;
-
-  /* To perform delete, we just make it the min key, and extract.  */
-  fibheap_replace_key (heap, node, FIBHEAPKEY_MIN);
-  if (node != heap->min)
-    {
-      fprintf (stderr, "Can't force minimum on fibheap.\n");
-      abort ();
-    }
-  fibheap_extract_min (heap);
-
-  return ret;
-}
-
-/* Delete HEAP.  */
-void
-fibheap_delete (fibheap_t heap)
-{
-  while (heap->min != NULL)
-    free (fibheap_extr_min_node (heap));
-
-  free (heap);
-}
-
-/* Determine if HEAP is empty.  */
-int
-fibheap_empty (fibheap_t heap)
-{
-  return heap->nodes == 0;
-}
-
-/* Extract the minimum node of the heap.  */
-static fibnode_t
-fibheap_extr_min_node (fibheap_t heap)
-{
-  fibnode_t ret = heap->min;
-  fibnode_t x, y, orig;
-
-  /* Attach the child list of the minimum node to the root list of the heap.
-     If there is no child list, we don't do squat.  */
-  for (x = ret->child, orig = NULL; x != orig && x != NULL; x = y)
-    {
-      if (orig == NULL)
-	orig = x;
-      y = x->right;
-      x->parent = NULL;
-      fibheap_ins_root (heap, x);
-    }
-
-  /* Remove the old root.  */
-  fibheap_rem_root (heap, ret);
-  heap->nodes--;
-
-  /* If we are left with no nodes, then the min is NULL.  */
-  if (heap->nodes == 0)
-    heap->min = NULL;
-  else
-    {
-      /* Otherwise, consolidate to find new minimum, as well as do the reorg
-         work that needs to be done.  */
-      heap->min = ret->right;
-      fibheap_consolidate (heap);
-    }
-
-  return ret;
-}
-
-/* Insert NODE into the root list of HEAP.  */
-static void
-fibheap_ins_root (fibheap_t heap, fibnode_t node)
-{
-  /* If the heap is currently empty, the new node becomes the singleton
-     circular root list.  */
-  if (heap->root == NULL)
-    {
-      heap->root = node;
-      node->left = node;
-      node->right = node;
-      return;
-    }
-
-  /* Otherwise, insert it in the circular root list between the root
-     and it's right node.  */
-  fibnode_insert_after (heap->root, node);
-}
-
-/* Remove NODE from the rootlist of HEAP.  */
-static void
-fibheap_rem_root (fibheap_t heap, fibnode_t node)
-{
-  if (node->left == node)
-    heap->root = NULL;
-  else
-    heap->root = fibnode_remove (node);
-}
-
-/* Consolidate the heap.  */
-static void
-fibheap_consolidate (fibheap_t heap)
-{
-  fibnode_t a[1 + 8 * sizeof (long)];
-  fibnode_t w;
-  fibnode_t y;
-  fibnode_t x;
-  int i;
-  int d;
-  int D;
-
-  D = 1 + 8 * sizeof (long);
-
-  memset (a, 0, sizeof (fibnode_t) * D);
-
-  while ((w = heap->root) != NULL)
-    {
-      x = w;
-      fibheap_rem_root (heap, w);
-      d = x->degree;
-      while (a[d] != NULL)
-	{
-	  y = a[d];
-	  if (fibheap_compare (heap, x, y) > 0)
-	    {
-	      fibnode_t temp;
-	      temp = x;
-	      x = y;
-	      y = temp;
-	    }
-	  fibheap_link (heap, y, x);
-	  a[d] = NULL;
-	  d++;
-	}
-      a[d] = x;
-    }
-  heap->min = NULL;
-  for (i = 0; i < D; i++)
-    if (a[i] != NULL)
-      {
-	fibheap_ins_root (heap, a[i]);
-	if (heap->min == NULL || fibheap_compare (heap, a[i], heap->min) < 0)
-	  heap->min = a[i];
-      }
-}
-
-/* Make NODE a child of PARENT.  */
-static void
-fibheap_link (fibheap_t heap ATTRIBUTE_UNUSED,
-              fibnode_t node, fibnode_t parent)
-{
-  if (parent->child == NULL)
-    parent->child = node;
-  else
-    fibnode_insert_before (parent->child, node);
-  node->parent = parent;
-  parent->degree++;
-  node->mark = 0;
-}
-
-/* Remove NODE from PARENT's child list.  */
-static void
-fibheap_cut (fibheap_t heap, fibnode_t node, fibnode_t parent)
-{
-  fibnode_remove (node);
-  parent->degree--;
-  fibheap_ins_root (heap, node);
-  node->parent = NULL;
-  node->mark = 0;
-}
-
-static void
-fibheap_cascading_cut (fibheap_t heap, fibnode_t y)
-{
-  fibnode_t z;
-
-  while ((z = y->parent) != NULL)
-    {
-      if (y->mark == 0)
-	{
-	  y->mark = 1;
-	  return;
-	}
-      else
-	{
-	  fibheap_cut (heap, y, z);
-	  y = z;
-	}
-    }
-}
-
-static void
-fibnode_insert_after (fibnode_t a, fibnode_t b)
-{
-  if (a == a->right)
-    {
-      a->right = b;
-      a->left = b;
-      b->right = a;
-      b->left = a;
-    }
-  else
-    {
-      b->right = a->right;
-      a->right->left = b;
-      a->right = b;
-      b->left = a;
-    }
-}
-
-static fibnode_t
-fibnode_remove (fibnode_t node)
-{
-  fibnode_t ret;
-
-  if (node == node->left)
-    ret = NULL;
-  else
-    ret = node->left;
-
-  if (node->parent != NULL && node->parent->child == node)
-    node->parent->child = ret;
-
-  node->right->left = node->left;
-  node->left->right = node->right;
-
-  node->parent = NULL;
-  node->left = node;
-  node->right = node;
-
-  return ret;
-}
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/9] New fibonacci heap and sreal enhancement.
@ 2014-11-13 20:39 mliska
  2014-11-13 20:39 ` [PATCH 4/9] tracer ported to new fibonacci_heap data structure mliska
                   ` (8 more replies)
  0 siblings, 9 replies; 38+ messages in thread
From: mliska @ 2014-11-13 20:39 UTC (permalink / raw)
  To: gcc-patches

Hello.

Following patch set introduces new template class for fibonacci heap
that is mainly utilized by IPA inliner. Apart from that, I also enhanced
existing sreal implementation so that it can also handle negative numbers.

I was primary motivated by Honza, because current heap implementation
in ipa-inline.c suffers from round off problems.

I was able to run WPA phase which was by about ~3% slower than current
implementation.

All patches can bootstrap and no regression was seen on x86_64-linux-pc.

I welcome any remarks connected to the patch set.

Thanks,
Martin

(please ignore following ChangeLog diff)
---
 gcc/ChangeLog | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d418c82..7ff6e3b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,4 @@
+
 2014-11-13  Eric Botcazou  <ebotcazou@adacore.com>
 
 	* doc/tm.texi.in (SELECT_CC_MODE): Update example.
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 6/9] fibonacci_heap is used for var-tracking.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
  2014-11-13 20:39 ` [PATCH 4/9] tracer ported to new fibonacci_heap data structure mliska
@ 2014-11-13 20:39 ` mliska
  2014-11-14  4:45   ` Jeff Law
  2014-11-13 20:39 ` [PATCH 7/9] Old libiberty fib_heap removed mliska
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 38+ messages in thread
From: mliska @ 2014-11-13 20:39 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* var-tracking.c (vt_find_locations): New fibonacci_node is used.
---
 gcc/var-tracking.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 302968e..2278815 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -130,6 +130,10 @@
 #include "tm_p.h"
 #include "alias.h"
 #include "rtl-iter.h"
+#include "fibonacci_heap.h"
+
+typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
+typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
 
 /* var-tracking.c assumes that tree code with the same value as VALUE rtx code
    has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
@@ -6961,7 +6965,9 @@ compute_bb_dataflow (basic_block bb)
 static bool
 vt_find_locations (void)
 {
-  fibheap_t worklist, pending, fibheap_swap;
+  bb_heap_t *worklist = new bb_heap_t (LONG_MIN);
+  bb_heap_t *pending = new bb_heap_t (LONG_MIN);
+  bb_heap_t *fibheap_swap = NULL;
   sbitmap visited, in_worklist, in_pending, sbitmap_swap;
   basic_block bb;
   edge e;
@@ -6982,18 +6988,16 @@ vt_find_locations (void)
     bb_order[rc_order[i]] = i;
   free (rc_order);
 
-  worklist = fibheap_new ();
-  pending = fibheap_new ();
   visited = sbitmap_alloc (last_basic_block_for_fn (cfun));
   in_worklist = sbitmap_alloc (last_basic_block_for_fn (cfun));
   in_pending = sbitmap_alloc (last_basic_block_for_fn (cfun));
   bitmap_clear (in_worklist);
 
   FOR_EACH_BB_FN (bb, cfun)
-    fibheap_insert (pending, bb_order[bb->index], bb);
+    pending->insert (bb_order[bb->index], bb);
   bitmap_ones (in_pending);
 
-  while (success && !fibheap_empty (pending))
+  while (success && !pending->empty ())
     {
       fibheap_swap = pending;
       pending = worklist;
@@ -7004,9 +7008,9 @@ vt_find_locations (void)
 
       bitmap_clear (visited);
 
-      while (!fibheap_empty (worklist))
+      while (!worklist->empty ())
 	{
-	  bb = (basic_block) fibheap_extract_min (worklist);
+	  bb = worklist->extract_min ();
 	  bitmap_clear_bit (in_worklist, bb->index);
 	  gcc_assert (!bitmap_bit_p (visited, bb->index));
 	  if (!bitmap_bit_p (visited, bb->index))
@@ -7113,17 +7117,16 @@ vt_find_locations (void)
 			    {
 			      /* Send E->DEST to next round.  */
 			      bitmap_set_bit (in_pending, e->dest->index);
-			      fibheap_insert (pending,
-					      bb_order[e->dest->index],
-					      e->dest);
+			      pending->insert (bb_order[e->dest->index],
+					       e->dest);
 			    }
 			}
 		      else if (!bitmap_bit_p (in_worklist, e->dest->index))
 			{
 			  /* Add E->DEST to current round.  */
 			  bitmap_set_bit (in_worklist, e->dest->index);
-			  fibheap_insert (worklist, bb_order[e->dest->index],
-					  e->dest);
+			  worklist->insert (bb_order[e->dest->index],
+					    e->dest);
 			}
 		    }
 		}
@@ -7136,7 +7139,8 @@ vt_find_locations (void)
 			 oldinsz,
 			 (int)shared_hash_htab (VTI (bb)->out.vars)->size (),
 			 oldoutsz,
-			 (int)worklist->nodes, (int)pending->nodes, htabsz);
+			 (int)worklist->nodes (), (int)pending->nodes (),
+			 htabsz);
 
 	      if (dump_file && (dump_flags & TDF_DETAILS))
 		{
@@ -7154,8 +7158,8 @@ vt_find_locations (void)
       gcc_assert (VTI (bb)->flooded);
 
   free (bb_order);
-  fibheap_delete (worklist);
-  fibheap_delete (pending);
+  delete worklist;
+  delete pending;
   sbitmap_free (visited);
   sbitmap_free (in_worklist);
   sbitmap_free (in_pending);
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
                   ` (4 preceding siblings ...)
  2014-11-13 20:39 ` [PATCH 5/9] bt-load is ported to fibonacci_heap mliska
@ 2014-11-13 20:45 ` mliska
  2014-11-14  4:46   ` Jeff Law
  2014-11-24 19:25   ` H.J. Lu
  2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 38+ messages in thread
From: mliska @ 2014-11-13 20:45 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* ipa-inline.c (edge_badness): long is replaced by sreal
	as fibonacci_heap template type.
	(update_edge_key): Likewise.
	(inline_small_functions): Likewise.
	* sreal.h (inline sreal operator<<): New function added.
	(inline sreal operator>>): Likewise.
---
 gcc/ipa-inline.c | 49 +++++++++++++++++++++++++------------------------
 gcc/sreal.h      | 16 +++++++++++++---
 2 files changed, 38 insertions(+), 27 deletions(-)

diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index aa5d029..e9c3042 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -139,8 +139,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "fibonacci_heap.h"
 
-typedef fibonacci_heap <long, cgraph_edge> edge_heap_t;
-typedef fibonacci_node <long, cgraph_edge> edge_heap_node_t;
+typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t;
+typedef fibonacci_node <sreal, cgraph_edge> edge_heap_node_t;
 
 /* Statistics we collect about inlining algorithm.  */
 static int overall_size;
@@ -909,10 +909,10 @@ relative_time_benefit (struct inline_summary *callee_info,
    metrics may accurately depend on values such as number of inlinable callers
    of the function or function body size.  */
 
-static int
+static sreal
 edge_badness (struct cgraph_edge *edge, bool dump)
 {
-  gcov_type badness;
+  sreal badness;
   int growth, edge_time;
   struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
   struct inline_summary *callee_info = inline_summary (callee);
@@ -949,7 +949,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
     {
       badness = INT_MIN / 2 + growth;
       if (dump)
-	fprintf (dump_file, "      %i: Growth %i <= 0\n", (int) badness,
+	fprintf (dump_file, "      %"PRId64": Growth %d <= 0\n", badness.to_int (),
 		 growth);
     }
 
@@ -991,9 +991,9 @@ edge_badness (struct cgraph_edge *edge, bool dump)
       if (dump)
 	{
 	  fprintf (dump_file,
-		   "      %i (relative %f): profile info. Relative count %f%s"
+		   "      %"PRId64" (relative %f): profile info. Relative count %f%s"
 		   " * Relative benefit %f\n",
-		   (int) badness, (double) badness / INT_MIN,
+		   badness.to_int (), (double) badness.to_int () / INT_MIN,
 		   (double) edge_count / max_count,
 		   edge->count > max_count ? " (capped to max_count)" : "",
 		   relbenefit * 100.0 / RELATIVE_TIME_BENEFIT_RANGE);
@@ -1034,10 +1034,10 @@ edge_badness (struct cgraph_edge *edge, bool dump)
       if (dump)
 	{
 	  fprintf (dump_file,
-		   "      %i: guessed profile. frequency %f,"
+		   "      %"PRId64": guessed profile. frequency %f,"
 		   " benefit %f%%, time w/o inlining %i, time w inlining %i"
 		   " overall growth %i (current) %i (original)\n",
-		   (int) badness, (double)edge->frequency / CGRAPH_FREQ_BASE,
+		   badness.to_int (), (double)edge->frequency / CGRAPH_FREQ_BASE,
 		   relative_time_benefit (callee_info, edge, edge_time) * 100.0
 		   / RELATIVE_TIME_BENEFIT_RANGE, 
 		   (int)compute_uninlined_call_time (callee_info, edge),
@@ -1057,13 +1057,13 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 
       /* Decrease badness if call is nested.  */
       if (badness > 0)
-	badness >>= nest;
+	badness = badness >> nest;
       else
 	{
-	  badness <<= nest;
+	  badness = badness << nest;
 	}
       if (dump)
-	fprintf (dump_file, "      %i: no profile. nest %i\n", (int) badness,
+	fprintf (dump_file, "      %"PRId64": no profile. nest %i\n", badness.to_int (),
 		 nest);
     }
 
@@ -1081,7 +1081,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 static inline void
 update_edge_key (edge_heap_t *heap, struct cgraph_edge *edge)
 {
-  int badness = edge_badness (edge, false);
+  sreal badness = edge_badness (edge, false);
   if (edge->aux)
     {
       edge_heap_node_t *n = (edge_heap_node_t *) edge->aux;
@@ -1096,13 +1096,14 @@ update_edge_key (edge_heap_t *heap, struct cgraph_edge *edge)
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
 	      fprintf (dump_file,
-		       "  decreasing badness %s/%i -> %s/%i, %i to %i\n",
+		       "  decreasing badness %s/%i -> %s/%i, %"PRId64
+		       " to %"PRId64"\n",
 		       xstrdup (edge->caller->name ()),
 		       edge->caller->order,
 		       xstrdup (edge->callee->name ()),
 		       edge->callee->order,
-		       (int)n->get_key (),
-		       badness);
+		       n->get_key ().to_int (),
+		       badness.to_int ());
 	    }
 	  heap->replace_key (n, badness);
 	  gcc_checking_assert (n->get_key () == badness);
@@ -1113,12 +1114,12 @@ update_edge_key (edge_heap_t *heap, struct cgraph_edge *edge)
        if (dump_file && (dump_flags & TDF_DETAILS))
 	 {
 	   fprintf (dump_file,
-		    "  enqueuing call %s/%i -> %s/%i, badness %i\n",
+		    "  enqueuing call %s/%i -> %s/%i, badness %"PRId64"\n",
 		    xstrdup (edge->caller->name ()),
 		    edge->caller->order,
 		    xstrdup (edge->callee->name ()),
 		    edge->callee->order,
-		    badness);
+		    badness.to_int ());
 	 }
       edge->aux = heap->insert (badness, edge);
     }
@@ -1568,7 +1569,7 @@ inline_small_functions (void)
 {
   struct cgraph_node *node;
   struct cgraph_edge *edge;
-  edge_heap_t edge_heap (LONG_MIN);
+  edge_heap_t edge_heap (sreal::min ());
   bitmap updated_nodes = BITMAP_ALLOC (NULL);
   int min_size, max_size;
   auto_vec<cgraph_edge *> new_indirect_edges;
@@ -1687,9 +1688,9 @@ inline_small_functions (void)
     {
       int old_size = overall_size;
       struct cgraph_node *where, *callee;
-      int badness = edge_heap.min_key ();
-      int current_badness;
-      int cached_badness;
+      sreal badness = edge_heap.min_key ();
+      sreal current_badness;
+      sreal cached_badness;
       int growth;
 
       edge = edge_heap.extract_min ();
@@ -1733,13 +1734,13 @@ inline_small_functions (void)
 		   inline_summary (callee)->size);
 	  fprintf (dump_file,
 		   " to be inlined into %s/%i in %s:%i\n"
-		   " Estimated badness is %i, frequency %.2f.\n",
+		   " Estimated badness is %"PRId64", frequency %.2f.\n",
 		   edge->caller->name (), edge->caller->order,
 		   flag_wpa ? "unknown"
 		   : gimple_filename ((const_gimple) edge->call_stmt),
 		   flag_wpa ? -1
 		   : gimple_lineno ((const_gimple) edge->call_stmt),
-		   badness,
+		   badness.to_int (),
 		   edge->frequency / (double)CGRAPH_FREQ_BASE);
 	  if (edge->count)
 	    fprintf (dump_file," Called %"PRId64"x\n",
diff --git a/gcc/sreal.h b/gcc/sreal.h
index bfed3c7..9834ff2 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -118,9 +118,9 @@ private:
   void normalize ();
   void shift_right (int amount);
 
-  uint64_t m_sig;		/* Significant.  */
-  signed int m_exp: 31;		/* Exponent.  */
-  unsigned int m_negative: 1;	/* Negative sign.  */
+  uint64_t m_sig;			/* Significant.  */
+  signed int m_exp: 31;			/* Exponent.  */
+  unsigned int m_negative: 1;		/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
@@ -166,4 +166,14 @@ inline bool operator>= (const sreal &a, const sreal &b)
   return a == b || a > b;
 }
 
+inline sreal operator<< (const sreal &a, int exp)
+{
+  return a.shift (exp);
+}
+
+inline sreal operator>> (const sreal &a, int exp)
+{
+  return a.shift (-exp);
+}
+
 #endif
-- 
2.1.2

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 2/9] New template fibonacci_heap class introduced.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
                   ` (5 preceding siblings ...)
  2014-11-13 20:45 ` [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument mliska
@ 2014-11-13 20:50 ` mliska
  2014-11-13 21:14   ` mliska
                     ` (3 more replies)
  2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
  2014-11-13 23:42 ` [PATCH 1/9] New fibonacci heap and sreal enhancement Jan Hubicka
  8 siblings, 4 replies; 38+ messages in thread
From: mliska @ 2014-11-13 20:50 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* fibonacci_heap.h: New file.
	* ipa-inline.c (update_edge_key): New heap API is used.
	(update_caller_keys): Likewise.
	(update_callee_keys): Likewise.
	(lookup_recursive_calls): Likewise.
	(recursive_inlining): Likewise.
	(add_new_edges_to_heap): Likewise.
	(heap_edge_removal_hook): Likewise.
	(inline_small_functions): Likewise.
---
 gcc/fibonacci_heap.h | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/ipa-inline.c     | 106 +++++----
 2 files changed, 663 insertions(+), 55 deletions(-)
 create mode 100644 gcc/fibonacci_heap.h

diff --git a/gcc/fibonacci_heap.h b/gcc/fibonacci_heap.h
new file mode 100644
index 0000000..548708f
--- /dev/null
+++ b/gcc/fibonacci_heap.h
@@ -0,0 +1,612 @@
+/* Vector API for GNU compiler.
+   Copyright (C) 1998-2014 Free Software Foundation, Inc.
+   Contributed by Daniel Berlin (dan@cgsoftware.com).
+   Re-implemented in C++ by Martin Liska <mliska@suse.cz>
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Fibonacci heaps are somewhat complex, but, there's an article in
+   DDJ that explains them pretty well:
+
+   http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms
+
+   Introduction to algorithms by Corman and Rivest also goes over them.
+
+   The original paper that introduced them is "Fibonacci heaps and their
+   uses in improved network optimization algorithms" by Tarjan and
+   Fredman (JACM 34(3), July 1987).
+
+   Amortized and real worst case time for operations:
+
+   ExtractMin: O(lg n) amortized. O(n) worst case.
+   DecreaseKey: O(1) amortized.  O(lg n) worst case.
+   Insert: O(2) amortized. O(1) actual.
+   Union: O(1) amortized. O(1) actual.  */
+
+#ifndef GCC_FIBONACCI_HEAP_H
+#define GCC_FIBONACCI_HEAP_H
+
+/* Forward definition.  */
+
+template<class K, class V>
+class fibonacci_heap;
+
+/* Fibonacci heap node class.  */
+
+template<class K, class V>
+class fibonacci_node
+{
+  typedef fibonacci_node<K,V> fibonacci_node_t;
+  friend class fibonacci_heap<K,V>;
+
+public:
+  /* Default constructor.  */
+  fibonacci_node (): m_parent (NULL), m_child (NULL), m_left (this),
+    m_right (this), m_degree (0), m_mark (0)
+  {
+  }
+
+  /* Constructor for a node with givek KEY.  */
+  fibonacci_node (K key): m_parent (NULL), m_child (NULL), m_left (this),
+    m_right (this), m_key (key),
+    m_degree (0), m_mark (0)
+  {
+  }
+
+  /* Compare fibonacci node with OTHER node.  */
+  int compare (fibonacci_node_t *other)
+  {
+    if (m_key < other->m_key)
+      return -1;
+    if (m_key > other->m_key)
+      return 1;
+    return 0;
+  }
+
+  /* Compare the node with a given KEY.  */
+  int compare_data (K key)
+  {
+    return fibonacci_node_t (key).compare (this);
+  }
+
+  /* Remove fibonacci heap node.  */
+  fibonacci_node_t *remove ();
+
+  /* Link the node with PARENT.  */
+  void link (fibonacci_node_t *parent);
+
+  /* Return key associated with the node.  */
+  K get_key ()
+  {
+    return m_key;
+  }
+
+  /* Return data associated with the node.  */
+  V *get_data ()
+  {
+    return m_data;
+  }
+
+private:
+  /* Put node B after this node.  */
+  void insert_after (fibonacci_node_t *b);
+
+  /* Insert fibonacci node B after this node.  */
+  void insert_before (fibonacci_node_t *b)
+  {
+    m_left->insert_after (b);
+  }
+
+  /* Parent node.  */
+  fibonacci_node *m_parent;
+  /* Child node.  */
+  fibonacci_node *m_child;
+  /* Left sibling.  */
+  fibonacci_node *m_left;
+  /* Right node.  */
+  fibonacci_node *m_right;
+  /* Key associated with node.  */
+  K m_key;
+  /* Data associated with node.  */
+  V *m_data;
+
+#if defined (__GNUC__) && (!defined (SIZEOF_INT) || SIZEOF_INT < 4)
+  /* Degree of the node.  */
+  __extension__ unsigned long int m_degree : 31;
+  /* Mark of the node.  */
+  __extension__ unsigned long int m_mark : 1;
+#else
+  /* Degree of the node.  */
+  unsigned int m_degree : 31;
+  /* Mark of the node.  */
+  unsigned int m_mark : 1;
+#endif
+};
+
+/* Fibonacci heap class. */
+template<class K, class V>
+class fibonacci_heap
+{
+  typedef fibonacci_node<K,V> fibonacci_node_t;
+  friend class fibonacci_node<K,V>;
+
+public:
+  /* Default constructor.  */
+  fibonacci_heap (K global_min_key): m_nodes (0), m_min (NULL), m_root (NULL),
+    m_global_min_key (global_min_key)
+  {
+  }
+
+  /* Destructor.  */
+  ~fibonacci_heap ()
+  {
+    while (m_min != NULL)
+      delete (extract_minimum_node ());
+  }
+
+  /* Insert new node given by KEY and DATA associated with the key.  */
+  fibonacci_node_t *insert (K key, V *data);
+
+  /* Return true if no entry is present.  */
+  bool empty ()
+  {
+    return m_nodes == 0;
+  }
+
+  /* Return the number of nodes.  */
+  size_t nodes ()
+  {
+    return m_nodes;
+  }
+
+  /* Return minimal key presented in the heap.  */
+  K min_key ()
+  {
+    if (m_min == NULL)
+      gcc_unreachable ();
+
+    return m_min->m_key;
+  }
+
+  /* For given NODE, set new KEY value.  */
+  K replace_key (fibonacci_node_t *node, K key)
+  {
+    K okey = node->m_key;
+    replace_key_data (node, key, node->m_data);
+    return okey;
+  }
+
+  /* For given NODE, set new KEY and DATA value.  */
+  V *replace_key_data (fibonacci_node_t *node, K key, V *data);
+
+  /* Extract minimum node in the heap. */
+  V *extract_min ();
+
+  /* Return value associated with minimum node in the heap.  */
+  V *min ()
+  {
+    if (m_min == NULL)
+      return NULL;
+
+    return m_min->data;
+  }
+
+  /* Replace data associated with NODE and replace it with DATA.  */
+  V *replace_data (fibonacci_node_t *node, V *data)
+  {
+    return replace_key_data (node, node->m_key, data);
+  }
+
+  /* Delete NODE in the heap.  */
+  V *delete_node (fibonacci_node_t *node);
+
+  /* Union the heap with HEAPB.  */
+  fibonacci_heap *union_with (fibonacci_heap *heapb);
+
+private:
+  /* Insert it into the root list.  */
+  void insert_root (fibonacci_node_t *node);
+
+  /* Remove NODE from PARENT's child list.  */
+  void cut (fibonacci_node_t *node, fibonacci_node_t *parent);
+
+  /* Process cut of node Y and do it recursivelly.  */
+  void cascading_cut (fibonacci_node_t *y);
+
+  /* Extract minimum node from the heap.  */
+  fibonacci_node_t * extract_minimum_node ();
+
+  /* Remove root NODE from the heap.  */
+  void remove_root (fibonacci_node_t *node);
+
+  /* Consolidate heap.  */
+  void consolidate ();
+
+  /* Number of nodes.  */
+  size_t m_nodes;
+  /* Minimum node of the heap.  */
+  fibonacci_node_t *m_min;
+  /* Root node of the heap.  */
+  fibonacci_node_t *m_root;
+  /* Global minimum given in the heap construction.  */
+  K m_global_min_key;
+};
+
+/* Remove fibonacci heap node.  */
+
+template<class K, class V>
+fibonacci_node<K,V> *
+fibonacci_node<K,V>::remove ()
+{
+  fibonacci_node<K,V> *ret;
+
+  if (this == m_left)
+    ret = NULL;
+  else
+    ret = m_left;
+
+  if (m_parent != NULL && m_parent->m_child == this)
+    m_parent->m_child = ret;
+
+  m_right->m_left = m_left;
+  m_left->m_right = m_right;
+
+  m_parent = NULL;
+  m_left = this;
+  m_right = this;
+
+  return ret;
+}
+
+/* Link the node with PARENT.  */
+
+template<class K, class V>
+void
+fibonacci_node<K,V>::link (fibonacci_node<K,V> *parent)
+{
+  if (parent->m_child == NULL)
+    parent->m_child = this;
+  else
+    parent->m_child->insert_before (this);
+  m_parent = parent;
+  parent->m_degree++;
+  m_mark = 0;
+}
+
+/* Put node B after this node.  */
+
+template<class K, class V>
+void
+fibonacci_node<K,V>::insert_after (fibonacci_node<K,V> *b)
+{
+  fibonacci_node<K,V> *a = this;
+
+  if (a == a->m_right)
+    {
+      a->m_right = b;
+      a->m_left = b;
+      b->m_right = a;
+      b->m_left = a;
+    }
+  else
+    {
+      b->m_right = a->m_right;
+      a->m_right->m_left = b;
+      a->m_right = b;
+      b->m_left = a;
+    }
+}
+
+/* Insert new node given by KEY and DATA associated with the key.  */
+
+template<class K, class V>
+fibonacci_node<K,V>*
+fibonacci_heap<K,V>::insert (K key, V *data)
+{
+  /* Create the new node.  */
+  fibonacci_node<K,V> *node = new fibonacci_node_t ();
+
+  /* Set the node's data.  */
+  node->m_data = data;
+  node->m_key = key;
+
+  /* Insert it into the root list.  */
+  insert_root (node);
+
+  /* If their was no minimum, or this key is less than the min,
+     it's the new min.  */
+  if (m_min == NULL || node->m_key < m_min->m_key)
+    m_min = node;
+
+  m_nodes++;
+
+  return node;
+}
+
+/* For given NODE, set new KEY and DATA value.  */
+template<class K, class V>
+V*
+fibonacci_heap<K,V>::replace_key_data (fibonacci_node<K,V> *node, K key,
+				       V *data)
+{
+  V *odata;
+  K okey;
+  fibonacci_node<K,V> *y;
+
+  /* If we wanted to, we could actually do a real increase by redeleting and
+     inserting. However, this would require O (log n) time. So just bail out
+     for now.  */
+  if (node->compare_data (key) > 0)
+    return NULL;
+
+  odata = node->m_data;
+  okey = node->m_key;
+  node->m_data = data;
+  node->m_key = key;
+  y = node->m_parent;
+
+  /* Short-circuit if the key is the same, as we then don't have to
+     do anything.  Except if we're trying to force the new node to
+     be the new minimum for delete.  */
+  if (okey == key && okey != m_global_min_key)
+    return odata;
+
+  /* These two compares are specifically <= 0 to make sure that in the case
+     of equality, a node we replaced the data on, becomes the new min.  This
+     is needed so that delete's call to extractmin gets the right node.  */
+  if (y != NULL && node->compare (y) <= 0)
+    {
+      cut (node, y);
+      cascading_cut (y);
+    }
+
+  if (node->compare (m_min) <= 0)
+    m_min = node;
+
+  return odata;
+}
+
+/* Extract minimum node in the heap.  */
+template<class K, class V>
+V*
+fibonacci_heap<K,V>::extract_min ()
+{
+  fibonacci_node<K,V> *z;
+  V *ret = NULL;
+
+  /* If we don't have a min set, it means we have no nodes.  */
+  if (m_min != NULL)
+    {
+      /* Otherwise, extract the min node, free the node, and return the
+       node's data.  */
+      z = extract_minimum_node ();
+      ret = z->m_data;
+      delete (z);
+    }
+
+  return ret;
+}
+
+/* Delete NODE in the heap.  */
+
+template<class K, class V>
+V*
+fibonacci_heap<K,V>::delete_node (fibonacci_node<K,V> *node)
+{
+  V *ret = node->m_data;
+
+  /* To perform delete, we just make it the min key, and extract.  */
+  replace_key (node, m_global_min_key);
+  if (node != m_min)
+    {
+      fprintf (stderr, "Can't force minimum on fibheap.\n");
+      abort ();
+    }
+  extract_min ();
+
+  return ret;
+}
+
+/* Union the heap with HEAPB.  */
+
+template<class K, class V>
+fibonacci_heap<K,V>*
+fibonacci_heap<K,V>::union_with (fibonacci_heap<K,V> *heapb)
+{
+  fibonacci_heap<K,V> *heapa = this;
+
+  fibonacci_node<K,V> *a_root, *b_root, *temp;
+
+  /* If one of the heaps is empty, the union is just the other heap.  */
+  if ((a_root = heapa->m_root) == NULL)
+    {
+      delete (heapa);
+      return heapb;
+    }
+  if ((b_root = heapb->m_root) == NULL)
+    {
+      delete (heapb);
+      return heapa;
+    }
+
+  /* Merge them to the next nodes on the opposite chain.  */
+  a_root->m_left->m_right = b_root;
+  b_root->m_left->m_right = a_root;
+  temp = a_root->m_left;
+  a_root->m_left = b_root->m_left;
+  b_root->m_left = temp;
+  heapa->m_nodes += heapb->m_nodes;
+
+  /* And set the new minimum, if it's changed.  */
+  if (heapb->min->compare (heapa->min) < 0)
+    heapa->m_min = heapb->m_min;
+
+  delete (heapb);
+  return heapa;
+}
+
+/* Insert it into the root list.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::insert_root (fibonacci_node_t *node)
+{
+  /* If the heap is currently empty, the new node becomes the singleton
+     circular root list.  */
+  if (m_root == NULL)
+    {
+      m_root = node;
+      node->m_left = node;
+      node->m_right = node;
+      return;
+    }
+
+  /* Otherwise, insert it in the circular root list between the root
+     and it's right node.  */
+  m_root->insert_after (node);
+}
+
+/* Remove NODE from PARENT's child list.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::cut (fibonacci_node<K,V> *node,
+			  fibonacci_node<K,V> *parent)
+{
+  node->remove ();
+  parent->m_degree--;
+  insert_root (node);
+  node->m_parent = NULL;
+  node->m_mark = 0;
+}
+
+/* Process cut of node Y and do it recursivelly.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::cascading_cut (fibonacci_node<K,V> *y)
+{
+  fibonacci_node<K,V> *z;
+
+  while ((z = y->m_parent) != NULL)
+    {
+      if (y->m_mark == 0)
+	{
+	  y->m_mark = 1;
+	  return;
+	}
+      else
+	{
+	  cut (y, z);
+	  y = z;
+	}
+    }
+}
+
+/* Extract minimum node from the heap.  */
+template<class K, class V>
+fibonacci_node<K,V>*
+fibonacci_heap<K,V>::extract_minimum_node ()
+{
+  fibonacci_node<K,V> *ret = m_min;
+  fibonacci_node<K,V> *x, *y, *orig;
+
+  /* Attach the child list of the minimum node to the root list of the heap.
+     If there is no child list, we don't do squat.  */
+  for (x = ret->m_child, orig = NULL; x != orig && x != NULL; x = y)
+    {
+      if (orig == NULL)
+	orig = x;
+      y = x->m_right;
+      x->m_parent = NULL;
+      insert_root (x);
+    }
+
+  /* Remove the old root.  */
+  remove_root (ret);
+  m_nodes--;
+
+  /* If we are left with no nodes, then the min is NULL.  */
+  if (m_nodes == 0)
+    m_min = NULL;
+  else
+    {
+      /* Otherwise, consolidate to find new minimum, as well as do the reorg
+       work that needs to be done.  */
+      m_min = ret->m_right;
+      consolidate ();
+    }
+
+  return ret;
+}
+
+/* Remove root NODE from the heap.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::remove_root (fibonacci_node<K,V> *node)
+{
+  if (node->m_left == node)
+    m_root = NULL;
+  else
+    m_root = node->remove ();
+}
+
+/* Consolidate heap.  */
+
+template<class K, class V>
+void fibonacci_heap<K,V>::consolidate ()
+{
+  int D = 1 + 8 * sizeof (long);
+  auto_vec<fibonacci_node<K,V> *> a (D);
+  a.safe_grow_cleared (D);
+  fibonacci_node<K,V> *w, *x, *y;
+  int i, d;
+
+  while ((w = m_root) != NULL)
+    {
+      x = w;
+      remove_root (w);
+      d = x->m_degree;
+      while (a[d] != NULL)
+	{
+	  y = a[d];
+	  if (x->compare (y) > 0)
+	    {
+	      /* TODO: swap */
+	      fibonacci_node_t *temp;
+	      temp = x;
+	      x = y;
+	      y = temp;
+	    }
+	  y->link (x);
+	  a[d] = NULL;
+	  d++;
+	}
+      a[d] = x;
+    }
+  m_min = NULL;
+  for (i = 0; i < D; i++)
+    if (a[i] != NULL)
+      {
+	insert_root (a[i]);
+	if (m_min == NULL || a[i]->compare (m_min) < 0)
+	  m_min = a[i];
+      }
+}
+
+#endif  // GCC_FIBONACCI_HEAP_H
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c97815..1ce856f 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -138,6 +138,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "auto-profile.h"
 #include "cilk.h"
 #include "builtins.h"
+#include "fibonacci_heap.h"
+
+typedef fibonacci_heap <long, cgraph_edge> edge_heap_t;
+typedef fibonacci_node <long, cgraph_edge> edge_heap_node_t;
 
 /* Statistics we collect about inlining algorithm.  */
 static int overall_size;
@@ -1076,19 +1080,19 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 
 /* Recompute badness of EDGE and update its key in HEAP if needed.  */
 static inline void
-update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
+update_edge_key (edge_heap_t *heap, struct cgraph_edge *edge)
 {
   int badness = edge_badness (edge, false);
   if (edge->aux)
     {
-      fibnode_t n = (fibnode_t) edge->aux;
-      gcc_checking_assert (n->data == edge);
+      edge_heap_node_t *n = (edge_heap_node_t *) edge->aux;
+      gcc_checking_assert (n->get_data () == edge);
 
-      /* fibheap_replace_key only decrease the keys.
+      /* fibonacci_heap::replace_key only decrease the keys.
 	 When we increase the key we do not update heap
 	 and instead re-insert the element once it becomes
 	 a minimum of heap.  */
-      if (badness < n->key)
+      if (badness < n->get_key ())
 	{
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
@@ -1098,11 +1102,11 @@ update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
 		       edge->caller->order,
 		       xstrdup (edge->callee->name ()),
 		       edge->callee->order,
-		       (int)n->key,
+		       (int)n->get_key (),
 		       badness);
 	    }
-	  fibheap_replace_key (heap, n, badness);
-	  gcc_checking_assert (n->key == badness);
+	  heap->replace_key (n, badness);
+	  gcc_checking_assert (n->get_key () == badness);
 	}
     }
   else
@@ -1117,7 +1121,7 @@ update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
 		    edge->callee->order,
 		    badness);
 	 }
-      edge->aux = fibheap_insert (heap, badness, edge);
+      edge->aux = heap->insert (badness, edge);
     }
 }
 
@@ -1180,7 +1184,7 @@ reset_edge_caches (struct cgraph_node *node)
    it is inlinable. Otherwise check all edges.  */
 
 static void
-update_caller_keys (fibheap_t heap, struct cgraph_node *node,
+update_caller_keys (edge_heap_t *heap, struct cgraph_node *node,
 		    bitmap updated_nodes,
 		    struct cgraph_edge *check_inlinablity_for)
 {
@@ -1211,7 +1215,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
 	    else if (edge->aux)
 	      {
 		report_inline_failed_reason (edge);
-		fibheap_delete_node (heap, (fibnode_t) edge->aux);
+		heap->delete_node ((edge_heap_node_t *) edge->aux);
 		edge->aux = NULL;
 	      }
 	  }
@@ -1226,7 +1230,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
    created edges into heap.  */
 
 static void
-update_callee_keys (fibheap_t heap, struct cgraph_node *node,
+update_callee_keys (edge_heap_t *heap, struct cgraph_node *node,
 		    bitmap updated_nodes)
 {
   struct cgraph_edge *e = node->callees;
@@ -1255,7 +1259,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
 	    else if (e->aux)
 	      {
 		report_inline_failed_reason (e);
-		fibheap_delete_node (heap, (fibnode_t) e->aux);
+		heap->delete_node ((edge_heap_node_t *) e->aux);
 		e->aux = NULL;
 	      }
 	  }
@@ -1280,7 +1284,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
 
 static void
 lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
-			fibheap_t heap)
+			edge_heap_t *heap)
 {
   struct cgraph_edge *e;
   enum availability avail;
@@ -1292,10 +1296,9 @@ lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
       {
 	/* When profile feedback is available, prioritize by expected number
 	   of calls.  */
-        fibheap_insert (heap,
-			!max_count ? -e->frequency
-		        : -(e->count / ((max_count + (1<<24) - 1) / (1<<24))),
-		        e);
+        heap->insert (!max_count ? -e->frequency
+		      : -(e->count / ((max_count + (1<<24) - 1) / (1<<24))),
+		      e);
       }
   for (e = where->callees; e; e = e->next_callee)
     if (!e->inline_failed)
@@ -1312,7 +1315,7 @@ recursive_inlining (struct cgraph_edge *edge,
 		    vec<cgraph_edge *> *new_edges)
 {
   int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
-  fibheap_t heap;
+  edge_heap_t heap (LONG_MIN);
   struct cgraph_node *node;
   struct cgraph_edge *e;
   struct cgraph_node *master_clone = NULL, *next;
@@ -1329,13 +1332,9 @@ recursive_inlining (struct cgraph_edge *edge,
   /* Make sure that function is small enough to be considered for inlining.  */
   if (estimate_size_after_inlining (node, edge)  >= limit)
     return false;
-  heap = fibheap_new ();
-  lookup_recursive_calls (node, node, heap);
-  if (fibheap_empty (heap))
-    {
-      fibheap_delete (heap);
-      return false;
-    }
+  lookup_recursive_calls (node, node, &heap);
+  if (heap.empty ())
+    return false;
 
   if (dump_file)
     fprintf (dump_file,
@@ -1343,10 +1342,9 @@ recursive_inlining (struct cgraph_edge *edge,
 	     node->name ());
 
   /* Do the inlining and update list of recursive call during process.  */
-  while (!fibheap_empty (heap))
+  while (!heap.empty ())
     {
-      struct cgraph_edge *curr
-	= (struct cgraph_edge *) fibheap_extract_min (heap);
+      struct cgraph_edge *curr = heap.extract_min ();
       struct cgraph_node *cnode, *dest = curr->callee;
 
       if (!can_inline_edge_p (curr, true))
@@ -1408,13 +1406,12 @@ recursive_inlining (struct cgraph_edge *edge,
 	}
 
       inline_call (curr, false, new_edges, &overall_size, true);
-      lookup_recursive_calls (node, curr->callee, heap);
+      lookup_recursive_calls (node, curr->callee, &heap);
       n++;
     }
 
-  if (!fibheap_empty (heap) && dump_file)
+  if (!heap.empty () && dump_file)
     fprintf (dump_file, "    Recursive inlining growth limit met.\n");
-  fibheap_delete (heap);
 
   if (!master_clone)
     return false;
@@ -1459,7 +1456,7 @@ compute_max_insns (int insns)
 /* Compute badness of all edges in NEW_EDGES and add them to the HEAP.  */
 
 static void
-add_new_edges_to_heap (fibheap_t heap, vec<cgraph_edge *> new_edges)
+add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
 {
   while (new_edges.length () > 0)
     {
@@ -1469,7 +1466,7 @@ add_new_edges_to_heap (fibheap_t heap, vec<cgraph_edge *> new_edges)
       if (edge->inline_failed
 	  && can_inline_edge_p (edge, true)
 	  && want_inline_small_function_p (edge, true))
-        edge->aux = fibheap_insert (heap, edge_badness (edge, false), edge);
+        edge->aux = heap->insert (edge_badness (edge, false), edge);
     }
 }
 
@@ -1482,7 +1479,7 @@ heap_edge_removal_hook (struct cgraph_edge *e, void *data)
     reset_node_growth_cache (e->callee);
   if (e->aux)
     {
-      fibheap_delete_node ((fibheap_t)data, (fibnode_t)e->aux);
+      ((edge_heap_t *)data)->delete_node ((edge_heap_node_t *)e->aux);
       e->aux = NULL;
     }
 }
@@ -1540,7 +1537,7 @@ speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining)
    See if we can remove speculation.  */
 
 static void
-resolve_noninline_speculation (fibheap_t edge_heap, struct cgraph_edge *edge)
+resolve_noninline_speculation (edge_heap_t *edge_heap, struct cgraph_edge *edge)
 {
   if (edge->speculative && !speculation_useful_p (edge, false))
     {
@@ -1572,7 +1569,7 @@ inline_small_functions (void)
 {
   struct cgraph_node *node;
   struct cgraph_edge *edge;
-  fibheap_t edge_heap = fibheap_new ();
+  edge_heap_t edge_heap (LONG_MIN);
   bitmap updated_nodes = BITMAP_ALLOC (NULL);
   int min_size, max_size;
   auto_vec<cgraph_edge *> new_indirect_edges;
@@ -1583,7 +1580,7 @@ inline_small_functions (void)
     new_indirect_edges.create (8);
 
   edge_removal_hook_holder
-    = symtab->add_edge_removal_hook (&heap_edge_removal_hook, edge_heap);
+    = symtab->add_edge_removal_hook (&heap_edge_removal_hook, &edge_heap);
 
   /* Compute overall unit size and other global parameters used by badness
      metrics.  */
@@ -1662,7 +1659,7 @@ inline_small_functions (void)
 	      && edge->inline_failed)
 	    {
 	      gcc_assert (!edge->aux);
-	      update_edge_key (edge_heap, edge);
+	      update_edge_key (&edge_heap, edge);
 	    }
 	  if (edge->speculative && !speculation_useful_p (edge, edge->aux != NULL))
 	    {
@@ -1677,7 +1674,7 @@ inline_small_functions (void)
 	  inline_update_overall_summary (where);
           reset_node_growth_cache (where);
 	  reset_edge_caches (where);
-          update_caller_keys (edge_heap, where,
+          update_caller_keys (&edge_heap, where,
 			      updated_nodes, NULL);
           bitmap_clear (updated_nodes);
 	}
@@ -1687,16 +1684,16 @@ inline_small_functions (void)
 	      || !max_count
 	      || (profile_info && flag_branch_probabilities));
 
-  while (!fibheap_empty (edge_heap))
+  while (!edge_heap.empty ())
     {
       int old_size = overall_size;
       struct cgraph_node *where, *callee;
-      int badness = fibheap_min_key (edge_heap);
+      int badness = edge_heap.min_key ();
       int current_badness;
       int cached_badness;
       int growth;
 
-      edge = (struct cgraph_edge *) fibheap_extract_min (edge_heap);
+      edge = edge_heap.extract_min ();
       gcc_assert (edge->aux);
       edge->aux = NULL;
       if (!edge->inline_failed || !edge->callee->analyzed)
@@ -1717,13 +1714,13 @@ inline_small_functions (void)
       gcc_assert (current_badness >= badness);
       if (current_badness != badness)
 	{
-	  edge->aux = fibheap_insert (edge_heap, current_badness, edge);
+	  edge->aux = edge_heap.insert (current_badness, edge);
 	  continue;
 	}
 
       if (!can_inline_edge_p (edge, true))
 	{
-	  resolve_noninline_speculation (edge_heap, edge);
+	  resolve_noninline_speculation (&edge_heap, edge);
 	  continue;
 	}
       
@@ -1757,13 +1754,13 @@ inline_small_functions (void)
 	{
 	  edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT;
 	  report_inline_failed_reason (edge);
-	  resolve_noninline_speculation (edge_heap, edge);
+	  resolve_noninline_speculation (&edge_heap, edge);
 	  continue;
 	}
 
       if (!want_inline_small_function_p (edge, true))
 	{
-	  resolve_noninline_speculation (edge_heap, edge);
+	  resolve_noninline_speculation (&edge_heap, edge);
 	  continue;
 	}
 
@@ -1781,15 +1778,15 @@ inline_small_functions (void)
 				   ? &new_indirect_edges : NULL))
 	    {
 	      edge->inline_failed = CIF_RECURSIVE_INLINING;
-	      resolve_noninline_speculation (edge_heap, edge);
+	      resolve_noninline_speculation (&edge_heap, edge);
 	      continue;
 	    }
 	  reset_edge_caches (where);
 	  /* Recursive inliner inlines all recursive calls of the function
 	     at once. Consequently we need to update all callee keys.  */
 	  if (flag_indirect_inlining)
-	    add_new_edges_to_heap (edge_heap, new_indirect_edges);
-          update_callee_keys (edge_heap, where, updated_nodes);
+	    add_new_edges_to_heap (&edge_heap, new_indirect_edges);
+          update_callee_keys (&edge_heap, where, updated_nodes);
 	  bitmap_clear (updated_nodes);
 	}
       else
@@ -1817,7 +1814,7 @@ inline_small_functions (void)
 	      edge->inline_failed
 		= (DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl)
 		   ? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
-	      resolve_noninline_speculation (edge_heap, edge);
+	      resolve_noninline_speculation (&edge_heap, edge);
 	      continue;
 	    }
 	  else if (depth && dump_file)
@@ -1826,12 +1823,12 @@ inline_small_functions (void)
 	  gcc_checking_assert (!callee->global.inlined_to);
 	  inline_call (edge, true, &new_indirect_edges, &overall_size, true);
 	  if (flag_indirect_inlining)
-	    add_new_edges_to_heap (edge_heap, new_indirect_edges);
+	    add_new_edges_to_heap (&edge_heap, new_indirect_edges);
 
 	  reset_edge_caches (edge->callee);
           reset_node_growth_cache (callee);
 
-	  update_callee_keys (edge_heap, where, updated_nodes);
+	  update_callee_keys (&edge_heap, where, updated_nodes);
 	}
       where = edge->caller;
       if (where->global.inlined_to)
@@ -1843,7 +1840,7 @@ inline_small_functions (void)
 	 inlined into (since it's body size changed) and for the functions
 	 called by function we inlined (since number of it inlinable callers
 	 might change).  */
-      update_caller_keys (edge_heap, where, updated_nodes, NULL);
+      update_caller_keys (&edge_heap, where, updated_nodes, NULL);
       bitmap_clear (updated_nodes);
 
       if (dump_file)
@@ -1867,7 +1864,6 @@ inline_small_functions (void)
     }
 
   free_growth_caches ();
-  fibheap_delete (edge_heap);
   if (dump_file)
     fprintf (dump_file,
 	     "Unit growth for small function inlining: %i->%i (%i%%)\n",
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
                   ` (6 preceding siblings ...)
  2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
@ 2014-11-13 20:51 ` mliska
  2014-11-13 21:31   ` mliska
                     ` (3 more replies)
  2014-11-13 23:42 ` [PATCH 1/9] New fibonacci heap and sreal enhancement Jan Hubicka
  8 siblings, 4 replies; 38+ messages in thread
From: mliska @ 2014-11-13 20:51 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* predict.c (propagate_freq): More elegant sreal API is used.
	(estimate_bb_frequencies): New static constants defined by sreal
	replace precomputed ones.
	* sreal.c (sreal::normalize): New function.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	* sreal.h: Definition of new functions added.
---
 gcc/predict.c | 30 +++++++++++-------------
 gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
 gcc/sreal.h   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 126 insertions(+), 35 deletions(-)

diff --git a/gcc/predict.c b/gcc/predict.c
index 0215e91..0f640f5 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
 		   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
-static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
+static sreal real_almost_one, real_br_prob_base,
 	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
 static void combine_predictions_for_insn (rtx_insn *, basic_block);
@@ -2528,13 +2528,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 	bb->count = bb->frequency = 0;
     }
 
-  BLOCK_INFO (head)->frequency = real_one;
+  BLOCK_INFO (head)->frequency = sreal::one ();
   last = head;
   for (bb = head; bb; bb = nextbb)
     {
       edge_iterator ei;
-      sreal cyclic_probability = real_zero;
-      sreal frequency = real_zero;
+      sreal cyclic_probability = sreal::zero ();
+      sreal frequency = sreal::zero ();
 
       nextbb = BLOCK_INFO (bb)->next;
       BLOCK_INFO (bb)->next = NULL;
@@ -2559,13 +2559,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 				  * BLOCK_INFO (e->src)->frequency /
 				  REG_BR_PROB_BASE);  */
 
-		sreal tmp (e->probability, 0);
+		sreal tmp = e->probability;
 		tmp *= BLOCK_INFO (e->src)->frequency;
 		tmp *= real_inv_br_prob_base;
 		frequency += tmp;
 	      }
 
-	  if (cyclic_probability == real_zero)
+	  if (cyclic_probability == sreal::zero ())
 	    {
 	      BLOCK_INFO (bb)->frequency = frequency;
 	    }
@@ -2577,7 +2577,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	      /* BLOCK_INFO (bb)->frequency = frequency
 					      / (1 - cyclic_probability) */
 
-	      cyclic_probability = real_one - cyclic_probability;
+	      cyclic_probability = sreal::one () - cyclic_probability;
 	      BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
 	    }
 	}
@@ -2591,7 +2591,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	     = ((e->probability * BLOCK_INFO (bb)->frequency)
 	     / REG_BR_PROB_BASE); */
 
-	  sreal tmp (e->probability, 0);
+	  sreal tmp = e->probability;
 	  tmp *= BLOCK_INFO (bb)->frequency;
 	  EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
 	}
@@ -2873,13 +2873,11 @@ estimate_bb_frequencies (bool force)
       if (!real_values_initialized)
         {
 	  real_values_initialized = 1;
-	  real_zero = sreal (0, 0);
-	  real_one = sreal (1, 0);
-	  real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
-	  real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
+	  real_br_prob_base = REG_BR_PROB_BASE;
+	  real_bb_freq_max = BB_FREQ_MAX;
 	  real_one_half = sreal (1, -1);
-	  real_inv_br_prob_base = real_one / real_br_prob_base;
-	  real_almost_one = real_one - real_inv_br_prob_base;
+	  real_inv_br_prob_base = sreal::one () / real_br_prob_base;
+	  real_almost_one = sreal::one () - real_inv_br_prob_base;
 	}
 
       mark_dfs_back_edges ();
@@ -2897,7 +2895,7 @@ estimate_bb_frequencies (bool force)
 
 	  FOR_EACH_EDGE (e, ei, bb->succs)
 	    {
-	      EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
+	      EDGE_INFO (e)->back_edge_prob = e->probability;
 	      EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
 	    }
 	}
@@ -2906,7 +2904,7 @@ estimate_bb_frequencies (bool force)
          to outermost to examine frequencies for back edges.  */
       estimate_loops ();
 
-      freq_max = real_zero;
+      freq_max = sreal::zero ();
       FOR_EACH_BB_FN (bb, cfun)
 	if (freq_max < BLOCK_INFO (bb)->frequency)
 	  freq_max = BLOCK_INFO (bb)->frequency;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 3f5456a..89b9c4d 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -1,4 +1,4 @@
-/* Simple data type for positive real numbers for the GNU compiler.
+/* Simple data type for real numbers for the GNU compiler.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* This library supports positive real numbers and 0;
+/* This library supports real numbers;
    inf and nan are NOT supported.
    It is written to be simple and fast.
 
@@ -102,6 +102,7 @@ sreal::normalize ()
 {
   if (m_sig == 0)
     {
+      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
   else if (m_sig < SREAL_MIN_SIG)
@@ -153,15 +154,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
+  int64_t sign = m_negative ? -1 : 1;
+
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
-    return INTTYPE_MAXIMUM (int64_t);
+    return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return m_sig << m_exp;
+    return sign * (m_sig << m_exp);
   if (m_exp < 0)
-    return m_sig >> -m_exp;
-  return m_sig;
+    return sign * (m_sig >> -m_exp);
+  return sign * m_sig;
 }
 
 /* Return *this + other.  */
@@ -169,9 +172,19 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
+  const sreal *a_p = this, *b_p = &other, *bb;
+
+  if (m_negative && !other.m_negative)
+    return other + *a_p;
+
+  if (!m_negative && other.m_negative)
+    return *a_p - -other;
+
+  gcc_assert (m_negative == other.m_negative);
+
   int dexp;
   sreal tmp, r;
-const sreal *a_p = this, *b_p = &other, *bb;
+  r.m_negative = a_p->m_negative;
 
   if (*a_p < *b_p)
     {
@@ -211,10 +224,30 @@ sreal::operator- (const sreal &other) const
   int dexp;
   sreal tmp, r;
   const sreal *bb;
+  const sreal *a_p = this;
+
+  /* -a - b => -a + (-b).  */
+  if (m_negative && !other.m_negative)
+    return *a_p + -other;
 
-  gcc_assert (*this >= other);
+  /* a - (-b) => a + b.  */
+  if (!m_negative && other.m_negative)
+    return *a_p + -other;
+
+  gcc_assert (m_negative == other.m_negative);
+
+  /* We want to substract a smaller number from bigger
+    for nonegative numbers.  */
+  if (!m_negative && *this < other)
+    return -(other - *this);
+
+  /* Example: -2 - (-3) => 3 - 2 */
+  if (m_negative && *this > other)
+    return -other - -(*this);
 
   dexp = m_exp - other.m_exp;
+
+  r.m_negative = m_negative;
   r.m_exp = m_exp;
   if (dexp > SREAL_BITS)
     {
@@ -240,7 +273,7 @@ sreal::operator- (const sreal &other) const
 sreal
 sreal::operator* (const sreal &other) const
 {
-sreal r;
+  sreal r;
   if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
@@ -252,6 +285,8 @@ sreal r;
       r.m_exp = m_exp + other.m_exp;
       r.normalize ();
     }
+
+  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -261,9 +296,10 @@ sreal
 sreal::operator/ (const sreal &other) const
 {
   gcc_assert (other.m_sig != 0);
-sreal r;
+  sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
+  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 461e28b..bfed3c7 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -1,4 +1,4 @@
-/* Definitions for simple data type for positive real numbers.
+/* Definitions for simple data type for real numbers.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
 #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
-#define SREAL_MAX_EXP (INT_MAX / 4)
+#define SREAL_MAX_EXP (INT_MAX / 8)
 
 #define SREAL_BITS SREAL_PART_BITS
 
@@ -34,10 +34,21 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1) {}
+  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
 
   /* Construct a sreal.  */
-  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
+  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  {
+    m_negative = sig < 0;
+
+    // TODO: speed up
+    if (sig < 0)
+      sig = -sig;
+
+    m_sig = (uint64_t) sig;
+
+    normalize ();
+  }
 
   void dump (FILE *) const;
   int64_t to_int () const;
@@ -49,13 +60,58 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    return m_exp < other.m_exp
+    if (m_negative != other.m_negative)
+      return m_negative > other.m_negative;
+
+    bool r = m_exp < other.m_exp
       || (m_exp == other.m_exp && m_sig < other.m_sig);
+
+    return m_negative ? !r : r;
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig;
+    return m_exp == other.m_exp && m_sig == other.m_sig
+		    && m_negative == other.m_negative;
+  }
+
+  sreal operator- () const
+  {
+    if (m_sig == 0)
+      return *this;
+
+    sreal tmp = *this;
+    tmp.m_negative = !tmp.m_negative;
+
+    return tmp;
+  }
+
+  sreal shift (int sig) const
+  {
+    sreal tmp = *this;
+    tmp.m_sig += sig;
+
+    return tmp;
+  }
+
+  /* Return zero constant.  */
+  inline static sreal zero ()
+  {
+    static const sreal zero = sreal (0);
+    return zero;
+  }
+
+  /* Return one constant.  */
+  inline static sreal one ()
+  {
+    static const sreal one = sreal (1);
+    return one;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal min ()
+  {
+    return sreal (LONG_MIN, 0);
   }
 
 private:
@@ -63,7 +119,8 @@ private:
   void shift_right (int amount);
 
   uint64_t m_sig;		/* Significant.  */
-  signed int m_exp;			/* Exponent.  */
+  signed int m_exp: 31;		/* Exponent.  */
+  unsigned int m_negative: 1;	/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
@@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
 
 inline sreal &operator-= (sreal &a, const sreal &b)
 {
-return a = a - b;
+  return a = a - b;
 }
 
 inline sreal &operator/= (sreal &a, const sreal &b)
 {
-return a = a / b;
+  return a = a / b;
 }
 
 inline sreal &operator*= (sreal &a, const sreal &b)
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 2/9] New template fibonacci_heap class introduced.
  2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
@ 2014-11-13 21:14   ` mliska
  2014-11-13 23:42   ` Jan Hubicka
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 38+ messages in thread
From: mliska @ 2014-11-13 21:14 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* fibonacci_heap.h: New file.
	* ipa-inline.c (update_edge_key): New heap API is used.
	(update_caller_keys): Likewise.
	(update_callee_keys): Likewise.
	(lookup_recursive_calls): Likewise.
	(recursive_inlining): Likewise.
	(add_new_edges_to_heap): Likewise.
	(heap_edge_removal_hook): Likewise.
	(inline_small_functions): Likewise.
---
 gcc/fibonacci_heap.h | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/ipa-inline.c     | 106 +++++----
 2 files changed, 663 insertions(+), 55 deletions(-)
 create mode 100644 gcc/fibonacci_heap.h

diff --git a/gcc/fibonacci_heap.h b/gcc/fibonacci_heap.h
new file mode 100644
index 0000000..548708f
--- /dev/null
+++ b/gcc/fibonacci_heap.h
@@ -0,0 +1,612 @@
+/* Vector API for GNU compiler.
+   Copyright (C) 1998-2014 Free Software Foundation, Inc.
+   Contributed by Daniel Berlin (dan@cgsoftware.com).
+   Re-implemented in C++ by Martin Liska <mliska@suse.cz>
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Fibonacci heaps are somewhat complex, but, there's an article in
+   DDJ that explains them pretty well:
+
+   http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms
+
+   Introduction to algorithms by Corman and Rivest also goes over them.
+
+   The original paper that introduced them is "Fibonacci heaps and their
+   uses in improved network optimization algorithms" by Tarjan and
+   Fredman (JACM 34(3), July 1987).
+
+   Amortized and real worst case time for operations:
+
+   ExtractMin: O(lg n) amortized. O(n) worst case.
+   DecreaseKey: O(1) amortized.  O(lg n) worst case.
+   Insert: O(2) amortized. O(1) actual.
+   Union: O(1) amortized. O(1) actual.  */
+
+#ifndef GCC_FIBONACCI_HEAP_H
+#define GCC_FIBONACCI_HEAP_H
+
+/* Forward definition.  */
+
+template<class K, class V>
+class fibonacci_heap;
+
+/* Fibonacci heap node class.  */
+
+template<class K, class V>
+class fibonacci_node
+{
+  typedef fibonacci_node<K,V> fibonacci_node_t;
+  friend class fibonacci_heap<K,V>;
+
+public:
+  /* Default constructor.  */
+  fibonacci_node (): m_parent (NULL), m_child (NULL), m_left (this),
+    m_right (this), m_degree (0), m_mark (0)
+  {
+  }
+
+  /* Constructor for a node with givek KEY.  */
+  fibonacci_node (K key): m_parent (NULL), m_child (NULL), m_left (this),
+    m_right (this), m_key (key),
+    m_degree (0), m_mark (0)
+  {
+  }
+
+  /* Compare fibonacci node with OTHER node.  */
+  int compare (fibonacci_node_t *other)
+  {
+    if (m_key < other->m_key)
+      return -1;
+    if (m_key > other->m_key)
+      return 1;
+    return 0;
+  }
+
+  /* Compare the node with a given KEY.  */
+  int compare_data (K key)
+  {
+    return fibonacci_node_t (key).compare (this);
+  }
+
+  /* Remove fibonacci heap node.  */
+  fibonacci_node_t *remove ();
+
+  /* Link the node with PARENT.  */
+  void link (fibonacci_node_t *parent);
+
+  /* Return key associated with the node.  */
+  K get_key ()
+  {
+    return m_key;
+  }
+
+  /* Return data associated with the node.  */
+  V *get_data ()
+  {
+    return m_data;
+  }
+
+private:
+  /* Put node B after this node.  */
+  void insert_after (fibonacci_node_t *b);
+
+  /* Insert fibonacci node B after this node.  */
+  void insert_before (fibonacci_node_t *b)
+  {
+    m_left->insert_after (b);
+  }
+
+  /* Parent node.  */
+  fibonacci_node *m_parent;
+  /* Child node.  */
+  fibonacci_node *m_child;
+  /* Left sibling.  */
+  fibonacci_node *m_left;
+  /* Right node.  */
+  fibonacci_node *m_right;
+  /* Key associated with node.  */
+  K m_key;
+  /* Data associated with node.  */
+  V *m_data;
+
+#if defined (__GNUC__) && (!defined (SIZEOF_INT) || SIZEOF_INT < 4)
+  /* Degree of the node.  */
+  __extension__ unsigned long int m_degree : 31;
+  /* Mark of the node.  */
+  __extension__ unsigned long int m_mark : 1;
+#else
+  /* Degree of the node.  */
+  unsigned int m_degree : 31;
+  /* Mark of the node.  */
+  unsigned int m_mark : 1;
+#endif
+};
+
+/* Fibonacci heap class. */
+template<class K, class V>
+class fibonacci_heap
+{
+  typedef fibonacci_node<K,V> fibonacci_node_t;
+  friend class fibonacci_node<K,V>;
+
+public:
+  /* Default constructor.  */
+  fibonacci_heap (K global_min_key): m_nodes (0), m_min (NULL), m_root (NULL),
+    m_global_min_key (global_min_key)
+  {
+  }
+
+  /* Destructor.  */
+  ~fibonacci_heap ()
+  {
+    while (m_min != NULL)
+      delete (extract_minimum_node ());
+  }
+
+  /* Insert new node given by KEY and DATA associated with the key.  */
+  fibonacci_node_t *insert (K key, V *data);
+
+  /* Return true if no entry is present.  */
+  bool empty ()
+  {
+    return m_nodes == 0;
+  }
+
+  /* Return the number of nodes.  */
+  size_t nodes ()
+  {
+    return m_nodes;
+  }
+
+  /* Return minimal key presented in the heap.  */
+  K min_key ()
+  {
+    if (m_min == NULL)
+      gcc_unreachable ();
+
+    return m_min->m_key;
+  }
+
+  /* For given NODE, set new KEY value.  */
+  K replace_key (fibonacci_node_t *node, K key)
+  {
+    K okey = node->m_key;
+    replace_key_data (node, key, node->m_data);
+    return okey;
+  }
+
+  /* For given NODE, set new KEY and DATA value.  */
+  V *replace_key_data (fibonacci_node_t *node, K key, V *data);
+
+  /* Extract minimum node in the heap. */
+  V *extract_min ();
+
+  /* Return value associated with minimum node in the heap.  */
+  V *min ()
+  {
+    if (m_min == NULL)
+      return NULL;
+
+    return m_min->data;
+  }
+
+  /* Replace data associated with NODE and replace it with DATA.  */
+  V *replace_data (fibonacci_node_t *node, V *data)
+  {
+    return replace_key_data (node, node->m_key, data);
+  }
+
+  /* Delete NODE in the heap.  */
+  V *delete_node (fibonacci_node_t *node);
+
+  /* Union the heap with HEAPB.  */
+  fibonacci_heap *union_with (fibonacci_heap *heapb);
+
+private:
+  /* Insert it into the root list.  */
+  void insert_root (fibonacci_node_t *node);
+
+  /* Remove NODE from PARENT's child list.  */
+  void cut (fibonacci_node_t *node, fibonacci_node_t *parent);
+
+  /* Process cut of node Y and do it recursivelly.  */
+  void cascading_cut (fibonacci_node_t *y);
+
+  /* Extract minimum node from the heap.  */
+  fibonacci_node_t * extract_minimum_node ();
+
+  /* Remove root NODE from the heap.  */
+  void remove_root (fibonacci_node_t *node);
+
+  /* Consolidate heap.  */
+  void consolidate ();
+
+  /* Number of nodes.  */
+  size_t m_nodes;
+  /* Minimum node of the heap.  */
+  fibonacci_node_t *m_min;
+  /* Root node of the heap.  */
+  fibonacci_node_t *m_root;
+  /* Global minimum given in the heap construction.  */
+  K m_global_min_key;
+};
+
+/* Remove fibonacci heap node.  */
+
+template<class K, class V>
+fibonacci_node<K,V> *
+fibonacci_node<K,V>::remove ()
+{
+  fibonacci_node<K,V> *ret;
+
+  if (this == m_left)
+    ret = NULL;
+  else
+    ret = m_left;
+
+  if (m_parent != NULL && m_parent->m_child == this)
+    m_parent->m_child = ret;
+
+  m_right->m_left = m_left;
+  m_left->m_right = m_right;
+
+  m_parent = NULL;
+  m_left = this;
+  m_right = this;
+
+  return ret;
+}
+
+/* Link the node with PARENT.  */
+
+template<class K, class V>
+void
+fibonacci_node<K,V>::link (fibonacci_node<K,V> *parent)
+{
+  if (parent->m_child == NULL)
+    parent->m_child = this;
+  else
+    parent->m_child->insert_before (this);
+  m_parent = parent;
+  parent->m_degree++;
+  m_mark = 0;
+}
+
+/* Put node B after this node.  */
+
+template<class K, class V>
+void
+fibonacci_node<K,V>::insert_after (fibonacci_node<K,V> *b)
+{
+  fibonacci_node<K,V> *a = this;
+
+  if (a == a->m_right)
+    {
+      a->m_right = b;
+      a->m_left = b;
+      b->m_right = a;
+      b->m_left = a;
+    }
+  else
+    {
+      b->m_right = a->m_right;
+      a->m_right->m_left = b;
+      a->m_right = b;
+      b->m_left = a;
+    }
+}
+
+/* Insert new node given by KEY and DATA associated with the key.  */
+
+template<class K, class V>
+fibonacci_node<K,V>*
+fibonacci_heap<K,V>::insert (K key, V *data)
+{
+  /* Create the new node.  */
+  fibonacci_node<K,V> *node = new fibonacci_node_t ();
+
+  /* Set the node's data.  */
+  node->m_data = data;
+  node->m_key = key;
+
+  /* Insert it into the root list.  */
+  insert_root (node);
+
+  /* If their was no minimum, or this key is less than the min,
+     it's the new min.  */
+  if (m_min == NULL || node->m_key < m_min->m_key)
+    m_min = node;
+
+  m_nodes++;
+
+  return node;
+}
+
+/* For given NODE, set new KEY and DATA value.  */
+template<class K, class V>
+V*
+fibonacci_heap<K,V>::replace_key_data (fibonacci_node<K,V> *node, K key,
+				       V *data)
+{
+  V *odata;
+  K okey;
+  fibonacci_node<K,V> *y;
+
+  /* If we wanted to, we could actually do a real increase by redeleting and
+     inserting. However, this would require O (log n) time. So just bail out
+     for now.  */
+  if (node->compare_data (key) > 0)
+    return NULL;
+
+  odata = node->m_data;
+  okey = node->m_key;
+  node->m_data = data;
+  node->m_key = key;
+  y = node->m_parent;
+
+  /* Short-circuit if the key is the same, as we then don't have to
+     do anything.  Except if we're trying to force the new node to
+     be the new minimum for delete.  */
+  if (okey == key && okey != m_global_min_key)
+    return odata;
+
+  /* These two compares are specifically <= 0 to make sure that in the case
+     of equality, a node we replaced the data on, becomes the new min.  This
+     is needed so that delete's call to extractmin gets the right node.  */
+  if (y != NULL && node->compare (y) <= 0)
+    {
+      cut (node, y);
+      cascading_cut (y);
+    }
+
+  if (node->compare (m_min) <= 0)
+    m_min = node;
+
+  return odata;
+}
+
+/* Extract minimum node in the heap.  */
+template<class K, class V>
+V*
+fibonacci_heap<K,V>::extract_min ()
+{
+  fibonacci_node<K,V> *z;
+  V *ret = NULL;
+
+  /* If we don't have a min set, it means we have no nodes.  */
+  if (m_min != NULL)
+    {
+      /* Otherwise, extract the min node, free the node, and return the
+       node's data.  */
+      z = extract_minimum_node ();
+      ret = z->m_data;
+      delete (z);
+    }
+
+  return ret;
+}
+
+/* Delete NODE in the heap.  */
+
+template<class K, class V>
+V*
+fibonacci_heap<K,V>::delete_node (fibonacci_node<K,V> *node)
+{
+  V *ret = node->m_data;
+
+  /* To perform delete, we just make it the min key, and extract.  */
+  replace_key (node, m_global_min_key);
+  if (node != m_min)
+    {
+      fprintf (stderr, "Can't force minimum on fibheap.\n");
+      abort ();
+    }
+  extract_min ();
+
+  return ret;
+}
+
+/* Union the heap with HEAPB.  */
+
+template<class K, class V>
+fibonacci_heap<K,V>*
+fibonacci_heap<K,V>::union_with (fibonacci_heap<K,V> *heapb)
+{
+  fibonacci_heap<K,V> *heapa = this;
+
+  fibonacci_node<K,V> *a_root, *b_root, *temp;
+
+  /* If one of the heaps is empty, the union is just the other heap.  */
+  if ((a_root = heapa->m_root) == NULL)
+    {
+      delete (heapa);
+      return heapb;
+    }
+  if ((b_root = heapb->m_root) == NULL)
+    {
+      delete (heapb);
+      return heapa;
+    }
+
+  /* Merge them to the next nodes on the opposite chain.  */
+  a_root->m_left->m_right = b_root;
+  b_root->m_left->m_right = a_root;
+  temp = a_root->m_left;
+  a_root->m_left = b_root->m_left;
+  b_root->m_left = temp;
+  heapa->m_nodes += heapb->m_nodes;
+
+  /* And set the new minimum, if it's changed.  */
+  if (heapb->min->compare (heapa->min) < 0)
+    heapa->m_min = heapb->m_min;
+
+  delete (heapb);
+  return heapa;
+}
+
+/* Insert it into the root list.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::insert_root (fibonacci_node_t *node)
+{
+  /* If the heap is currently empty, the new node becomes the singleton
+     circular root list.  */
+  if (m_root == NULL)
+    {
+      m_root = node;
+      node->m_left = node;
+      node->m_right = node;
+      return;
+    }
+
+  /* Otherwise, insert it in the circular root list between the root
+     and it's right node.  */
+  m_root->insert_after (node);
+}
+
+/* Remove NODE from PARENT's child list.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::cut (fibonacci_node<K,V> *node,
+			  fibonacci_node<K,V> *parent)
+{
+  node->remove ();
+  parent->m_degree--;
+  insert_root (node);
+  node->m_parent = NULL;
+  node->m_mark = 0;
+}
+
+/* Process cut of node Y and do it recursivelly.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::cascading_cut (fibonacci_node<K,V> *y)
+{
+  fibonacci_node<K,V> *z;
+
+  while ((z = y->m_parent) != NULL)
+    {
+      if (y->m_mark == 0)
+	{
+	  y->m_mark = 1;
+	  return;
+	}
+      else
+	{
+	  cut (y, z);
+	  y = z;
+	}
+    }
+}
+
+/* Extract minimum node from the heap.  */
+template<class K, class V>
+fibonacci_node<K,V>*
+fibonacci_heap<K,V>::extract_minimum_node ()
+{
+  fibonacci_node<K,V> *ret = m_min;
+  fibonacci_node<K,V> *x, *y, *orig;
+
+  /* Attach the child list of the minimum node to the root list of the heap.
+     If there is no child list, we don't do squat.  */
+  for (x = ret->m_child, orig = NULL; x != orig && x != NULL; x = y)
+    {
+      if (orig == NULL)
+	orig = x;
+      y = x->m_right;
+      x->m_parent = NULL;
+      insert_root (x);
+    }
+
+  /* Remove the old root.  */
+  remove_root (ret);
+  m_nodes--;
+
+  /* If we are left with no nodes, then the min is NULL.  */
+  if (m_nodes == 0)
+    m_min = NULL;
+  else
+    {
+      /* Otherwise, consolidate to find new minimum, as well as do the reorg
+       work that needs to be done.  */
+      m_min = ret->m_right;
+      consolidate ();
+    }
+
+  return ret;
+}
+
+/* Remove root NODE from the heap.  */
+
+template<class K, class V>
+void
+fibonacci_heap<K,V>::remove_root (fibonacci_node<K,V> *node)
+{
+  if (node->m_left == node)
+    m_root = NULL;
+  else
+    m_root = node->remove ();
+}
+
+/* Consolidate heap.  */
+
+template<class K, class V>
+void fibonacci_heap<K,V>::consolidate ()
+{
+  int D = 1 + 8 * sizeof (long);
+  auto_vec<fibonacci_node<K,V> *> a (D);
+  a.safe_grow_cleared (D);
+  fibonacci_node<K,V> *w, *x, *y;
+  int i, d;
+
+  while ((w = m_root) != NULL)
+    {
+      x = w;
+      remove_root (w);
+      d = x->m_degree;
+      while (a[d] != NULL)
+	{
+	  y = a[d];
+	  if (x->compare (y) > 0)
+	    {
+	      /* TODO: swap */
+	      fibonacci_node_t *temp;
+	      temp = x;
+	      x = y;
+	      y = temp;
+	    }
+	  y->link (x);
+	  a[d] = NULL;
+	  d++;
+	}
+      a[d] = x;
+    }
+  m_min = NULL;
+  for (i = 0; i < D; i++)
+    if (a[i] != NULL)
+      {
+	insert_root (a[i]);
+	if (m_min == NULL || a[i]->compare (m_min) < 0)
+	  m_min = a[i];
+      }
+}
+
+#endif  // GCC_FIBONACCI_HEAP_H
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5c97815..1ce856f 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -138,6 +138,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "auto-profile.h"
 #include "cilk.h"
 #include "builtins.h"
+#include "fibonacci_heap.h"
+
+typedef fibonacci_heap <long, cgraph_edge> edge_heap_t;
+typedef fibonacci_node <long, cgraph_edge> edge_heap_node_t;
 
 /* Statistics we collect about inlining algorithm.  */
 static int overall_size;
@@ -1076,19 +1080,19 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 
 /* Recompute badness of EDGE and update its key in HEAP if needed.  */
 static inline void
-update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
+update_edge_key (edge_heap_t *heap, struct cgraph_edge *edge)
 {
   int badness = edge_badness (edge, false);
   if (edge->aux)
     {
-      fibnode_t n = (fibnode_t) edge->aux;
-      gcc_checking_assert (n->data == edge);
+      edge_heap_node_t *n = (edge_heap_node_t *) edge->aux;
+      gcc_checking_assert (n->get_data () == edge);
 
-      /* fibheap_replace_key only decrease the keys.
+      /* fibonacci_heap::replace_key only decrease the keys.
 	 When we increase the key we do not update heap
 	 and instead re-insert the element once it becomes
 	 a minimum of heap.  */
-      if (badness < n->key)
+      if (badness < n->get_key ())
 	{
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
@@ -1098,11 +1102,11 @@ update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
 		       edge->caller->order,
 		       xstrdup (edge->callee->name ()),
 		       edge->callee->order,
-		       (int)n->key,
+		       (int)n->get_key (),
 		       badness);
 	    }
-	  fibheap_replace_key (heap, n, badness);
-	  gcc_checking_assert (n->key == badness);
+	  heap->replace_key (n, badness);
+	  gcc_checking_assert (n->get_key () == badness);
 	}
     }
   else
@@ -1117,7 +1121,7 @@ update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
 		    edge->callee->order,
 		    badness);
 	 }
-      edge->aux = fibheap_insert (heap, badness, edge);
+      edge->aux = heap->insert (badness, edge);
     }
 }
 
@@ -1180,7 +1184,7 @@ reset_edge_caches (struct cgraph_node *node)
    it is inlinable. Otherwise check all edges.  */
 
 static void
-update_caller_keys (fibheap_t heap, struct cgraph_node *node,
+update_caller_keys (edge_heap_t *heap, struct cgraph_node *node,
 		    bitmap updated_nodes,
 		    struct cgraph_edge *check_inlinablity_for)
 {
@@ -1211,7 +1215,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
 	    else if (edge->aux)
 	      {
 		report_inline_failed_reason (edge);
-		fibheap_delete_node (heap, (fibnode_t) edge->aux);
+		heap->delete_node ((edge_heap_node_t *) edge->aux);
 		edge->aux = NULL;
 	      }
 	  }
@@ -1226,7 +1230,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
    created edges into heap.  */
 
 static void
-update_callee_keys (fibheap_t heap, struct cgraph_node *node,
+update_callee_keys (edge_heap_t *heap, struct cgraph_node *node,
 		    bitmap updated_nodes)
 {
   struct cgraph_edge *e = node->callees;
@@ -1255,7 +1259,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
 	    else if (e->aux)
 	      {
 		report_inline_failed_reason (e);
-		fibheap_delete_node (heap, (fibnode_t) e->aux);
+		heap->delete_node ((edge_heap_node_t *) e->aux);
 		e->aux = NULL;
 	      }
 	  }
@@ -1280,7 +1284,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
 
 static void
 lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
-			fibheap_t heap)
+			edge_heap_t *heap)
 {
   struct cgraph_edge *e;
   enum availability avail;
@@ -1292,10 +1296,9 @@ lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
       {
 	/* When profile feedback is available, prioritize by expected number
 	   of calls.  */
-        fibheap_insert (heap,
-			!max_count ? -e->frequency
-		        : -(e->count / ((max_count + (1<<24) - 1) / (1<<24))),
-		        e);
+        heap->insert (!max_count ? -e->frequency
+		      : -(e->count / ((max_count + (1<<24) - 1) / (1<<24))),
+		      e);
       }
   for (e = where->callees; e; e = e->next_callee)
     if (!e->inline_failed)
@@ -1312,7 +1315,7 @@ recursive_inlining (struct cgraph_edge *edge,
 		    vec<cgraph_edge *> *new_edges)
 {
   int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
-  fibheap_t heap;
+  edge_heap_t heap (LONG_MIN);
   struct cgraph_node *node;
   struct cgraph_edge *e;
   struct cgraph_node *master_clone = NULL, *next;
@@ -1329,13 +1332,9 @@ recursive_inlining (struct cgraph_edge *edge,
   /* Make sure that function is small enough to be considered for inlining.  */
   if (estimate_size_after_inlining (node, edge)  >= limit)
     return false;
-  heap = fibheap_new ();
-  lookup_recursive_calls (node, node, heap);
-  if (fibheap_empty (heap))
-    {
-      fibheap_delete (heap);
-      return false;
-    }
+  lookup_recursive_calls (node, node, &heap);
+  if (heap.empty ())
+    return false;
 
   if (dump_file)
     fprintf (dump_file,
@@ -1343,10 +1342,9 @@ recursive_inlining (struct cgraph_edge *edge,
 	     node->name ());
 
   /* Do the inlining and update list of recursive call during process.  */
-  while (!fibheap_empty (heap))
+  while (!heap.empty ())
     {
-      struct cgraph_edge *curr
-	= (struct cgraph_edge *) fibheap_extract_min (heap);
+      struct cgraph_edge *curr = heap.extract_min ();
       struct cgraph_node *cnode, *dest = curr->callee;
 
       if (!can_inline_edge_p (curr, true))
@@ -1408,13 +1406,12 @@ recursive_inlining (struct cgraph_edge *edge,
 	}
 
       inline_call (curr, false, new_edges, &overall_size, true);
-      lookup_recursive_calls (node, curr->callee, heap);
+      lookup_recursive_calls (node, curr->callee, &heap);
       n++;
     }
 
-  if (!fibheap_empty (heap) && dump_file)
+  if (!heap.empty () && dump_file)
     fprintf (dump_file, "    Recursive inlining growth limit met.\n");
-  fibheap_delete (heap);
 
   if (!master_clone)
     return false;
@@ -1459,7 +1456,7 @@ compute_max_insns (int insns)
 /* Compute badness of all edges in NEW_EDGES and add them to the HEAP.  */
 
 static void
-add_new_edges_to_heap (fibheap_t heap, vec<cgraph_edge *> new_edges)
+add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
 {
   while (new_edges.length () > 0)
     {
@@ -1469,7 +1466,7 @@ add_new_edges_to_heap (fibheap_t heap, vec<cgraph_edge *> new_edges)
       if (edge->inline_failed
 	  && can_inline_edge_p (edge, true)
 	  && want_inline_small_function_p (edge, true))
-        edge->aux = fibheap_insert (heap, edge_badness (edge, false), edge);
+        edge->aux = heap->insert (edge_badness (edge, false), edge);
     }
 }
 
@@ -1482,7 +1479,7 @@ heap_edge_removal_hook (struct cgraph_edge *e, void *data)
     reset_node_growth_cache (e->callee);
   if (e->aux)
     {
-      fibheap_delete_node ((fibheap_t)data, (fibnode_t)e->aux);
+      ((edge_heap_t *)data)->delete_node ((edge_heap_node_t *)e->aux);
       e->aux = NULL;
     }
 }
@@ -1540,7 +1537,7 @@ speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining)
    See if we can remove speculation.  */
 
 static void
-resolve_noninline_speculation (fibheap_t edge_heap, struct cgraph_edge *edge)
+resolve_noninline_speculation (edge_heap_t *edge_heap, struct cgraph_edge *edge)
 {
   if (edge->speculative && !speculation_useful_p (edge, false))
     {
@@ -1572,7 +1569,7 @@ inline_small_functions (void)
 {
   struct cgraph_node *node;
   struct cgraph_edge *edge;
-  fibheap_t edge_heap = fibheap_new ();
+  edge_heap_t edge_heap (LONG_MIN);
   bitmap updated_nodes = BITMAP_ALLOC (NULL);
   int min_size, max_size;
   auto_vec<cgraph_edge *> new_indirect_edges;
@@ -1583,7 +1580,7 @@ inline_small_functions (void)
     new_indirect_edges.create (8);
 
   edge_removal_hook_holder
-    = symtab->add_edge_removal_hook (&heap_edge_removal_hook, edge_heap);
+    = symtab->add_edge_removal_hook (&heap_edge_removal_hook, &edge_heap);
 
   /* Compute overall unit size and other global parameters used by badness
      metrics.  */
@@ -1662,7 +1659,7 @@ inline_small_functions (void)
 	      && edge->inline_failed)
 	    {
 	      gcc_assert (!edge->aux);
-	      update_edge_key (edge_heap, edge);
+	      update_edge_key (&edge_heap, edge);
 	    }
 	  if (edge->speculative && !speculation_useful_p (edge, edge->aux != NULL))
 	    {
@@ -1677,7 +1674,7 @@ inline_small_functions (void)
 	  inline_update_overall_summary (where);
           reset_node_growth_cache (where);
 	  reset_edge_caches (where);
-          update_caller_keys (edge_heap, where,
+          update_caller_keys (&edge_heap, where,
 			      updated_nodes, NULL);
           bitmap_clear (updated_nodes);
 	}
@@ -1687,16 +1684,16 @@ inline_small_functions (void)
 	      || !max_count
 	      || (profile_info && flag_branch_probabilities));
 
-  while (!fibheap_empty (edge_heap))
+  while (!edge_heap.empty ())
     {
       int old_size = overall_size;
       struct cgraph_node *where, *callee;
-      int badness = fibheap_min_key (edge_heap);
+      int badness = edge_heap.min_key ();
       int current_badness;
       int cached_badness;
       int growth;
 
-      edge = (struct cgraph_edge *) fibheap_extract_min (edge_heap);
+      edge = edge_heap.extract_min ();
       gcc_assert (edge->aux);
       edge->aux = NULL;
       if (!edge->inline_failed || !edge->callee->analyzed)
@@ -1717,13 +1714,13 @@ inline_small_functions (void)
       gcc_assert (current_badness >= badness);
       if (current_badness != badness)
 	{
-	  edge->aux = fibheap_insert (edge_heap, current_badness, edge);
+	  edge->aux = edge_heap.insert (current_badness, edge);
 	  continue;
 	}
 
       if (!can_inline_edge_p (edge, true))
 	{
-	  resolve_noninline_speculation (edge_heap, edge);
+	  resolve_noninline_speculation (&edge_heap, edge);
 	  continue;
 	}
       
@@ -1757,13 +1754,13 @@ inline_small_functions (void)
 	{
 	  edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT;
 	  report_inline_failed_reason (edge);
-	  resolve_noninline_speculation (edge_heap, edge);
+	  resolve_noninline_speculation (&edge_heap, edge);
 	  continue;
 	}
 
       if (!want_inline_small_function_p (edge, true))
 	{
-	  resolve_noninline_speculation (edge_heap, edge);
+	  resolve_noninline_speculation (&edge_heap, edge);
 	  continue;
 	}
 
@@ -1781,15 +1778,15 @@ inline_small_functions (void)
 				   ? &new_indirect_edges : NULL))
 	    {
 	      edge->inline_failed = CIF_RECURSIVE_INLINING;
-	      resolve_noninline_speculation (edge_heap, edge);
+	      resolve_noninline_speculation (&edge_heap, edge);
 	      continue;
 	    }
 	  reset_edge_caches (where);
 	  /* Recursive inliner inlines all recursive calls of the function
 	     at once. Consequently we need to update all callee keys.  */
 	  if (flag_indirect_inlining)
-	    add_new_edges_to_heap (edge_heap, new_indirect_edges);
-          update_callee_keys (edge_heap, where, updated_nodes);
+	    add_new_edges_to_heap (&edge_heap, new_indirect_edges);
+          update_callee_keys (&edge_heap, where, updated_nodes);
 	  bitmap_clear (updated_nodes);
 	}
       else
@@ -1817,7 +1814,7 @@ inline_small_functions (void)
 	      edge->inline_failed
 		= (DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl)
 		   ? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
-	      resolve_noninline_speculation (edge_heap, edge);
+	      resolve_noninline_speculation (&edge_heap, edge);
 	      continue;
 	    }
 	  else if (depth && dump_file)
@@ -1826,12 +1823,12 @@ inline_small_functions (void)
 	  gcc_checking_assert (!callee->global.inlined_to);
 	  inline_call (edge, true, &new_indirect_edges, &overall_size, true);
 	  if (flag_indirect_inlining)
-	    add_new_edges_to_heap (edge_heap, new_indirect_edges);
+	    add_new_edges_to_heap (&edge_heap, new_indirect_edges);
 
 	  reset_edge_caches (edge->callee);
           reset_node_growth_cache (callee);
 
-	  update_callee_keys (edge_heap, where, updated_nodes);
+	  update_callee_keys (&edge_heap, where, updated_nodes);
 	}
       where = edge->caller;
       if (where->global.inlined_to)
@@ -1843,7 +1840,7 @@ inline_small_functions (void)
 	 inlined into (since it's body size changed) and for the functions
 	 called by function we inlined (since number of it inlinable callers
 	 might change).  */
-      update_caller_keys (edge_heap, where, updated_nodes, NULL);
+      update_caller_keys (&edge_heap, where, updated_nodes, NULL);
       bitmap_clear (updated_nodes);
 
       if (dump_file)
@@ -1867,7 +1864,6 @@ inline_small_functions (void)
     }
 
   free_growth_caches ();
-  fibheap_delete (edge_heap);
   if (dump_file)
     fprintf (dump_file,
 	     "Unit growth for small function inlining: %i->%i (%i%%)\n",
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
@ 2014-11-13 21:31   ` mliska
  2014-11-13 23:44   ` Jan Hubicka
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 38+ messages in thread
From: mliska @ 2014-11-13 21:31 UTC (permalink / raw)
  To: gcc-patches

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* predict.c (propagate_freq): More elegant sreal API is used.
	(estimate_bb_frequencies): New static constants defined by sreal
	replace precomputed ones.
	* sreal.c (sreal::normalize): New function.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	* sreal.h: Definition of new functions added.
---
 gcc/predict.c | 30 +++++++++++-------------
 gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
 gcc/sreal.h   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 126 insertions(+), 35 deletions(-)

diff --git a/gcc/predict.c b/gcc/predict.c
index 0215e91..0f640f5 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
 		   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
-static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
+static sreal real_almost_one, real_br_prob_base,
 	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
 static void combine_predictions_for_insn (rtx_insn *, basic_block);
@@ -2528,13 +2528,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 	bb->count = bb->frequency = 0;
     }
 
-  BLOCK_INFO (head)->frequency = real_one;
+  BLOCK_INFO (head)->frequency = sreal::one ();
   last = head;
   for (bb = head; bb; bb = nextbb)
     {
       edge_iterator ei;
-      sreal cyclic_probability = real_zero;
-      sreal frequency = real_zero;
+      sreal cyclic_probability = sreal::zero ();
+      sreal frequency = sreal::zero ();
 
       nextbb = BLOCK_INFO (bb)->next;
       BLOCK_INFO (bb)->next = NULL;
@@ -2559,13 +2559,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 				  * BLOCK_INFO (e->src)->frequency /
 				  REG_BR_PROB_BASE);  */
 
-		sreal tmp (e->probability, 0);
+		sreal tmp = e->probability;
 		tmp *= BLOCK_INFO (e->src)->frequency;
 		tmp *= real_inv_br_prob_base;
 		frequency += tmp;
 	      }
 
-	  if (cyclic_probability == real_zero)
+	  if (cyclic_probability == sreal::zero ())
 	    {
 	      BLOCK_INFO (bb)->frequency = frequency;
 	    }
@@ -2577,7 +2577,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	      /* BLOCK_INFO (bb)->frequency = frequency
 					      / (1 - cyclic_probability) */
 
-	      cyclic_probability = real_one - cyclic_probability;
+	      cyclic_probability = sreal::one () - cyclic_probability;
 	      BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
 	    }
 	}
@@ -2591,7 +2591,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	     = ((e->probability * BLOCK_INFO (bb)->frequency)
 	     / REG_BR_PROB_BASE); */
 
-	  sreal tmp (e->probability, 0);
+	  sreal tmp = e->probability;
 	  tmp *= BLOCK_INFO (bb)->frequency;
 	  EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
 	}
@@ -2873,13 +2873,11 @@ estimate_bb_frequencies (bool force)
       if (!real_values_initialized)
         {
 	  real_values_initialized = 1;
-	  real_zero = sreal (0, 0);
-	  real_one = sreal (1, 0);
-	  real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
-	  real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
+	  real_br_prob_base = REG_BR_PROB_BASE;
+	  real_bb_freq_max = BB_FREQ_MAX;
 	  real_one_half = sreal (1, -1);
-	  real_inv_br_prob_base = real_one / real_br_prob_base;
-	  real_almost_one = real_one - real_inv_br_prob_base;
+	  real_inv_br_prob_base = sreal::one () / real_br_prob_base;
+	  real_almost_one = sreal::one () - real_inv_br_prob_base;
 	}
 
       mark_dfs_back_edges ();
@@ -2897,7 +2895,7 @@ estimate_bb_frequencies (bool force)
 
 	  FOR_EACH_EDGE (e, ei, bb->succs)
 	    {
-	      EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
+	      EDGE_INFO (e)->back_edge_prob = e->probability;
 	      EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
 	    }
 	}
@@ -2906,7 +2904,7 @@ estimate_bb_frequencies (bool force)
          to outermost to examine frequencies for back edges.  */
       estimate_loops ();
 
-      freq_max = real_zero;
+      freq_max = sreal::zero ();
       FOR_EACH_BB_FN (bb, cfun)
 	if (freq_max < BLOCK_INFO (bb)->frequency)
 	  freq_max = BLOCK_INFO (bb)->frequency;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 3f5456a..89b9c4d 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -1,4 +1,4 @@
-/* Simple data type for positive real numbers for the GNU compiler.
+/* Simple data type for real numbers for the GNU compiler.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* This library supports positive real numbers and 0;
+/* This library supports real numbers;
    inf and nan are NOT supported.
    It is written to be simple and fast.
 
@@ -102,6 +102,7 @@ sreal::normalize ()
 {
   if (m_sig == 0)
     {
+      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
   else if (m_sig < SREAL_MIN_SIG)
@@ -153,15 +154,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
+  int64_t sign = m_negative ? -1 : 1;
+
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
-    return INTTYPE_MAXIMUM (int64_t);
+    return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return m_sig << m_exp;
+    return sign * (m_sig << m_exp);
   if (m_exp < 0)
-    return m_sig >> -m_exp;
-  return m_sig;
+    return sign * (m_sig >> -m_exp);
+  return sign * m_sig;
 }
 
 /* Return *this + other.  */
@@ -169,9 +172,19 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
+  const sreal *a_p = this, *b_p = &other, *bb;
+
+  if (m_negative && !other.m_negative)
+    return other + *a_p;
+
+  if (!m_negative && other.m_negative)
+    return *a_p - -other;
+
+  gcc_assert (m_negative == other.m_negative);
+
   int dexp;
   sreal tmp, r;
-const sreal *a_p = this, *b_p = &other, *bb;
+  r.m_negative = a_p->m_negative;
 
   if (*a_p < *b_p)
     {
@@ -211,10 +224,30 @@ sreal::operator- (const sreal &other) const
   int dexp;
   sreal tmp, r;
   const sreal *bb;
+  const sreal *a_p = this;
+
+  /* -a - b => -a + (-b).  */
+  if (m_negative && !other.m_negative)
+    return *a_p + -other;
 
-  gcc_assert (*this >= other);
+  /* a - (-b) => a + b.  */
+  if (!m_negative && other.m_negative)
+    return *a_p + -other;
+
+  gcc_assert (m_negative == other.m_negative);
+
+  /* We want to substract a smaller number from bigger
+    for nonegative numbers.  */
+  if (!m_negative && *this < other)
+    return -(other - *this);
+
+  /* Example: -2 - (-3) => 3 - 2 */
+  if (m_negative && *this > other)
+    return -other - -(*this);
 
   dexp = m_exp - other.m_exp;
+
+  r.m_negative = m_negative;
   r.m_exp = m_exp;
   if (dexp > SREAL_BITS)
     {
@@ -240,7 +273,7 @@ sreal::operator- (const sreal &other) const
 sreal
 sreal::operator* (const sreal &other) const
 {
-sreal r;
+  sreal r;
   if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
@@ -252,6 +285,8 @@ sreal r;
       r.m_exp = m_exp + other.m_exp;
       r.normalize ();
     }
+
+  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -261,9 +296,10 @@ sreal
 sreal::operator/ (const sreal &other) const
 {
   gcc_assert (other.m_sig != 0);
-sreal r;
+  sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
+  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 461e28b..bfed3c7 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -1,4 +1,4 @@
-/* Definitions for simple data type for positive real numbers.
+/* Definitions for simple data type for real numbers.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
 #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
-#define SREAL_MAX_EXP (INT_MAX / 4)
+#define SREAL_MAX_EXP (INT_MAX / 8)
 
 #define SREAL_BITS SREAL_PART_BITS
 
@@ -34,10 +34,21 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1) {}
+  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
 
   /* Construct a sreal.  */
-  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
+  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  {
+    m_negative = sig < 0;
+
+    // TODO: speed up
+    if (sig < 0)
+      sig = -sig;
+
+    m_sig = (uint64_t) sig;
+
+    normalize ();
+  }
 
   void dump (FILE *) const;
   int64_t to_int () const;
@@ -49,13 +60,58 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    return m_exp < other.m_exp
+    if (m_negative != other.m_negative)
+      return m_negative > other.m_negative;
+
+    bool r = m_exp < other.m_exp
       || (m_exp == other.m_exp && m_sig < other.m_sig);
+
+    return m_negative ? !r : r;
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig;
+    return m_exp == other.m_exp && m_sig == other.m_sig
+		    && m_negative == other.m_negative;
+  }
+
+  sreal operator- () const
+  {
+    if (m_sig == 0)
+      return *this;
+
+    sreal tmp = *this;
+    tmp.m_negative = !tmp.m_negative;
+
+    return tmp;
+  }
+
+  sreal shift (int sig) const
+  {
+    sreal tmp = *this;
+    tmp.m_sig += sig;
+
+    return tmp;
+  }
+
+  /* Return zero constant.  */
+  inline static sreal zero ()
+  {
+    static const sreal zero = sreal (0);
+    return zero;
+  }
+
+  /* Return one constant.  */
+  inline static sreal one ()
+  {
+    static const sreal one = sreal (1);
+    return one;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal min ()
+  {
+    return sreal (LONG_MIN, 0);
   }
 
 private:
@@ -63,7 +119,8 @@ private:
   void shift_right (int amount);
 
   uint64_t m_sig;		/* Significant.  */
-  signed int m_exp;			/* Exponent.  */
+  signed int m_exp: 31;		/* Exponent.  */
+  unsigned int m_negative: 1;	/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
@@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
 
 inline sreal &operator-= (sreal &a, const sreal &b)
 {
-return a = a - b;
+  return a = a - b;
 }
 
 inline sreal &operator/= (sreal &a, const sreal &b)
 {
-return a = a / b;
+  return a = a / b;
 }
 
 inline sreal &operator*= (sreal &a, const sreal &b)
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 2/9] New template fibonacci_heap class introduced.
  2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
  2014-11-13 21:14   ` mliska
@ 2014-11-13 23:42   ` Jan Hubicka
  2014-11-14  5:19   ` Jeff Law
  2014-11-14 12:37   ` Florian Weimer
  3 siblings, 0 replies; 38+ messages in thread
From: Jan Hubicka @ 2014-11-13 23:42 UTC (permalink / raw)
  To: mliska, rguenther, tsaunders, paolo.carlini; +Cc: gcc-patches

> gcc/ChangeLog:
> 
> 2014-11-13  Martin Liska  <mliska@suse.cz>
> 
> 	* fibonacci_heap.h: New file.
> 	* ipa-inline.c (update_edge_key): New heap API is used.
> 	(update_caller_keys): Likewise.
> 	(update_callee_keys): Likewise.
> 	(lookup_recursive_calls): Likewise.
> 	(recursive_inlining): Likewise.
> 	(add_new_edges_to_heap): Likewise.
> 	(heap_edge_removal_hook): Likewise.
> 	(inline_small_functions): Likewise.

My C++-fu is not on par to properly review fibonaci_heap.h.  Trevor, Richard, could
you please comment? My only concer is about the amount of code this winds into that
may be shared across instantiations in other way than via ICF :)

Also I wonder if API compatibility with std:: heaps would be useful in future.
(we can not use priority queue from libstdc++ because inliner actually need operation
to decrease keys badness and to remove a key)

> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
> index 5c97815..1ce856f 100644
> --- a/gcc/ipa-inline.c
> +++ b/gcc/ipa-inline.c
> @@ -138,6 +138,10 @@ along with GCC; see the file COPYING3.  If not see
>  #include "auto-profile.h"
>  #include "cilk.h"
>  #include "builtins.h"
> +#include "fibonacci_heap.h"
> +
> +typedef fibonacci_heap <long, cgraph_edge> edge_heap_t;
> +typedef fibonacci_node <long, cgraph_edge> edge_heap_node_t;

The second can be just typedef of first, right?
>  
>  /* Statistics we collect about inlining algorithm.  */
>  static int overall_size;
> @@ -1076,19 +1080,19 @@ edge_badness (struct cgraph_edge *edge, bool dump)
>  
>  /* Recompute badness of EDGE and update its key in HEAP if needed.  */
>  static inline void
> -update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
> +update_edge_key (edge_heap_t *heap, struct cgraph_edge *edge)
>  {
>    int badness = edge_badness (edge, false);
>    if (edge->aux)
>      {
> -      fibnode_t n = (fibnode_t) edge->aux;
> -      gcc_checking_assert (n->data == edge);
> +      edge_heap_node_t *n = (edge_heap_node_t *) edge->aux;
> +      gcc_checking_assert (n->get_data () == edge);
>  
> -      /* fibheap_replace_key only decrease the keys.
> +      /* fibonacci_heap::replace_key only decrease the keys.
>  	 When we increase the key we do not update heap
>  	 and instead re-insert the element once it becomes
>  	 a minimum of heap.  */
> -      if (badness < n->key)
> +      if (badness < n->get_key ())
>  	{
>  	  if (dump_file && (dump_flags & TDF_DETAILS))
>  	    {
> @@ -1098,11 +1102,11 @@ update_edge_key (fibheap_t heap, struct cgraph_edge *edge)
>  		       edge->caller->order,
>  		       xstrdup (edge->callee->name ()),
>  		       edge->callee->order,
> -		       (int)n->key,
> +		       (int)n->get_key (),
>  		       badness);
>  	    }
> -	  fibheap_replace_key (heap, n, badness);
> -	  gcc_checking_assert (n->key == badness);
> +	  heap->replace_key (n, badness);

One thing that can be "fixed" is that fibheap actually do not allow you to increase key
(if you do so it will give bogus order). Perhaps replace_key should be called decrease_key ;)

Otherwise the ipa-inline.c changes are OK.

Honza

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/9] New fibonacci heap and sreal enhancement.
  2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
                   ` (7 preceding siblings ...)
  2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
@ 2014-11-13 23:42 ` Jan Hubicka
  8 siblings, 0 replies; 38+ messages in thread
From: Jan Hubicka @ 2014-11-13 23:42 UTC (permalink / raw)
  To: mliska; +Cc: gcc-patches

> Hello.
> 
> Following patch set introduces new template class for fibonacci heap
> that is mainly utilized by IPA inliner. Apart from that, I also enhanced
> existing sreal implementation so that it can also handle negative numbers.
> 
> I was primary motivated by Honza, because current heap implementation
> in ipa-inline.c suffers from round off problems.
> 
> I was able to run WPA phase which was by about ~3% slower than current
> implementation.
> 
> All patches can bootstrap and no regression was seen on x86_64-linux-pc.
> 
> I welcome any remarks connected to the patch set.
> 
> Thanks,
> Martin
> 
> (please ignore following ChangeLog diff)

I do :)

To give bit of context into this, the inliner is basically a greedy algorithm
making inline decisions in the increasing badness order.  The badness is
(in simplified view) a ration of size growth over expected speedup with several
other factors added.

Given that both size and expected speedup do not have any good upper bound,
it is very hard to compute those as fixed point 32bit value required for current
fibheap keys. In some cases we need to watch overflows when badness get really
high (especially now when we inline functions ignoring the size bounds in
cases we know the inlining will bring considerable benefits) and there are cases
where we have too much of roundoff to 0.  This happens in tramp3d that has
tens of thousdands inline candidates all with expected growth <5 instructions
that still needs to be ordered.

I changed the fixed point few times, but now again we hit case where tramp3d
inlining exhaust the queue with badness of 0 (and thus making kind of random
decisions) so I think going into floating point badness would be significant
improvement.

It needs to be done curefully though to avoid performance impact with LTO where
fibheap maintenance is important % of compile time.

Honza

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
  2014-11-13 21:31   ` mliska
@ 2014-11-13 23:44   ` Jan Hubicka
  2014-11-14  4:57     ` Trevor Saunders
  2014-11-14  4:29   ` Jeff Law
  2014-11-14 10:58   ` Richard Biener
  3 siblings, 1 reply; 38+ messages in thread
From: Jan Hubicka @ 2014-11-13 23:44 UTC (permalink / raw)
  To: mliska; +Cc: gcc-patches

Hello,
in general I like this addition - I was not aware that sreal has no support for negative values.
This would be serious maintainance burden if sreals was used for profile updating - it is very
easy to get negative temporaries while dong the updates.
> gcc/ChangeLog:
> 
> 2014-11-13  Martin Liska  <mliska@suse.cz>
> 
> 	* predict.c (propagate_freq): More elegant sreal API is used.
> 	(estimate_bb_frequencies): New static constants defined by sreal
> 	replace precomputed ones.
> 	* sreal.c (sreal::normalize): New function.
> 	(sreal::to_int): Likewise.
> 	(sreal::operator+): Likewise.
> 	(sreal::operator-): Likewise.
> 	* sreal.h: Definition of new functions added.
> diff --git a/gcc/sreal.c b/gcc/sreal.c
> index 3f5456a..89b9c4d 100644
> --- a/gcc/sreal.c
> +++ b/gcc/sreal.c
> @@ -1,4 +1,4 @@
> -/* Simple data type for positive real numbers for the GNU compiler.
> +/* Simple data type for real numbers for the GNU compiler.
>     Copyright (C) 2002-2014 Free Software Foundation, Inc.
>  
>  This file is part of GCC.
> @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
>  along with GCC; see the file COPYING3.  If not see
>  <http://www.gnu.org/licenses/>.  */
>  
> -/* This library supports positive real numbers and 0;
> +/* This library supports real numbers;
>     inf and nan are NOT supported.
>     It is written to be simple and fast.
>  
> @@ -102,6 +102,7 @@ sreal::normalize ()
>  {
>    if (m_sig == 0)
>      {
> +      m_negative = 0;
>        m_exp = -SREAL_MAX_EXP;
>      }
>    else if (m_sig < SREAL_MIN_SIG)
> @@ -153,15 +154,17 @@ sreal::normalize ()
>  int64_t
>  sreal::to_int () const
>  {
> +  int64_t sign = m_negative ? -1 : 1;
> +
>    if (m_exp <= -SREAL_BITS)
>      return 0;
>    if (m_exp >= SREAL_PART_BITS)
> -    return INTTYPE_MAXIMUM (int64_t);
> +    return sign * INTTYPE_MAXIMUM (int64_t);
>    if (m_exp > 0)
> -    return m_sig << m_exp;
> +    return sign * (m_sig << m_exp);
>    if (m_exp < 0)
> -    return m_sig >> -m_exp;
> -  return m_sig;
> +    return sign * (m_sig >> -m_exp);
> +  return sign * m_sig;
>  }
>  
>  /* Return *this + other.  */
> @@ -169,9 +172,19 @@ sreal::to_int () const
>  sreal
>  sreal::operator+ (const sreal &other) const
>  {
> +  const sreal *a_p = this, *b_p = &other, *bb;
> +
> +  if (m_negative && !other.m_negative)
> +    return other + *a_p;
> +
> +  if (!m_negative && other.m_negative)
> +    return *a_p - -other;
> +
> +  gcc_assert (m_negative == other.m_negative);

I wonder what kind of code this winds into - you need recursive inlining to fix
this and it won't be clear to inliner that the recursion depth is 1.  Perhaps
having an inline private function for signedless + and - and implementing real
operators by this would factor the code better.

I wonder if there is not a faster implementation given that this code is on
way to internal loops of inliner.  If significand was signed, some of these operations
would just work, right?
> diff --git a/gcc/sreal.h b/gcc/sreal.h
> index 461e28b..bfed3c7 100644
> --- a/gcc/sreal.h
> +++ b/gcc/sreal.h
> @@ -1,4 +1,4 @@
> -/* Definitions for simple data type for positive real numbers.
> +/* Definitions for simple data type for real numbers.
>     Copyright (C) 2002-2014 Free Software Foundation, Inc.
>  
>  This file is part of GCC.
> @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
>  
>  #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>  #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
> -#define SREAL_MAX_EXP (INT_MAX / 4)
> +#define SREAL_MAX_EXP (INT_MAX / 8)
>  
>  #define SREAL_BITS SREAL_PART_BITS
>  
> @@ -34,10 +34,21 @@ class sreal
>  {
>  public:
>    /* Construct an uninitialized sreal.  */
> -  sreal () : m_sig (-1), m_exp (-1) {}
> +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
>  
>    /* Construct a sreal.  */
> -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
> +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
> +  {
> +    m_negative = sig < 0;
> +
> +    // TODO: speed up
I think we do not need to care about this; expression folding should
> +    if (sig < 0)
> +      sig = -sig;
> +
> +    m_sig = (uint64_t) sig;
> +
> +    normalize ();
> +  }

We probably want sreal conversion from both signed and unsigned ints?
For debugging output it would be very useful to also have conversion to double.
The dump method is bit unhandy to use.
>  
>    void dump (FILE *) const;
>    int64_t to_int () const;
> @@ -49,13 +60,58 @@ public:
>  
>    bool operator< (const sreal &other) const
>    {
> -    return m_exp < other.m_exp
> +    if (m_negative != other.m_negative)
> +      return m_negative > other.m_negative;
I guess negative zero is smaller than positive, but I do not see why that would be problem

Again, I would preffer C++ person to glance over this.

Honza

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 7/9] Old libiberty fib_heap removed.
  2014-11-13 20:39 ` [PATCH 7/9] Old libiberty fib_heap removed mliska
@ 2014-11-13 23:54   ` Jan Hubicka
  2014-11-14  1:30     ` Jeff Law
  0 siblings, 1 reply; 38+ messages in thread
From: Jan Hubicka @ 2014-11-13 23:54 UTC (permalink / raw)
  To: mliska; +Cc: gcc-patches

> gcc/ChangeLog:
> 
> 2014-11-13  Martin Liska  <mliska@suse.cz>
> 
> 	* bb-reorder.c (find_traces_1_round): Old fibheap_t type removed.
> 	* bt-load.c: Include of fibheap.h is removed.
> 	* cgraphunit.c: Likewise.
> 	* config/i386/i386.c: Likewise.
> 	* ipa-inline.c: Likewise.
> 	* var-tracking.c: Likewise.
> 
> include/ChangeLog:
> 
> 2014-11-13  Martin Liska  <mliska@suse.cz>
> 
> 	* fibheap.h: Remove.
> 
> libiberty/ChangeLog:
> 
> 2014-11-13  Martin Liska  <mliska@suse.cz>
> 
> 	* Makefile.in: Remove.
> 	* fibheap.c: Remove.

You can not really remove libiberty fibheap, because it is shared across
projects.  Basically everything in libiberty is set in stone.
(I believe gdb is other user)

Removing the uses from gcc directory is OK of course. From where the fibheap_t is comming
before this patch is applied?

Honza

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 7/9] Old libiberty fib_heap removed.
  2014-11-13 23:54   ` Jan Hubicka
@ 2014-11-14  1:30     ` Jeff Law
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  1:30 UTC (permalink / raw)
  To: Jan Hubicka, mliska; +Cc: gcc-patches

On 11/13/14 16:42, Jan Hubicka wrote:
>> gcc/ChangeLog:
>>
>> 2014-11-13  Martin Liska  <mliska@suse.cz>
>>
>> 	* bb-reorder.c (find_traces_1_round): Old fibheap_t type removed.
>> 	* bt-load.c: Include of fibheap.h is removed.
>> 	* cgraphunit.c: Likewise.
>> 	* config/i386/i386.c: Likewise.
>> 	* ipa-inline.c: Likewise.
>> 	* var-tracking.c: Likewise.
>>
>> include/ChangeLog:
>>
>> 2014-11-13  Martin Liska  <mliska@suse.cz>
>>
>> 	* fibheap.h: Remove.
>>
>> libiberty/ChangeLog:
>>
>> 2014-11-13  Martin Liska  <mliska@suse.cz>
>>
>> 	* Makefile.in: Remove.
>> 	* fibheap.c: Remove.
>
> You can not really remove libiberty fibheap, because it is shared across
> projects.  Basically everything in libiberty is set in stone.
> (I believe gdb is other user)
More correctly we'd have to coordinate with other projects prior to 
removing something from libibery.  I think it's OK to just leave the 
libiberty implementation and include API header alone.


>
> Removing the uses from gcc directory is OK of course. From where the fibheap_t is comming
> before this patch is applied?
Right, agreed.
jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
  2014-11-13 21:31   ` mliska
  2014-11-13 23:44   ` Jan Hubicka
@ 2014-11-14  4:29   ` Jeff Law
  2014-11-14 10:58   ` Richard Biener
  3 siblings, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  4:29 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/13/14 05:35, mliska wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* predict.c (propagate_freq): More elegant sreal API is used.
> 	(estimate_bb_frequencies): New static constants defined by sreal
> 	replace precomputed ones.
> 	* sreal.c (sreal::normalize): New function.
> 	(sreal::to_int): Likewise.
> 	(sreal::operator+): Likewise.
> 	(sreal::operator-): Likewise.
> 	* sreal.h: Definition of new functions added.
Shouldn't this be moving forward independent of the fibheap changes?


> ---
>   gcc/predict.c | 30 +++++++++++-------------
>   gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
>   gcc/sreal.h   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>   3 files changed, 126 insertions(+), 35 deletions(-)
>
> diff --git a/gcc/predict.c b/gcc/predict.c
> index 0215e91..0f640f5 100644
> --- a/gcc/predict.c
> +++ b/gcc/predict.c
> @@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
>
>   /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
>   		   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
> -static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
> +static sreal real_almost_one, real_br_prob_base,
>   	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
Update comment to reflect the remaining values.

Implementation of the arithmetics seems sane in the sense that we're 
just using basic identities to put everything into a canonical form then 
calling back into one of the existing functions.

If this is supposed to be small and fast, do we pay a noticeable penalty 
for canonicalizing then another call?  Would we be better off (for 
example) directly handling a + b with a negative and b positive?

I think it's OK to assume we can apply these identities as we're 
building a minimalist real implementation.   Obviously if we were 
building an IEEE compliant implementation, this would all be 
considerably more complex ;-)


>
> @@ -34,10 +34,21 @@ class sreal
>   {
>   public:
>     /* Construct an uninitialized sreal.  */
> -  sreal () : m_sig (-1), m_exp (-1) {}
> +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
>
>     /* Construct a sreal.  */
> -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
> +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
> +  {
> +    m_negative = sig < 0;
> +
> +    // TODO: speed up
> +    if (sig < 0)
> +      sig = -sig;
Not sure what you really need to do here.  You could test and flip the 
sign bit, but  I'm pretty sure that's already handled for you in GCC, at 
least in the cases that are likely to matter.

So one thing that comes to mind is that it looks like we have +-0.  THey 
compare unequal and have an ordering.  Not sure if that's desirable or not.

I assume the shift method is used by one of the other patches in the 
series.  RIght?

So with the comment fix, some comment about handling of +-0, I think 
this is good to go and can go in independently of the rest of the patch 
series.

jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 4/9] tracer ported to new fibonacci_heap data structure.
  2014-11-13 20:39 ` [PATCH 4/9] tracer ported to new fibonacci_heap data structure mliska
@ 2014-11-14  4:31   ` Jeff Law
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  4:31 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/12/14 18:54, mliska wrote:
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* tracer.c (tail_duplicate): New fibonacci_heap class is used.
OK if/when prerequisites are approved.

jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose.
  2014-11-13 20:39 ` [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose mliska
@ 2014-11-14  4:32   ` Jeff Law
  2014-11-19 18:42   ` H.J. Lu
  1 sibling, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  4:32 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/12/14 18:45, mliska wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* bb-reorder.c (mark_bb_visited): New fibonacci_heap is used.
> 	(find_traces): Likewise.
> 	(find_traces_1_round): Likewise.
If this removed the last uses of the old fibheap code, then the old 
fibheap.h include ought to be removed.

With that change, OK if/when prerequisites are approved.

Jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 5/9] bt-load is ported to fibonacci_heap.
  2014-11-13 20:39 ` [PATCH 5/9] bt-load is ported to fibonacci_heap mliska
@ 2014-11-14  4:34   ` Jeff Law
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  4:34 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/13/14 03:08, mliska wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* bt-load.c (add_btr_def): New fibonacci_heap is used.
> 	(migrate_btr_defs): Likewise.
If you've removed last uses of the old fibheap code, then remove the 
include of fibheap.h.

OK once prerequisites are approved.

jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 6/9] fibonacci_heap is used for var-tracking.
  2014-11-13 20:39 ` [PATCH 6/9] fibonacci_heap is used for var-tracking mliska
@ 2014-11-14  4:45   ` Jeff Law
  0 siblings, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  4:45 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/13/14 03:17, mliska wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* var-tracking.c (vt_find_locations): New fibonacci_node is used.
Remove old fibheap.h if it's not used anymore.

OK if/when prerequisites are approved.

jeff


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument.
  2014-11-13 20:45 ` [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument mliska
@ 2014-11-14  4:46   ` Jeff Law
  2014-11-24 19:25   ` H.J. Lu
  1 sibling, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  4:46 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/13/14 13:10, mliska wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* ipa-inline.c (edge_badness): long is replaced by sreal
> 	as fibonacci_heap template type.
> 	(update_edge_key): Likewise.
> 	(inline_small_functions): Likewise.
> 	* sreal.h (inline sreal operator<<): New function added.
> 	(inline sreal operator>>): Likewise.
Remove include of fibheap.h if it's no longer needed.



> @@ -1057,13 +1057,13 @@ edge_badness (struct cgraph_edge *edge, bool dump)
>
>         /* Decrease badness if call is nested.  */
>         if (badness > 0)
> -	badness >>= nest;
> +	badness = badness >> nest;
>         else
>   	{
> -	  badness <<= nest;
> +	  badness = badness << nest;
OK.  Here's the shifts I was asking about when I looked at the sreal 
changes :-)

OK if/when prerequisites are approved.

jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-13 23:44   ` Jan Hubicka
@ 2014-11-14  4:57     ` Trevor Saunders
  0 siblings, 0 replies; 38+ messages in thread
From: Trevor Saunders @ 2014-11-14  4:57 UTC (permalink / raw)
  To: gcc-patches

On Fri, Nov 14, 2014 at 12:40:23AM +0100, Jan Hubicka wrote:
> Hello,
> in general I like this addition - I was not aware that sreal has no support for negative values.
> This would be serious maintainance burden if sreals was used for profile updating - it is very
> easy to get negative temporaries while dong the updates.
> > gcc/ChangeLog:
> > 
> > 2014-11-13  Martin Liska  <mliska@suse.cz>
> > 
> > 	* predict.c (propagate_freq): More elegant sreal API is used.
> > 	(estimate_bb_frequencies): New static constants defined by sreal
> > 	replace precomputed ones.
> > 	* sreal.c (sreal::normalize): New function.
> > 	(sreal::to_int): Likewise.
> > 	(sreal::operator+): Likewise.
> > 	(sreal::operator-): Likewise.
> > 	* sreal.h: Definition of new functions added.
> > diff --git a/gcc/sreal.c b/gcc/sreal.c
> > index 3f5456a..89b9c4d 100644
> > --- a/gcc/sreal.c
> > +++ b/gcc/sreal.c
> > @@ -1,4 +1,4 @@
> > -/* Simple data type for positive real numbers for the GNU compiler.
> > +/* Simple data type for real numbers for the GNU compiler.
> >     Copyright (C) 2002-2014 Free Software Foundation, Inc.
> >  
> >  This file is part of GCC.
> > @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
> >  along with GCC; see the file COPYING3.  If not see
> >  <http://www.gnu.org/licenses/>.  */
> >  
> > -/* This library supports positive real numbers and 0;
> > +/* This library supports real numbers;
> >     inf and nan are NOT supported.
> >     It is written to be simple and fast.
> >  
> > @@ -102,6 +102,7 @@ sreal::normalize ()
> >  {
> >    if (m_sig == 0)
> >      {
> > +      m_negative = 0;
> >        m_exp = -SREAL_MAX_EXP;
> >      }
> >    else if (m_sig < SREAL_MIN_SIG)
> > @@ -153,15 +154,17 @@ sreal::normalize ()
> >  int64_t
> >  sreal::to_int () const
> >  {
> > +  int64_t sign = m_negative ? -1 : 1;
> > +
> >    if (m_exp <= -SREAL_BITS)
> >      return 0;
> >    if (m_exp >= SREAL_PART_BITS)
> > -    return INTTYPE_MAXIMUM (int64_t);
> > +    return sign * INTTYPE_MAXIMUM (int64_t);
> >    if (m_exp > 0)
> > -    return m_sig << m_exp;
> > +    return sign * (m_sig << m_exp);
> >    if (m_exp < 0)
> > -    return m_sig >> -m_exp;
> > -  return m_sig;
> > +    return sign * (m_sig >> -m_exp);
> > +  return sign * m_sig;
> >  }
> >  
> >  /* Return *this + other.  */
> > @@ -169,9 +172,19 @@ sreal::to_int () const
> >  sreal
> >  sreal::operator+ (const sreal &other) const
> >  {
> > +  const sreal *a_p = this, *b_p = &other, *bb;
> > +
> > +  if (m_negative && !other.m_negative)
> > +    return other + *a_p;
> > +
> > +  if (!m_negative && other.m_negative)
> > +    return *a_p - -other;
> > +
> > +  gcc_assert (m_negative == other.m_negative);
> 
> I wonder what kind of code this winds into - you need recursive inlining to fix
> this and it won't be clear to inliner that the recursion depth is 1.  Perhaps

maybe tail recurse optimizer is smart enough to see it can use a jump,
and then it might not be too bad.

> having an inline private function for signedless + and - and implementing real
> operators by this would factor the code better.
> 
> I wonder if there is not a faster implementation given that this code is on
> way to internal loops of inliner.  If significand was signed, some of these operations
> would just work, right?

I believe so, but I haven't actually proved it to myself (I also
suggested going this route).

I'll try and look in this in more depth, but so many things to do and a
bunch of my time the next few days will be at family events.

Trev

> > diff --git a/gcc/sreal.h b/gcc/sreal.h
> > index 461e28b..bfed3c7 100644
> > --- a/gcc/sreal.h
> > +++ b/gcc/sreal.h
> > @@ -1,4 +1,4 @@
> > -/* Definitions for simple data type for positive real numbers.
> > +/* Definitions for simple data type for real numbers.
> >     Copyright (C) 2002-2014 Free Software Foundation, Inc.
> >  
> >  This file is part of GCC.
> > @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
> >  
> >  #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
> >  #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
> > -#define SREAL_MAX_EXP (INT_MAX / 4)
> > +#define SREAL_MAX_EXP (INT_MAX / 8)
> >  
> >  #define SREAL_BITS SREAL_PART_BITS
> >  
> > @@ -34,10 +34,21 @@ class sreal
> >  {
> >  public:
> >    /* Construct an uninitialized sreal.  */
> > -  sreal () : m_sig (-1), m_exp (-1) {}
> > +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
> >  
> >    /* Construct a sreal.  */
> > -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
> > +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
> > +  {
> > +    m_negative = sig < 0;
> > +
> > +    // TODO: speed up
> I think we do not need to care about this; expression folding should
> > +    if (sig < 0)
> > +      sig = -sig;
> > +
> > +    m_sig = (uint64_t) sig;
> > +
> > +    normalize ();
> > +  }
> 
> We probably want sreal conversion from both signed and unsigned ints?
> For debugging output it would be very useful to also have conversion to double.
> The dump method is bit unhandy to use.
> >  
> >    void dump (FILE *) const;
> >    int64_t to_int () const;
> > @@ -49,13 +60,58 @@ public:
> >  
> >    bool operator< (const sreal &other) const
> >    {
> > -    return m_exp < other.m_exp
> > +    if (m_negative != other.m_negative)
> > +      return m_negative > other.m_negative;
> I guess negative zero is smaller than positive, but I do not see why that would be problem
> 
> Again, I would preffer C++ person to glance over this.
> 
> Honza

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 2/9] New template fibonacci_heap class introduced.
  2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
  2014-11-13 21:14   ` mliska
  2014-11-13 23:42   ` Jan Hubicka
@ 2014-11-14  5:19   ` Jeff Law
  2014-11-14 12:37   ` Florian Weimer
  3 siblings, 0 replies; 38+ messages in thread
From: Jeff Law @ 2014-11-14  5:19 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/13/14 13:06, mliska wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
> 	* fibonacci_heap.h: New file.
> 	* ipa-inline.c (update_edge_key): New heap API is used.
> 	(update_caller_keys): Likewise.
> 	(update_callee_keys): Likewise.
> 	(lookup_recursive_calls): Likewise.
> 	(recursive_inlining): Likewise.
> 	(add_new_edges_to_heap): Likewise.
> 	(heap_edge_removal_hook): Likewise.
> 	(inline_small_functions): Likewise.
This is a very simple, literal translation of the old fibheap code into 
C++.  Probably the hardest part of reviewing was translating between the 
function names between the two implementations.


> +  /* Constructor for a node with givek KEY.  */
s/givek/given/

> +	  if (x->compare (y) > 0)
> +	    {
> +	      /* TODO: swap */
> +	      fibonacci_node_t *temp;
> +	      temp = x;
> +	      x = y;
> +	      y = temp;
> +	    }
Given the literal translation, I can see why you left this.  Feel free 
to turn it into a swap, consider the patch pre-approved.

> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
> index 5c97815..1ce856f 100644
> --- a/gcc/ipa-inline.c
> +++ b/gcc/ipa-inline.c
> @@ -138,6 +138,10 @@ along with GCC; see the file COPYING3.  If not see
>   #include "auto-profile.h"
>   #include "cilk.h"
>   #include "builtins.h"
> +#include "fibonacci_heap.h"
If there are no more uses of fibheap.h, then remove its #include.

Approved with the nit fixes.

jeff

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
                     ` (2 preceding siblings ...)
  2014-11-14  4:29   ` Jeff Law
@ 2014-11-14 10:58   ` Richard Biener
  2014-11-21 11:30     ` Martin Liška
  3 siblings, 1 reply; 38+ messages in thread
From: Richard Biener @ 2014-11-14 10:58 UTC (permalink / raw)
  To: mliska; +Cc: GCC Patches

On Thu, Nov 13, 2014 at 1:35 PM, mliska <mliska@suse.cz> wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
>         * predict.c (propagate_freq): More elegant sreal API is used.
>         (estimate_bb_frequencies): New static constants defined by sreal
>         replace precomputed ones.
>         * sreal.c (sreal::normalize): New function.
>         (sreal::to_int): Likewise.
>         (sreal::operator+): Likewise.
>         (sreal::operator-): Likewise.
>         * sreal.h: Definition of new functions added.

Please use gcc_checking_assert()s everywhere.  sreal is supposed
to be fast... (I see it has current uses of gcc_assert - you may want
to mass-convert them as a followup).

> ---
>  gcc/predict.c | 30 +++++++++++-------------
>  gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
>  gcc/sreal.h   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>  3 files changed, 126 insertions(+), 35 deletions(-)
>
> diff --git a/gcc/predict.c b/gcc/predict.c
> index 0215e91..0f640f5 100644
> --- a/gcc/predict.c
> +++ b/gcc/predict.c
> @@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
>
>  /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
>                    1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
> -static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
> +static sreal real_almost_one, real_br_prob_base,
>              real_inv_br_prob_base, real_one_half, real_bb_freq_max;
>
>  static void combine_predictions_for_insn (rtx_insn *, basic_block);
> @@ -2528,13 +2528,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>         bb->count = bb->frequency = 0;
>      }
>
> -  BLOCK_INFO (head)->frequency = real_one;
> +  BLOCK_INFO (head)->frequency = sreal::one ();
>    last = head;
>    for (bb = head; bb; bb = nextbb)
>      {
>        edge_iterator ei;
> -      sreal cyclic_probability = real_zero;
> -      sreal frequency = real_zero;
> +      sreal cyclic_probability = sreal::zero ();
> +      sreal frequency = sreal::zero ();
>
>        nextbb = BLOCK_INFO (bb)->next;
>        BLOCK_INFO (bb)->next = NULL;
> @@ -2559,13 +2559,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>                                   * BLOCK_INFO (e->src)->frequency /
>                                   REG_BR_PROB_BASE);  */
>
> -               sreal tmp (e->probability, 0);
> +               sreal tmp = e->probability;
>                 tmp *= BLOCK_INFO (e->src)->frequency;
>                 tmp *= real_inv_br_prob_base;
>                 frequency += tmp;
>               }
>
> -         if (cyclic_probability == real_zero)
> +         if (cyclic_probability == sreal::zero ())
>             {
>               BLOCK_INFO (bb)->frequency = frequency;
>             }
> @@ -2577,7 +2577,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>               /* BLOCK_INFO (bb)->frequency = frequency
>                                               / (1 - cyclic_probability) */
>
> -             cyclic_probability = real_one - cyclic_probability;
> +             cyclic_probability = sreal::one () - cyclic_probability;
>               BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
>             }
>         }
> @@ -2591,7 +2591,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>              = ((e->probability * BLOCK_INFO (bb)->frequency)
>              / REG_BR_PROB_BASE); */
>
> -         sreal tmp (e->probability, 0);
> +         sreal tmp = e->probability;
>           tmp *= BLOCK_INFO (bb)->frequency;
>           EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
>         }
> @@ -2873,13 +2873,11 @@ estimate_bb_frequencies (bool force)
>        if (!real_values_initialized)
>          {
>           real_values_initialized = 1;
> -         real_zero = sreal (0, 0);
> -         real_one = sreal (1, 0);
> -         real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
> -         real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
> +         real_br_prob_base = REG_BR_PROB_BASE;
> +         real_bb_freq_max = BB_FREQ_MAX;
>           real_one_half = sreal (1, -1);
> -         real_inv_br_prob_base = real_one / real_br_prob_base;
> -         real_almost_one = real_one - real_inv_br_prob_base;
> +         real_inv_br_prob_base = sreal::one () / real_br_prob_base;
> +         real_almost_one = sreal::one () - real_inv_br_prob_base;
>         }
>
>        mark_dfs_back_edges ();
> @@ -2897,7 +2895,7 @@ estimate_bb_frequencies (bool force)
>
>           FOR_EACH_EDGE (e, ei, bb->succs)
>             {
> -             EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
> +             EDGE_INFO (e)->back_edge_prob = e->probability;
>               EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
>             }
>         }
> @@ -2906,7 +2904,7 @@ estimate_bb_frequencies (bool force)
>           to outermost to examine frequencies for back edges.  */
>        estimate_loops ();
>
> -      freq_max = real_zero;
> +      freq_max = sreal::zero ();
>        FOR_EACH_BB_FN (bb, cfun)
>         if (freq_max < BLOCK_INFO (bb)->frequency)
>           freq_max = BLOCK_INFO (bb)->frequency;
> diff --git a/gcc/sreal.c b/gcc/sreal.c
> index 3f5456a..89b9c4d 100644
> --- a/gcc/sreal.c
> +++ b/gcc/sreal.c
> @@ -1,4 +1,4 @@
> -/* Simple data type for positive real numbers for the GNU compiler.
> +/* Simple data type for real numbers for the GNU compiler.
>     Copyright (C) 2002-2014 Free Software Foundation, Inc.
>
>  This file is part of GCC.
> @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
>  along with GCC; see the file COPYING3.  If not see
>  <http://www.gnu.org/licenses/>.  */
>
> -/* This library supports positive real numbers and 0;
> +/* This library supports real numbers;
>     inf and nan are NOT supported.
>     It is written to be simple and fast.
>
> @@ -102,6 +102,7 @@ sreal::normalize ()
>  {
>    if (m_sig == 0)
>      {
> +      m_negative = 0;
>        m_exp = -SREAL_MAX_EXP;
>      }
>    else if (m_sig < SREAL_MIN_SIG)
> @@ -153,15 +154,17 @@ sreal::normalize ()
>  int64_t
>  sreal::to_int () const
>  {
> +  int64_t sign = m_negative ? -1 : 1;
> +
>    if (m_exp <= -SREAL_BITS)
>      return 0;
>    if (m_exp >= SREAL_PART_BITS)
> -    return INTTYPE_MAXIMUM (int64_t);
> +    return sign * INTTYPE_MAXIMUM (int64_t);
>    if (m_exp > 0)
> -    return m_sig << m_exp;
> +    return sign * (m_sig << m_exp);
>    if (m_exp < 0)
> -    return m_sig >> -m_exp;
> -  return m_sig;
> +    return sign * (m_sig >> -m_exp);
> +  return sign * m_sig;
>  }
>
>  /* Return *this + other.  */
> @@ -169,9 +172,19 @@ sreal::to_int () const
>  sreal
>  sreal::operator+ (const sreal &other) const
>  {
> +  const sreal *a_p = this, *b_p = &other, *bb;
> +
> +  if (m_negative && !other.m_negative)
> +    return other + *a_p;
> +
> +  if (!m_negative && other.m_negative)
> +    return *a_p - -other;
> +
> +  gcc_assert (m_negative == other.m_negative);
> +
>    int dexp;
>    sreal tmp, r;
> -const sreal *a_p = this, *b_p = &other, *bb;
> +  r.m_negative = a_p->m_negative;
>
>    if (*a_p < *b_p)
>      {
> @@ -211,10 +224,30 @@ sreal::operator- (const sreal &other) const
>    int dexp;
>    sreal tmp, r;
>    const sreal *bb;
> +  const sreal *a_p = this;
> +
> +  /* -a - b => -a + (-b).  */
> +  if (m_negative && !other.m_negative)
> +    return *a_p + -other;
>
> -  gcc_assert (*this >= other);
> +  /* a - (-b) => a + b.  */
> +  if (!m_negative && other.m_negative)
> +    return *a_p + -other;
> +
> +  gcc_assert (m_negative == other.m_negative);
> +
> +  /* We want to substract a smaller number from bigger
> +    for nonegative numbers.  */
> +  if (!m_negative && *this < other)
> +    return -(other - *this);
> +
> +  /* Example: -2 - (-3) => 3 - 2 */
> +  if (m_negative && *this > other)
> +    return -other - -(*this);
>
>    dexp = m_exp - other.m_exp;
> +
> +  r.m_negative = m_negative;
>    r.m_exp = m_exp;
>    if (dexp > SREAL_BITS)
>      {
> @@ -240,7 +273,7 @@ sreal::operator- (const sreal &other) const
>  sreal
>  sreal::operator* (const sreal &other) const
>  {
> -sreal r;
> +  sreal r;
>    if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
>      {
>        r.m_sig = 0;
> @@ -252,6 +285,8 @@ sreal r;
>        r.m_exp = m_exp + other.m_exp;
>        r.normalize ();
>      }
> +
> +  r.m_negative = m_negative ^ other.m_negative;
>    return r;
>  }
>
> @@ -261,9 +296,10 @@ sreal
>  sreal::operator/ (const sreal &other) const
>  {
>    gcc_assert (other.m_sig != 0);
> -sreal r;
> +  sreal r;
>    r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
>    r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
> +  r.m_negative = m_negative ^ other.m_negative;
>    r.normalize ();
>    return r;
>  }
> diff --git a/gcc/sreal.h b/gcc/sreal.h
> index 461e28b..bfed3c7 100644
> --- a/gcc/sreal.h
> +++ b/gcc/sreal.h
> @@ -1,4 +1,4 @@
> -/* Definitions for simple data type for positive real numbers.
> +/* Definitions for simple data type for real numbers.
>     Copyright (C) 2002-2014 Free Software Foundation, Inc.
>
>  This file is part of GCC.
> @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
>
>  #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>  #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
> -#define SREAL_MAX_EXP (INT_MAX / 4)
> +#define SREAL_MAX_EXP (INT_MAX / 8)
>
>  #define SREAL_BITS SREAL_PART_BITS
>
> @@ -34,10 +34,21 @@ class sreal
>  {
>  public:
>    /* Construct an uninitialized sreal.  */
> -  sreal () : m_sig (-1), m_exp (-1) {}
> +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
>
>    /* Construct a sreal.  */
> -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
> +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
> +  {
> +    m_negative = sig < 0;
> +
> +    // TODO: speed up
> +    if (sig < 0)
> +      sig = -sig;

also undefined behavior for sig == int64_min ...

> +
> +    m_sig = (uint64_t) sig;

any reason for not making m_sig signed and using the sign of m_sig
as sign of the sreal?

> +
> +    normalize ();
> +  }
>
>    void dump (FILE *) const;
>    int64_t to_int () const;
> @@ -49,13 +60,58 @@ public:
>
>    bool operator< (const sreal &other) const
>    {
> -    return m_exp < other.m_exp
> +    if (m_negative != other.m_negative)
> +      return m_negative > other.m_negative;
> +
> +    bool r = m_exp < other.m_exp
>        || (m_exp == other.m_exp && m_sig < other.m_sig);
> +
> +    return m_negative ? !r : r;
>    }
>
>    bool operator== (const sreal &other) const
>    {
> -    return m_exp == other.m_exp && m_sig == other.m_sig;
> +    return m_exp == other.m_exp && m_sig == other.m_sig
> +                   && m_negative == other.m_negative;
> +  }
> +
> +  sreal operator- () const
> +  {
> +    if (m_sig == 0)
> +      return *this;
> +
> +    sreal tmp = *this;
> +    tmp.m_negative = !tmp.m_negative;
> +
> +    return tmp;
> +  }
> +
> +  sreal shift (int sig) const
> +  {
> +    sreal tmp = *this;
> +    tmp.m_sig += sig;
> +
> +    return tmp;
> +  }
> +
> +  /* Return zero constant.  */
> +  inline static sreal zero ()
> +  {
> +    static const sreal zero = sreal (0);
> +    return zero;
> +  }
> +
> +  /* Return one constant.  */
> +  inline static sreal one ()
> +  {
> +    static const sreal one = sreal (1);
> +    return one;
> +  }
> +
> +  /* Global minimum sreal can hold.  */
> +  inline static sreal min ()
> +  {
> +    return sreal (LONG_MIN, 0);
>    }
>
>  private:
> @@ -63,7 +119,8 @@ private:
>    void shift_right (int amount);
>
>    uint64_t m_sig;              /* Significant.  */
> -  signed int m_exp;                    /* Exponent.  */
> +  signed int m_exp: 31;                /* Exponent.  */
> +  unsigned int m_negative: 1;  /* Negative sign.  */

As this gets padded to 2 * 64bits I wonder if it is necessary to
get the slowdowns for using bitfields here.  I'd have just used

  uint64_t m_sig;               /* Significant.  */
  signed int m_exp;                     /* Exponent.  */
  bool m_negative;

or making m_sig signed...

Thanks,
Richard.

>  };
>
>  extern void debug (sreal &ref);
> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
>
>  inline sreal &operator-= (sreal &a, const sreal &b)
>  {
> -return a = a - b;
> +  return a = a - b;
>  }
>
>  inline sreal &operator/= (sreal &a, const sreal &b)
>  {
> -return a = a / b;
> +  return a = a / b;
>  }
>
>  inline sreal &operator*= (sreal &a, const sreal &b)
> --
> 2.1.2
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 2/9] New template fibonacci_heap class introduced.
  2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
                     ` (2 preceding siblings ...)
  2014-11-14  5:19   ` Jeff Law
@ 2014-11-14 12:37   ` Florian Weimer
  3 siblings, 0 replies; 38+ messages in thread
From: Florian Weimer @ 2014-11-14 12:37 UTC (permalink / raw)
  To: mliska, gcc-patches

On 11/13/2014 09:06 PM, mliska wrote:
> +   Insert: O(2) amortized. O(1) actual.

This does not make much sense.  Typo?

-- 
Florian Weimer / Red Hat Product Security

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose.
  2014-11-13 20:39 ` [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose mliska
  2014-11-14  4:32   ` Jeff Law
@ 2014-11-19 18:42   ` H.J. Lu
  1 sibling, 0 replies; 38+ messages in thread
From: H.J. Lu @ 2014-11-19 18:42 UTC (permalink / raw)
  To: mliska; +Cc: GCC Patches

On Wed, Nov 12, 2014 at 5:45 PM, mliska <mliska@suse.cz> wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
>         * bb-reorder.c (mark_bb_visited): New fibonacci_heap is used.
>         (find_traces): Likewise.
>         (find_traces_1_round): Likewise.

This caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63968


-- 
H.J.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-14 10:58   ` Richard Biener
@ 2014-11-21 11:30     ` Martin Liška
  2014-11-21 12:18       ` Richard Biener
  0 siblings, 1 reply; 38+ messages in thread
From: Martin Liška @ 2014-11-21 11:30 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 13658 bytes --]

On 11/14/2014 11:48 AM, Richard Biener wrote:
> On Thu, Nov 13, 2014 at 1:35 PM, mliska <mliska@suse.cz> wrote:
>> gcc/ChangeLog:
>>
>> 2014-11-13  Martin Liska  <mliska@suse.cz>
>>
>>          * predict.c (propagate_freq): More elegant sreal API is used.
>>          (estimate_bb_frequencies): New static constants defined by sreal
>>          replace precomputed ones.
>>          * sreal.c (sreal::normalize): New function.
>>          (sreal::to_int): Likewise.
>>          (sreal::operator+): Likewise.
>>          (sreal::operator-): Likewise.
>>          * sreal.h: Definition of new functions added.
>
> Please use gcc_checking_assert()s everywhere.  sreal is supposed
> to be fast... (I see it has current uses of gcc_assert - you may want
> to mass-convert them as a followup).
>
>> ---
>>   gcc/predict.c | 30 +++++++++++-------------
>>   gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
>>   gcc/sreal.h   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>>   3 files changed, 126 insertions(+), 35 deletions(-)
>>
>> diff --git a/gcc/predict.c b/gcc/predict.c
>> index 0215e91..0f640f5 100644
>> --- a/gcc/predict.c
>> +++ b/gcc/predict.c
>> @@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
>>
>>   /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
>>                     1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
>> -static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
>> +static sreal real_almost_one, real_br_prob_base,
>>               real_inv_br_prob_base, real_one_half, real_bb_freq_max;
>>
>>   static void combine_predictions_for_insn (rtx_insn *, basic_block);
>> @@ -2528,13 +2528,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>>          bb->count = bb->frequency = 0;
>>       }
>>
>> -  BLOCK_INFO (head)->frequency = real_one;
>> +  BLOCK_INFO (head)->frequency = sreal::one ();
>>     last = head;
>>     for (bb = head; bb; bb = nextbb)
>>       {
>>         edge_iterator ei;
>> -      sreal cyclic_probability = real_zero;
>> -      sreal frequency = real_zero;
>> +      sreal cyclic_probability = sreal::zero ();
>> +      sreal frequency = sreal::zero ();
>>
>>         nextbb = BLOCK_INFO (bb)->next;
>>         BLOCK_INFO (bb)->next = NULL;
>> @@ -2559,13 +2559,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>>                                    * BLOCK_INFO (e->src)->frequency /
>>                                    REG_BR_PROB_BASE);  */
>>
>> -               sreal tmp (e->probability, 0);
>> +               sreal tmp = e->probability;
>>                  tmp *= BLOCK_INFO (e->src)->frequency;
>>                  tmp *= real_inv_br_prob_base;
>>                  frequency += tmp;
>>                }
>>
>> -         if (cyclic_probability == real_zero)
>> +         if (cyclic_probability == sreal::zero ())
>>              {
>>                BLOCK_INFO (bb)->frequency = frequency;
>>              }
>> @@ -2577,7 +2577,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>>                /* BLOCK_INFO (bb)->frequency = frequency
>>                                                / (1 - cyclic_probability) */
>>
>> -             cyclic_probability = real_one - cyclic_probability;
>> +             cyclic_probability = sreal::one () - cyclic_probability;
>>                BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
>>              }
>>          }
>> @@ -2591,7 +2591,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>>               = ((e->probability * BLOCK_INFO (bb)->frequency)
>>               / REG_BR_PROB_BASE); */
>>
>> -         sreal tmp (e->probability, 0);
>> +         sreal tmp = e->probability;
>>            tmp *= BLOCK_INFO (bb)->frequency;
>>            EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
>>          }
>> @@ -2873,13 +2873,11 @@ estimate_bb_frequencies (bool force)
>>         if (!real_values_initialized)
>>           {
>>            real_values_initialized = 1;
>> -         real_zero = sreal (0, 0);
>> -         real_one = sreal (1, 0);
>> -         real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
>> -         real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
>> +         real_br_prob_base = REG_BR_PROB_BASE;
>> +         real_bb_freq_max = BB_FREQ_MAX;
>>            real_one_half = sreal (1, -1);
>> -         real_inv_br_prob_base = real_one / real_br_prob_base;
>> -         real_almost_one = real_one - real_inv_br_prob_base;
>> +         real_inv_br_prob_base = sreal::one () / real_br_prob_base;
>> +         real_almost_one = sreal::one () - real_inv_br_prob_base;
>>          }
>>
>>         mark_dfs_back_edges ();
>> @@ -2897,7 +2895,7 @@ estimate_bb_frequencies (bool force)
>>
>>            FOR_EACH_EDGE (e, ei, bb->succs)
>>              {
>> -             EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
>> +             EDGE_INFO (e)->back_edge_prob = e->probability;
>>                EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
>>              }
>>          }
>> @@ -2906,7 +2904,7 @@ estimate_bb_frequencies (bool force)
>>            to outermost to examine frequencies for back edges.  */
>>         estimate_loops ();
>>
>> -      freq_max = real_zero;
>> +      freq_max = sreal::zero ();
>>         FOR_EACH_BB_FN (bb, cfun)
>>          if (freq_max < BLOCK_INFO (bb)->frequency)
>>            freq_max = BLOCK_INFO (bb)->frequency;
>> diff --git a/gcc/sreal.c b/gcc/sreal.c
>> index 3f5456a..89b9c4d 100644
>> --- a/gcc/sreal.c
>> +++ b/gcc/sreal.c
>> @@ -1,4 +1,4 @@
>> -/* Simple data type for positive real numbers for the GNU compiler.
>> +/* Simple data type for real numbers for the GNU compiler.
>>      Copyright (C) 2002-2014 Free Software Foundation, Inc.
>>
>>   This file is part of GCC.
>> @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
>>   along with GCC; see the file COPYING3.  If not see
>>   <http://www.gnu.org/licenses/>.  */
>>
>> -/* This library supports positive real numbers and 0;
>> +/* This library supports real numbers;
>>      inf and nan are NOT supported.
>>      It is written to be simple and fast.
>>
>> @@ -102,6 +102,7 @@ sreal::normalize ()
>>   {
>>     if (m_sig == 0)
>>       {
>> +      m_negative = 0;
>>         m_exp = -SREAL_MAX_EXP;
>>       }
>>     else if (m_sig < SREAL_MIN_SIG)
>> @@ -153,15 +154,17 @@ sreal::normalize ()
>>   int64_t
>>   sreal::to_int () const
>>   {
>> +  int64_t sign = m_negative ? -1 : 1;
>> +
>>     if (m_exp <= -SREAL_BITS)
>>       return 0;
>>     if (m_exp >= SREAL_PART_BITS)
>> -    return INTTYPE_MAXIMUM (int64_t);
>> +    return sign * INTTYPE_MAXIMUM (int64_t);
>>     if (m_exp > 0)
>> -    return m_sig << m_exp;
>> +    return sign * (m_sig << m_exp);
>>     if (m_exp < 0)
>> -    return m_sig >> -m_exp;
>> -  return m_sig;
>> +    return sign * (m_sig >> -m_exp);
>> +  return sign * m_sig;
>>   }
>>
>>   /* Return *this + other.  */
>> @@ -169,9 +172,19 @@ sreal::to_int () const
>>   sreal
>>   sreal::operator+ (const sreal &other) const
>>   {
>> +  const sreal *a_p = this, *b_p = &other, *bb;
>> +
>> +  if (m_negative && !other.m_negative)
>> +    return other + *a_p;
>> +
>> +  if (!m_negative && other.m_negative)
>> +    return *a_p - -other;
>> +
>> +  gcc_assert (m_negative == other.m_negative);
>> +
>>     int dexp;
>>     sreal tmp, r;
>> -const sreal *a_p = this, *b_p = &other, *bb;
>> +  r.m_negative = a_p->m_negative;
>>
>>     if (*a_p < *b_p)
>>       {
>> @@ -211,10 +224,30 @@ sreal::operator- (const sreal &other) const
>>     int dexp;
>>     sreal tmp, r;
>>     const sreal *bb;
>> +  const sreal *a_p = this;
>> +
>> +  /* -a - b => -a + (-b).  */
>> +  if (m_negative && !other.m_negative)
>> +    return *a_p + -other;
>>
>> -  gcc_assert (*this >= other);
>> +  /* a - (-b) => a + b.  */
>> +  if (!m_negative && other.m_negative)
>> +    return *a_p + -other;
>> +
>> +  gcc_assert (m_negative == other.m_negative);
>> +
>> +  /* We want to substract a smaller number from bigger
>> +    for nonegative numbers.  */
>> +  if (!m_negative && *this < other)
>> +    return -(other - *this);
>> +
>> +  /* Example: -2 - (-3) => 3 - 2 */
>> +  if (m_negative && *this > other)
>> +    return -other - -(*this);
>>
>>     dexp = m_exp - other.m_exp;
>> +
>> +  r.m_negative = m_negative;
>>     r.m_exp = m_exp;
>>     if (dexp > SREAL_BITS)
>>       {
>> @@ -240,7 +273,7 @@ sreal::operator- (const sreal &other) const
>>   sreal
>>   sreal::operator* (const sreal &other) const
>>   {
>> -sreal r;
>> +  sreal r;
>>     if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
>>       {
>>         r.m_sig = 0;
>> @@ -252,6 +285,8 @@ sreal r;
>>         r.m_exp = m_exp + other.m_exp;
>>         r.normalize ();
>>       }
>> +
>> +  r.m_negative = m_negative ^ other.m_negative;
>>     return r;
>>   }
>>
>> @@ -261,9 +296,10 @@ sreal
>>   sreal::operator/ (const sreal &other) const
>>   {
>>     gcc_assert (other.m_sig != 0);
>> -sreal r;
>> +  sreal r;
>>     r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
>>     r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
>> +  r.m_negative = m_negative ^ other.m_negative;
>>     r.normalize ();
>>     return r;
>>   }
>> diff --git a/gcc/sreal.h b/gcc/sreal.h
>> index 461e28b..bfed3c7 100644
>> --- a/gcc/sreal.h
>> +++ b/gcc/sreal.h
>> @@ -1,4 +1,4 @@
>> -/* Definitions for simple data type for positive real numbers.
>> +/* Definitions for simple data type for real numbers.
>>      Copyright (C) 2002-2014 Free Software Foundation, Inc.
>>
>>   This file is part of GCC.
>> @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
>>
>>   #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>   #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>
>>   #define SREAL_BITS SREAL_PART_BITS
>>
>> @@ -34,10 +34,21 @@ class sreal
>>   {
>>   public:
>>     /* Construct an uninitialized sreal.  */
>> -  sreal () : m_sig (-1), m_exp (-1) {}
>> +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
>>
>>     /* Construct a sreal.  */
>> -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
>> +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
>> +  {
>> +    m_negative = sig < 0;
>> +
>> +    // TODO: speed up
>> +    if (sig < 0)
>> +      sig = -sig;
>
> also undefined behavior for sig == int64_min ...
>
>> +
>> +    m_sig = (uint64_t) sig;
>
> any reason for not making m_sig signed and using the sign of m_sig
> as sign of the sreal?
>
>> +
>> +    normalize ();
>> +  }
>>
>>     void dump (FILE *) const;
>>     int64_t to_int () const;
>> @@ -49,13 +60,58 @@ public:
>>
>>     bool operator< (const sreal &other) const
>>     {
>> -    return m_exp < other.m_exp
>> +    if (m_negative != other.m_negative)
>> +      return m_negative > other.m_negative;
>> +
>> +    bool r = m_exp < other.m_exp
>>         || (m_exp == other.m_exp && m_sig < other.m_sig);
>> +
>> +    return m_negative ? !r : r;
>>     }
>>
>>     bool operator== (const sreal &other) const
>>     {
>> -    return m_exp == other.m_exp && m_sig == other.m_sig;
>> +    return m_exp == other.m_exp && m_sig == other.m_sig
>> +                   && m_negative == other.m_negative;
>> +  }
>> +
>> +  sreal operator- () const
>> +  {
>> +    if (m_sig == 0)
>> +      return *this;
>> +
>> +    sreal tmp = *this;
>> +    tmp.m_negative = !tmp.m_negative;
>> +
>> +    return tmp;
>> +  }
>> +
>> +  sreal shift (int sig) const
>> +  {
>> +    sreal tmp = *this;
>> +    tmp.m_sig += sig;
>> +
>> +    return tmp;
>> +  }
>> +
>> +  /* Return zero constant.  */
>> +  inline static sreal zero ()
>> +  {
>> +    static const sreal zero = sreal (0);
>> +    return zero;
>> +  }
>> +
>> +  /* Return one constant.  */
>> +  inline static sreal one ()
>> +  {
>> +    static const sreal one = sreal (1);
>> +    return one;
>> +  }
>> +
>> +  /* Global minimum sreal can hold.  */
>> +  inline static sreal min ()
>> +  {
>> +    return sreal (LONG_MIN, 0);
>>     }
>>
>>   private:
>> @@ -63,7 +119,8 @@ private:
>>     void shift_right (int amount);
>>
>>     uint64_t m_sig;              /* Significant.  */
>> -  signed int m_exp;                    /* Exponent.  */
>> +  signed int m_exp: 31;                /* Exponent.  */
>> +  unsigned int m_negative: 1;  /* Negative sign.  */
>
> As this gets padded to 2 * 64bits I wonder if it is necessary to
> get the slowdowns for using bitfields here.  I'd have just used
>
>    uint64_t m_sig;               /* Significant.  */
>    signed int m_exp;                     /* Exponent.  */
>    bool m_negative;
>
> or making m_sig signed...
>
> Thanks,
> Richard.

Hello.

I tries to fix all notes I was given in this thread. There's list of 
updates:
1) signedless_{plus}|{minus} was introduced and there's no more 
recursion coming from operator+|-.
2) Bitfields are not used.
3) New function to_double is added.
4) gcc_assert is converted to gcc_checking_assert.

With having this patch applied I was able to reach the same time 
(difference is in noise level) for Inkscape WPA phase.

What do you think about it?

Thanks,
Martin

>>   };
>>
>>   extern void debug (sreal &ref);
>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
>>
>>   inline sreal &operator-= (sreal &a, const sreal &b)
>>   {
>> -return a = a - b;
>> +  return a = a - b;
>>   }
>>
>>   inline sreal &operator/= (sreal &a, const sreal &b)
>>   {
>> -return a = a / b;
>> +  return a = a / b;
>>   }
>>
>>   inline sreal &operator*= (sreal &a, const sreal &b)
>> --
>> 2.1.2
>>
>>


[-- Attachment #2: sreal-v2.patch --]
[-- Type: text/x-patch, Size: 13557 bytes --]

diff --git a/gcc/predict.c b/gcc/predict.c
index 779af11..5b4c186 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
 		   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
-static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
+static sreal real_almost_one, real_br_prob_base,
 	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
 static void combine_predictions_for_insn (rtx_insn *, basic_block);
@@ -2541,13 +2541,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 	bb->count = bb->frequency = 0;
     }
 
-  BLOCK_INFO (head)->frequency = real_one;
+  BLOCK_INFO (head)->frequency = sreal::one ();
   last = head;
   for (bb = head; bb; bb = nextbb)
     {
       edge_iterator ei;
-      sreal cyclic_probability = real_zero;
-      sreal frequency = real_zero;
+      sreal cyclic_probability = sreal::zero ();
+      sreal frequency = sreal::zero ();
 
       nextbb = BLOCK_INFO (bb)->next;
       BLOCK_INFO (bb)->next = NULL;
@@ -2572,13 +2572,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 				  * BLOCK_INFO (e->src)->frequency /
 				  REG_BR_PROB_BASE);  */
 
-		sreal tmp (e->probability, 0);
+		sreal tmp = e->probability;
 		tmp *= BLOCK_INFO (e->src)->frequency;
 		tmp *= real_inv_br_prob_base;
 		frequency += tmp;
 	      }
 
-	  if (cyclic_probability == real_zero)
+	  if (cyclic_probability == sreal::zero ())
 	    {
 	      BLOCK_INFO (bb)->frequency = frequency;
 	    }
@@ -2590,7 +2590,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	      /* BLOCK_INFO (bb)->frequency = frequency
 					      / (1 - cyclic_probability) */
 
-	      cyclic_probability = real_one - cyclic_probability;
+	      cyclic_probability = sreal::one () - cyclic_probability;
 	      BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
 	    }
 	}
@@ -2604,7 +2604,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	     = ((e->probability * BLOCK_INFO (bb)->frequency)
 	     / REG_BR_PROB_BASE); */
 
-	  sreal tmp (e->probability, 0);
+	  sreal tmp = e->probability;
 	  tmp *= BLOCK_INFO (bb)->frequency;
 	  EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
 	}
@@ -2886,13 +2886,11 @@ estimate_bb_frequencies (bool force)
       if (!real_values_initialized)
         {
 	  real_values_initialized = 1;
-	  real_zero = sreal (0, 0);
-	  real_one = sreal (1, 0);
-	  real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
-	  real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
+	  real_br_prob_base = REG_BR_PROB_BASE;
+	  real_bb_freq_max = BB_FREQ_MAX;
 	  real_one_half = sreal (1, -1);
-	  real_inv_br_prob_base = real_one / real_br_prob_base;
-	  real_almost_one = real_one - real_inv_br_prob_base;
+	  real_inv_br_prob_base = sreal::one () / real_br_prob_base;
+	  real_almost_one = sreal::one () - real_inv_br_prob_base;
 	}
 
       mark_dfs_back_edges ();
@@ -2910,7 +2908,7 @@ estimate_bb_frequencies (bool force)
 
 	  FOR_EACH_EDGE (e, ei, bb->succs)
 	    {
-	      EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
+	      EDGE_INFO (e)->back_edge_prob = e->probability;
 	      EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
 	    }
 	}
@@ -2919,7 +2917,7 @@ estimate_bb_frequencies (bool force)
          to outermost to examine frequencies for back edges.  */
       estimate_loops ();
 
-      freq_max = real_zero;
+      freq_max = sreal::zero ();
       FOR_EACH_BB_FN (bb, cfun)
 	if (freq_max < BLOCK_INFO (bb)->frequency)
 	  freq_max = BLOCK_INFO (bb)->frequency;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 3f5456a..a581bed 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -1,4 +1,4 @@
-/* Simple data type for positive real numbers for the GNU compiler.
+/* Simple data type for real numbers for the GNU compiler.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* This library supports positive real numbers and 0;
+/* This library supports real numbers;
    inf and nan are NOT supported.
    It is written to be simple and fast.
 
@@ -82,12 +82,12 @@ debug (sreal *ptr)
 void
 sreal::shift_right (int s)
 {
-  gcc_assert (s > 0);
-  gcc_assert (s <= SREAL_BITS);
+  gcc_checking_assert (s > 0);
+  gcc_checking_assert (s <= SREAL_BITS);
   /* Exponent should never be so large because shift_right is used only by
      sreal_add and sreal_sub ant thus the number cannot be shifted out from
      exponent range.  */
-  gcc_assert (m_exp + s <= SREAL_MAX_EXP);
+  gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
 
   m_exp += s;
 
@@ -102,6 +102,7 @@ sreal::normalize ()
 {
   if (m_sig == 0)
     {
+      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
   else if (m_sig < SREAL_MIN_SIG)
@@ -153,15 +154,64 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
+  int64_t sign = m_negative ? -1 : 1;
+
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
-    return INTTYPE_MAXIMUM (int64_t);
+    return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return m_sig << m_exp;
+    return sign * (m_sig << m_exp);
   if (m_exp < 0)
-    return m_sig >> -m_exp;
-  return m_sig;
+    return sign * (m_sig >> -m_exp);
+  return sign * m_sig;
+}
+
+/* Return double value of *this.   */
+double
+sreal::to_double () const
+{
+  int64_t sign = m_negative ? -1 : 1;
+  int64_t exp = m_exp;
+
+  if (m_exp > 0)
+    {
+      double d = m_sig;
+      while (exp != 0)
+        {
+	  if (exp > UINT64_BITS)
+	    {
+	      d *= INTTYPE_MAXIMUM (uint64_t);
+	      exp -= UINT64_BITS;
+	    }
+	  else
+	    {
+	      d *= ((uint64_t)1 << exp);
+	      exp = 0;
+	    }
+	}
+
+      return (double)sign * d;
+    }
+  if (exp < 0)
+    {
+      double d = m_sig;
+      while (exp != 0)
+        {
+	  if (exp < -UINT64_BITS)
+	    {
+	      d /= INTTYPE_MAXIMUM (uint64_t);
+	      exp += UINT64_BITS;
+	    }
+	  else
+	    {
+	      d /= ((uint64_t)1 << -exp);
+	      exp = 0;
+	    }
+	}
+      return (double)sign * d;
+    }
+  return (double)sign * m_sig;
 }
 
 /* Return *this + other.  */
@@ -169,18 +219,40 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
-  int dexp;
-  sreal tmp, r;
-const sreal *a_p = this, *b_p = &other, *bb;
+  const sreal *a_p = this, *b_p = &other;
 
-  if (*a_p < *b_p)
+  if (a_p->m_negative && !b_p->m_negative)
+    std::swap (a_p, b_p);
+
+  /* a + -b => a - b.  */
+  if (!a_p->m_negative && b_p->m_negative)
     {
-      const sreal *swap;
-      swap = a_p;
-      a_p = b_p;
-      b_p = swap;
+      sreal tmp = -(*b_p);
+      if (*a_p < tmp)
+	return signedless_minus (tmp, *a_p, false);
+      else
+	return signedless_minus (*a_p, tmp, true);
     }
 
+  gcc_checking_assert (a_p->m_negative == b_p->m_negative);
+
+  sreal r = signedless_plus (*a_p, *b_p, a_p->m_negative);
+
+  return r;
+}
+
+sreal
+sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
+{
+  const sreal *bb;
+  sreal r, tmp;
+  int dexp;
+  const sreal *a_p = &a;
+  const sreal *b_p = &b;
+
+  if (*a_p < *b_p)
+    std::swap (a_p, b_p);
+
   dexp = a_p->m_exp - b_p->m_exp;
   r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
@@ -200,6 +272,8 @@ const sreal *a_p = this, *b_p = &other, *bb;
 
   r.m_sig = a_p->m_sig + bb->m_sig;
   r.normalize ();
+
+  r.m_negative = negative;
   return r;
 }
 
@@ -208,30 +282,60 @@ const sreal *a_p = this, *b_p = &other, *bb;
 sreal
 sreal::operator- (const sreal &other) const
 {
+  /* -a - b => -a + (-b).  */
+  if (m_negative && !other.m_negative)
+    return signedless_plus (*this, -other, true);
+
+  /* a - (-b) => a + b.  */
+  if (!m_negative && other.m_negative)
+    return signedless_plus (*this, -other, false);
+
+  gcc_checking_assert (m_negative == other.m_negative);
+
+  /* We want to substract a smaller number from bigger
+    for nonegative numbers.  */
+  if (!m_negative && *this < other)
+    return -signedless_minus (other, *this, true);
+
+  /* Example: -2 - (-3) => 3 - 2 */
+  if (m_negative && *this > other)
+    return signedless_minus (-other, -(*this), true);
+
+  sreal r = signedless_minus (*this, other, m_negative);
+
+  return r;
+}
+
+sreal
+sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
+{
   int dexp;
   sreal tmp, r;
   const sreal *bb;
+  const sreal *a_p = &a;
+  const sreal *b_p = &b;
 
-  gcc_assert (*this >= other);
+  dexp = a_p->m_exp - b_p->m_exp;
 
-  dexp = m_exp - other.m_exp;
-  r.m_exp = m_exp;
+  r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
     {
-      r.m_sig = m_sig;
+      r.m_sig = a_p->m_sig;
       return r;
     }
   if (dexp == 0)
-    bb = &other;
+    bb = b_p;
   else
     {
-      tmp = other;
+      tmp = *b_p;
       tmp.shift_right (dexp);
       bb = &tmp;
     }
 
-  r.m_sig = m_sig - bb->m_sig;
+  r.m_sig = a_p->m_sig - bb->m_sig;
   r.normalize ();
+
+  r.m_negative = negative;
   return r;
 }
 
@@ -240,7 +344,7 @@ sreal::operator- (const sreal &other) const
 sreal
 sreal::operator* (const sreal &other) const
 {
-sreal r;
+  sreal r;
   if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
@@ -252,6 +356,8 @@ sreal r;
       r.m_exp = m_exp + other.m_exp;
       r.normalize ();
     }
+
+  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -260,10 +366,11 @@ sreal r;
 sreal
 sreal::operator/ (const sreal &other) const
 {
-  gcc_assert (other.m_sig != 0);
-sreal r;
+  gcc_checking_assert (other.m_sig != 0);
+  sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
+  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 461e28b..de8aa9c 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -1,4 +1,4 @@
-/* Definitions for simple data type for positive real numbers.
+/* Definitions for simple data type for real numbers.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,9 +23,11 @@ along with GCC; see the file COPYING3.  If not see
 /* SREAL_PART_BITS has to be an even number.  */
 #define SREAL_PART_BITS 32
 
+#define UINT64_BITS	64
+
 #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
 #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
-#define SREAL_MAX_EXP (INT_MAX / 4)
+#define SREAL_MAX_EXP (INT_MAX / 8)
 
 #define SREAL_BITS SREAL_PART_BITS
 
@@ -34,13 +36,24 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1) {}
+  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
 
   /* Construct a sreal.  */
-  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
+  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  {
+    m_negative = sig < 0;
+
+    if (sig < 0)
+      sig = -sig;
+
+    m_sig = (uint64_t) sig;
+
+    normalize ();
+  }
 
   void dump (FILE *) const;
   int64_t to_int () const;
+  double to_double () const;
 
   sreal operator+ (const sreal &other) const;
   sreal operator- (const sreal &other) const;
@@ -49,21 +62,70 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    return m_exp < other.m_exp
+    if (m_negative != other.m_negative)
+      return m_negative > other.m_negative;
+
+    bool r = m_exp < other.m_exp
       || (m_exp == other.m_exp && m_sig < other.m_sig);
+
+    return m_negative ? !r : r;
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig;
+    return m_exp == other.m_exp && m_sig == other.m_sig
+		    && m_negative == other.m_negative;
+  }
+
+  sreal operator- () const
+  {
+    if (m_sig == 0)
+      return *this;
+
+    sreal tmp = *this;
+    tmp.m_negative = !tmp.m_negative;
+
+    return tmp;
+  }
+
+  sreal shift (int sig) const
+  {
+    sreal tmp = *this;
+    tmp.m_sig += sig;
+
+    return tmp;
+  }
+
+  /* Return zero constant.  */
+  inline static sreal zero ()
+  {
+    static const sreal zero = sreal (0);
+    return zero;
+  }
+
+  /* Return one constant.  */
+  inline static sreal one ()
+  {
+    static const sreal one = sreal (1);
+    return one;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal min ()
+  {
+    return sreal (LONG_MIN, 0);
   }
 
 private:
   void normalize ();
   void shift_right (int amount);
 
-  uint64_t m_sig;		/* Significant.  */
+  static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
+  static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
+
+  uint64_t m_sig;			/* Significant.  */
   signed int m_exp;			/* Exponent.  */
+  bool m_negative;			/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
@@ -76,12 +138,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
 
 inline sreal &operator-= (sreal &a, const sreal &b)
 {
-return a = a - b;
+  return a = a - b;
 }
 
 inline sreal &operator/= (sreal &a, const sreal &b)
 {
-return a = a / b;
+  return a = a / b;
 }
 
 inline sreal &operator*= (sreal &a, const sreal &b)
@@ -109,4 +171,14 @@ inline bool operator>= (const sreal &a, const sreal &b)
   return a == b || a > b;
 }
 
+inline sreal operator<< (const sreal &a, int exp)
+{
+  return a.shift (exp);
+}
+
+inline sreal operator>> (const sreal &a, int exp)
+{
+  return a.shift (-exp);
+}
+
 #endif

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-21 11:30     ` Martin Liška
@ 2014-11-21 12:18       ` Richard Biener
  2014-11-21 15:34         ` Martin Liška
  0 siblings, 1 reply; 38+ messages in thread
From: Richard Biener @ 2014-11-21 12:18 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Fri, Nov 21, 2014 at 12:21 PM, Martin Liška <mliska@suse.cz> wrote:
> On 11/14/2014 11:48 AM, Richard Biener wrote:
>>
>> On Thu, Nov 13, 2014 at 1:35 PM, mliska <mliska@suse.cz> wrote:
>>>
>>> gcc/ChangeLog:
>>>
>>> 2014-11-13  Martin Liska  <mliska@suse.cz>
>>>
>>>          * predict.c (propagate_freq): More elegant sreal API is used.
>>>          (estimate_bb_frequencies): New static constants defined by sreal
>>>          replace precomputed ones.
>>>          * sreal.c (sreal::normalize): New function.
>>>          (sreal::to_int): Likewise.
>>>          (sreal::operator+): Likewise.
>>>          (sreal::operator-): Likewise.
>>>          * sreal.h: Definition of new functions added.
>>
>>
>> Please use gcc_checking_assert()s everywhere.  sreal is supposed
>> to be fast... (I see it has current uses of gcc_assert - you may want
>> to mass-convert them as a followup).
>>
>>> ---
>>>   gcc/predict.c | 30 +++++++++++-------------
>>>   gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
>>>   gcc/sreal.h   | 75
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>>>   3 files changed, 126 insertions(+), 35 deletions(-)
>>>
>>> diff --git a/gcc/predict.c b/gcc/predict.c
>>> index 0215e91..0f640f5 100644
>>> --- a/gcc/predict.c
>>> +++ b/gcc/predict.c
>>> @@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
>>>
>>>   /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
>>>                     1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
>>> -static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
>>> +static sreal real_almost_one, real_br_prob_base,
>>>               real_inv_br_prob_base, real_one_half, real_bb_freq_max;
>>>
>>>   static void combine_predictions_for_insn (rtx_insn *, basic_block);
>>> @@ -2528,13 +2528,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>          bb->count = bb->frequency = 0;
>>>       }
>>>
>>> -  BLOCK_INFO (head)->frequency = real_one;
>>> +  BLOCK_INFO (head)->frequency = sreal::one ();
>>>     last = head;
>>>     for (bb = head; bb; bb = nextbb)
>>>       {
>>>         edge_iterator ei;
>>> -      sreal cyclic_probability = real_zero;
>>> -      sreal frequency = real_zero;
>>> +      sreal cyclic_probability = sreal::zero ();
>>> +      sreal frequency = sreal::zero ();
>>>
>>>         nextbb = BLOCK_INFO (bb)->next;
>>>         BLOCK_INFO (bb)->next = NULL;
>>> @@ -2559,13 +2559,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>                                    * BLOCK_INFO (e->src)->frequency /
>>>                                    REG_BR_PROB_BASE);  */
>>>
>>> -               sreal tmp (e->probability, 0);
>>> +               sreal tmp = e->probability;
>>>                  tmp *= BLOCK_INFO (e->src)->frequency;
>>>                  tmp *= real_inv_br_prob_base;
>>>                  frequency += tmp;
>>>                }
>>>
>>> -         if (cyclic_probability == real_zero)
>>> +         if (cyclic_probability == sreal::zero ())
>>>              {
>>>                BLOCK_INFO (bb)->frequency = frequency;
>>>              }
>>> @@ -2577,7 +2577,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>                /* BLOCK_INFO (bb)->frequency = frequency
>>>                                                / (1 - cyclic_probability)
>>> */
>>>
>>> -             cyclic_probability = real_one - cyclic_probability;
>>> +             cyclic_probability = sreal::one () - cyclic_probability;
>>>                BLOCK_INFO (bb)->frequency = frequency /
>>> cyclic_probability;
>>>              }
>>>          }
>>> @@ -2591,7 +2591,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>               = ((e->probability * BLOCK_INFO (bb)->frequency)
>>>               / REG_BR_PROB_BASE); */
>>>
>>> -         sreal tmp (e->probability, 0);
>>> +         sreal tmp = e->probability;
>>>            tmp *= BLOCK_INFO (bb)->frequency;
>>>            EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
>>>          }
>>> @@ -2873,13 +2873,11 @@ estimate_bb_frequencies (bool force)
>>>         if (!real_values_initialized)
>>>           {
>>>            real_values_initialized = 1;
>>> -         real_zero = sreal (0, 0);
>>> -         real_one = sreal (1, 0);
>>> -         real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
>>> -         real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
>>> +         real_br_prob_base = REG_BR_PROB_BASE;
>>> +         real_bb_freq_max = BB_FREQ_MAX;
>>>            real_one_half = sreal (1, -1);
>>> -         real_inv_br_prob_base = real_one / real_br_prob_base;
>>> -         real_almost_one = real_one - real_inv_br_prob_base;
>>> +         real_inv_br_prob_base = sreal::one () / real_br_prob_base;
>>> +         real_almost_one = sreal::one () - real_inv_br_prob_base;
>>>          }
>>>
>>>         mark_dfs_back_edges ();
>>> @@ -2897,7 +2895,7 @@ estimate_bb_frequencies (bool force)
>>>
>>>            FOR_EACH_EDGE (e, ei, bb->succs)
>>>              {
>>> -             EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
>>> +             EDGE_INFO (e)->back_edge_prob = e->probability;
>>>                EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
>>>              }
>>>          }
>>> @@ -2906,7 +2904,7 @@ estimate_bb_frequencies (bool force)
>>>            to outermost to examine frequencies for back edges.  */
>>>         estimate_loops ();
>>>
>>> -      freq_max = real_zero;
>>> +      freq_max = sreal::zero ();
>>>         FOR_EACH_BB_FN (bb, cfun)
>>>          if (freq_max < BLOCK_INFO (bb)->frequency)
>>>            freq_max = BLOCK_INFO (bb)->frequency;
>>> diff --git a/gcc/sreal.c b/gcc/sreal.c
>>> index 3f5456a..89b9c4d 100644
>>> --- a/gcc/sreal.c
>>> +++ b/gcc/sreal.c
>>> @@ -1,4 +1,4 @@
>>> -/* Simple data type for positive real numbers for the GNU compiler.
>>> +/* Simple data type for real numbers for the GNU compiler.
>>>      Copyright (C) 2002-2014 Free Software Foundation, Inc.
>>>
>>>   This file is part of GCC.
>>> @@ -17,7 +17,7 @@ You should have received a copy of the GNU General
>>> Public License
>>>   along with GCC; see the file COPYING3.  If not see
>>>   <http://www.gnu.org/licenses/>.  */
>>>
>>> -/* This library supports positive real numbers and 0;
>>> +/* This library supports real numbers;
>>>      inf and nan are NOT supported.
>>>      It is written to be simple and fast.
>>>
>>> @@ -102,6 +102,7 @@ sreal::normalize ()
>>>   {
>>>     if (m_sig == 0)
>>>       {
>>> +      m_negative = 0;
>>>         m_exp = -SREAL_MAX_EXP;
>>>       }
>>>     else if (m_sig < SREAL_MIN_SIG)
>>> @@ -153,15 +154,17 @@ sreal::normalize ()
>>>   int64_t
>>>   sreal::to_int () const
>>>   {
>>> +  int64_t sign = m_negative ? -1 : 1;
>>> +
>>>     if (m_exp <= -SREAL_BITS)
>>>       return 0;
>>>     if (m_exp >= SREAL_PART_BITS)
>>> -    return INTTYPE_MAXIMUM (int64_t);
>>> +    return sign * INTTYPE_MAXIMUM (int64_t);
>>>     if (m_exp > 0)
>>> -    return m_sig << m_exp;
>>> +    return sign * (m_sig << m_exp);
>>>     if (m_exp < 0)
>>> -    return m_sig >> -m_exp;
>>> -  return m_sig;
>>> +    return sign * (m_sig >> -m_exp);
>>> +  return sign * m_sig;
>>>   }
>>>
>>>   /* Return *this + other.  */
>>> @@ -169,9 +172,19 @@ sreal::to_int () const
>>>   sreal
>>>   sreal::operator+ (const sreal &other) const
>>>   {
>>> +  const sreal *a_p = this, *b_p = &other, *bb;
>>> +
>>> +  if (m_negative && !other.m_negative)
>>> +    return other + *a_p;
>>> +
>>> +  if (!m_negative && other.m_negative)
>>> +    return *a_p - -other;
>>> +
>>> +  gcc_assert (m_negative == other.m_negative);
>>> +
>>>     int dexp;
>>>     sreal tmp, r;
>>> -const sreal *a_p = this, *b_p = &other, *bb;
>>> +  r.m_negative = a_p->m_negative;
>>>
>>>     if (*a_p < *b_p)
>>>       {
>>> @@ -211,10 +224,30 @@ sreal::operator- (const sreal &other) const
>>>     int dexp;
>>>     sreal tmp, r;
>>>     const sreal *bb;
>>> +  const sreal *a_p = this;
>>> +
>>> +  /* -a - b => -a + (-b).  */
>>> +  if (m_negative && !other.m_negative)
>>> +    return *a_p + -other;
>>>
>>> -  gcc_assert (*this >= other);
>>> +  /* a - (-b) => a + b.  */
>>> +  if (!m_negative && other.m_negative)
>>> +    return *a_p + -other;
>>> +
>>> +  gcc_assert (m_negative == other.m_negative);
>>> +
>>> +  /* We want to substract a smaller number from bigger
>>> +    for nonegative numbers.  */
>>> +  if (!m_negative && *this < other)
>>> +    return -(other - *this);
>>> +
>>> +  /* Example: -2 - (-3) => 3 - 2 */
>>> +  if (m_negative && *this > other)
>>> +    return -other - -(*this);
>>>
>>>     dexp = m_exp - other.m_exp;
>>> +
>>> +  r.m_negative = m_negative;
>>>     r.m_exp = m_exp;
>>>     if (dexp > SREAL_BITS)
>>>       {
>>> @@ -240,7 +273,7 @@ sreal::operator- (const sreal &other) const
>>>   sreal
>>>   sreal::operator* (const sreal &other) const
>>>   {
>>> -sreal r;
>>> +  sreal r;
>>>     if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
>>>       {
>>>         r.m_sig = 0;
>>> @@ -252,6 +285,8 @@ sreal r;
>>>         r.m_exp = m_exp + other.m_exp;
>>>         r.normalize ();
>>>       }
>>> +
>>> +  r.m_negative = m_negative ^ other.m_negative;
>>>     return r;
>>>   }
>>>
>>> @@ -261,9 +296,10 @@ sreal
>>>   sreal::operator/ (const sreal &other) const
>>>   {
>>>     gcc_assert (other.m_sig != 0);
>>> -sreal r;
>>> +  sreal r;
>>>     r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
>>>     r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
>>> +  r.m_negative = m_negative ^ other.m_negative;
>>>     r.normalize ();
>>>     return r;
>>>   }
>>> diff --git a/gcc/sreal.h b/gcc/sreal.h
>>> index 461e28b..bfed3c7 100644
>>> --- a/gcc/sreal.h
>>> +++ b/gcc/sreal.h
>>> @@ -1,4 +1,4 @@
>>> -/* Definitions for simple data type for positive real numbers.
>>> +/* Definitions for simple data type for real numbers.
>>>      Copyright (C) 2002-2014 Free Software Foundation, Inc.
>>>
>>>   This file is part of GCC.
>>> @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
>>>
>>>   #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>>   #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>>
>>>   #define SREAL_BITS SREAL_PART_BITS
>>>
>>> @@ -34,10 +34,21 @@ class sreal
>>>   {
>>>   public:
>>>     /* Construct an uninitialized sreal.  */
>>> -  sreal () : m_sig (-1), m_exp (-1) {}
>>> +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
>>>
>>>     /* Construct a sreal.  */
>>> -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize
>>> (); }
>>> +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
>>> +  {
>>> +    m_negative = sig < 0;
>>> +
>>> +    // TODO: speed up
>>> +    if (sig < 0)
>>> +      sig = -sig;
>>
>>
>> also undefined behavior for sig == int64_min ...
>>
>>> +
>>> +    m_sig = (uint64_t) sig;
>>
>>
>> any reason for not making m_sig signed and using the sign of m_sig
>> as sign of the sreal?
>>
>>> +
>>> +    normalize ();
>>> +  }
>>>
>>>     void dump (FILE *) const;
>>>     int64_t to_int () const;
>>> @@ -49,13 +60,58 @@ public:
>>>
>>>     bool operator< (const sreal &other) const
>>>     {
>>> -    return m_exp < other.m_exp
>>> +    if (m_negative != other.m_negative)
>>> +      return m_negative > other.m_negative;
>>> +
>>> +    bool r = m_exp < other.m_exp
>>>         || (m_exp == other.m_exp && m_sig < other.m_sig);
>>> +
>>> +    return m_negative ? !r : r;
>>>     }
>>>
>>>     bool operator== (const sreal &other) const
>>>     {
>>> -    return m_exp == other.m_exp && m_sig == other.m_sig;
>>> +    return m_exp == other.m_exp && m_sig == other.m_sig
>>> +                   && m_negative == other.m_negative;
>>> +  }
>>> +
>>> +  sreal operator- () const
>>> +  {
>>> +    if (m_sig == 0)
>>> +      return *this;
>>> +
>>> +    sreal tmp = *this;
>>> +    tmp.m_negative = !tmp.m_negative;
>>> +
>>> +    return tmp;
>>> +  }
>>> +
>>> +  sreal shift (int sig) const
>>> +  {
>>> +    sreal tmp = *this;
>>> +    tmp.m_sig += sig;
>>> +
>>> +    return tmp;
>>> +  }
>>> +
>>> +  /* Return zero constant.  */
>>> +  inline static sreal zero ()
>>> +  {
>>> +    static const sreal zero = sreal (0);
>>> +    return zero;
>>> +  }
>>> +
>>> +  /* Return one constant.  */
>>> +  inline static sreal one ()
>>> +  {
>>> +    static const sreal one = sreal (1);
>>> +    return one;
>>> +  }
>>> +
>>> +  /* Global minimum sreal can hold.  */
>>> +  inline static sreal min ()
>>> +  {
>>> +    return sreal (LONG_MIN, 0);
>>>     }
>>>
>>>   private:
>>> @@ -63,7 +119,8 @@ private:
>>>     void shift_right (int amount);
>>>
>>>     uint64_t m_sig;              /* Significant.  */
>>> -  signed int m_exp;                    /* Exponent.  */
>>> +  signed int m_exp: 31;                /* Exponent.  */
>>> +  unsigned int m_negative: 1;  /* Negative sign.  */
>>
>>
>> As this gets padded to 2 * 64bits I wonder if it is necessary to
>> get the slowdowns for using bitfields here.  I'd have just used
>>
>>    uint64_t m_sig;               /* Significant.  */
>>    signed int m_exp;                     /* Exponent.  */
>>    bool m_negative;
>>
>> or making m_sig signed...
>>
>> Thanks,
>> Richard.
>
>
> Hello.
>
> I tries to fix all notes I was given in this thread. There's list of
> updates:
> 1) signedless_{plus}|{minus} was introduced and there's no more recursion
> coming from operator+|-.
> 2) Bitfields are not used.
> 3) New function to_double is added.
> 4) gcc_assert is converted to gcc_checking_assert.
>
> With having this patch applied I was able to reach the same time (difference
> is in noise level) for Inkscape WPA phase.
>
> What do you think about it?

What's the point of sreal::zero and sreal::one when sreal (0) and
sreal (1) work and when you could add

  sreal& operator=(int64_t sig) { new sreal (this) (sig); }

?

+  /* Global minimum sreal can hold.  */
+  inline static sreal min ()
+  {
+    return sreal (LONG_MIN, 0);
   }

that's a  new API, right?  There is no max () and I think that using
LONG_MIN here is asking for trouble (host dependence).  The
comment in the file says the max should be
sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?

Where do you need sreal::to_double?  The host shouldn't perform
double calculations so it can be only for dumping?  In which case
the user should have used sreal::dump (), maybe with extra
arguments.

Otherwise looks good to me and sorry for not noticing the above
earlier.

Thanks,
Richard.

> Thanks,
> Martin
>
>
>>>   };
>>>
>>>   extern void debug (sreal &ref);
>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
>>>
>>>   inline sreal &operator-= (sreal &a, const sreal &b)
>>>   {
>>> -return a = a - b;
>>> +  return a = a - b;
>>>   }
>>>
>>>   inline sreal &operator/= (sreal &a, const sreal &b)
>>>   {
>>> -return a = a / b;
>>> +  return a = a / b;
>>>   }
>>>
>>>   inline sreal &operator*= (sreal &a, const sreal &b)
>>> --
>>> 2.1.2
>>>
>>>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-21 12:18       ` Richard Biener
@ 2014-11-21 15:34         ` Martin Liška
  2014-11-21 15:46           ` Richard Biener
  0 siblings, 1 reply; 38+ messages in thread
From: Martin Liška @ 2014-11-21 15:34 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 16070 bytes --]

On 11/21/2014 01:03 PM, Richard Biener wrote:
> On Fri, Nov 21, 2014 at 12:21 PM, Martin Liška <mliska@suse.cz> wrote:
>> On 11/14/2014 11:48 AM, Richard Biener wrote:
>>>
>>> On Thu, Nov 13, 2014 at 1:35 PM, mliska <mliska@suse.cz> wrote:
>>>>
>>>> gcc/ChangeLog:
>>>>
>>>> 2014-11-13  Martin Liska  <mliska@suse.cz>
>>>>
>>>>           * predict.c (propagate_freq): More elegant sreal API is used.
>>>>           (estimate_bb_frequencies): New static constants defined by sreal
>>>>           replace precomputed ones.
>>>>           * sreal.c (sreal::normalize): New function.
>>>>           (sreal::to_int): Likewise.
>>>>           (sreal::operator+): Likewise.
>>>>           (sreal::operator-): Likewise.
>>>>           * sreal.h: Definition of new functions added.
>>>
>>>
>>> Please use gcc_checking_assert()s everywhere.  sreal is supposed
>>> to be fast... (I see it has current uses of gcc_assert - you may want
>>> to mass-convert them as a followup).
>>>
>>>> ---
>>>>    gcc/predict.c | 30 +++++++++++-------------
>>>>    gcc/sreal.c   | 56 ++++++++++++++++++++++++++++++++++++--------
>>>>    gcc/sreal.h   | 75
>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>>>>    3 files changed, 126 insertions(+), 35 deletions(-)
>>>>
>>>> diff --git a/gcc/predict.c b/gcc/predict.c
>>>> index 0215e91..0f640f5 100644
>>>> --- a/gcc/predict.c
>>>> +++ b/gcc/predict.c
>>>> @@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
>>>>
>>>>    /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
>>>>                      1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
>>>> -static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
>>>> +static sreal real_almost_one, real_br_prob_base,
>>>>                real_inv_br_prob_base, real_one_half, real_bb_freq_max;
>>>>
>>>>    static void combine_predictions_for_insn (rtx_insn *, basic_block);
>>>> @@ -2528,13 +2528,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>>           bb->count = bb->frequency = 0;
>>>>        }
>>>>
>>>> -  BLOCK_INFO (head)->frequency = real_one;
>>>> +  BLOCK_INFO (head)->frequency = sreal::one ();
>>>>      last = head;
>>>>      for (bb = head; bb; bb = nextbb)
>>>>        {
>>>>          edge_iterator ei;
>>>> -      sreal cyclic_probability = real_zero;
>>>> -      sreal frequency = real_zero;
>>>> +      sreal cyclic_probability = sreal::zero ();
>>>> +      sreal frequency = sreal::zero ();
>>>>
>>>>          nextbb = BLOCK_INFO (bb)->next;
>>>>          BLOCK_INFO (bb)->next = NULL;
>>>> @@ -2559,13 +2559,13 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>>                                     * BLOCK_INFO (e->src)->frequency /
>>>>                                     REG_BR_PROB_BASE);  */
>>>>
>>>> -               sreal tmp (e->probability, 0);
>>>> +               sreal tmp = e->probability;
>>>>                   tmp *= BLOCK_INFO (e->src)->frequency;
>>>>                   tmp *= real_inv_br_prob_base;
>>>>                   frequency += tmp;
>>>>                 }
>>>>
>>>> -         if (cyclic_probability == real_zero)
>>>> +         if (cyclic_probability == sreal::zero ())
>>>>               {
>>>>                 BLOCK_INFO (bb)->frequency = frequency;
>>>>               }
>>>> @@ -2577,7 +2577,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>>                 /* BLOCK_INFO (bb)->frequency = frequency
>>>>                                                 / (1 - cyclic_probability)
>>>> */
>>>>
>>>> -             cyclic_probability = real_one - cyclic_probability;
>>>> +             cyclic_probability = sreal::one () - cyclic_probability;
>>>>                 BLOCK_INFO (bb)->frequency = frequency /
>>>> cyclic_probability;
>>>>               }
>>>>           }
>>>> @@ -2591,7 +2591,7 @@ propagate_freq (basic_block head, bitmap tovisit)
>>>>                = ((e->probability * BLOCK_INFO (bb)->frequency)
>>>>                / REG_BR_PROB_BASE); */
>>>>
>>>> -         sreal tmp (e->probability, 0);
>>>> +         sreal tmp = e->probability;
>>>>             tmp *= BLOCK_INFO (bb)->frequency;
>>>>             EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
>>>>           }
>>>> @@ -2873,13 +2873,11 @@ estimate_bb_frequencies (bool force)
>>>>          if (!real_values_initialized)
>>>>            {
>>>>             real_values_initialized = 1;
>>>> -         real_zero = sreal (0, 0);
>>>> -         real_one = sreal (1, 0);
>>>> -         real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
>>>> -         real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
>>>> +         real_br_prob_base = REG_BR_PROB_BASE;
>>>> +         real_bb_freq_max = BB_FREQ_MAX;
>>>>             real_one_half = sreal (1, -1);
>>>> -         real_inv_br_prob_base = real_one / real_br_prob_base;
>>>> -         real_almost_one = real_one - real_inv_br_prob_base;
>>>> +         real_inv_br_prob_base = sreal::one () / real_br_prob_base;
>>>> +         real_almost_one = sreal::one () - real_inv_br_prob_base;
>>>>           }
>>>>
>>>>          mark_dfs_back_edges ();
>>>> @@ -2897,7 +2895,7 @@ estimate_bb_frequencies (bool force)
>>>>
>>>>             FOR_EACH_EDGE (e, ei, bb->succs)
>>>>               {
>>>> -             EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
>>>> +             EDGE_INFO (e)->back_edge_prob = e->probability;
>>>>                 EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
>>>>               }
>>>>           }
>>>> @@ -2906,7 +2904,7 @@ estimate_bb_frequencies (bool force)
>>>>             to outermost to examine frequencies for back edges.  */
>>>>          estimate_loops ();
>>>>
>>>> -      freq_max = real_zero;
>>>> +      freq_max = sreal::zero ();
>>>>          FOR_EACH_BB_FN (bb, cfun)
>>>>           if (freq_max < BLOCK_INFO (bb)->frequency)
>>>>             freq_max = BLOCK_INFO (bb)->frequency;
>>>> diff --git a/gcc/sreal.c b/gcc/sreal.c
>>>> index 3f5456a..89b9c4d 100644
>>>> --- a/gcc/sreal.c
>>>> +++ b/gcc/sreal.c
>>>> @@ -1,4 +1,4 @@
>>>> -/* Simple data type for positive real numbers for the GNU compiler.
>>>> +/* Simple data type for real numbers for the GNU compiler.
>>>>       Copyright (C) 2002-2014 Free Software Foundation, Inc.
>>>>
>>>>    This file is part of GCC.
>>>> @@ -17,7 +17,7 @@ You should have received a copy of the GNU General
>>>> Public License
>>>>    along with GCC; see the file COPYING3.  If not see
>>>>    <http://www.gnu.org/licenses/>.  */
>>>>
>>>> -/* This library supports positive real numbers and 0;
>>>> +/* This library supports real numbers;
>>>>       inf and nan are NOT supported.
>>>>       It is written to be simple and fast.
>>>>
>>>> @@ -102,6 +102,7 @@ sreal::normalize ()
>>>>    {
>>>>      if (m_sig == 0)
>>>>        {
>>>> +      m_negative = 0;
>>>>          m_exp = -SREAL_MAX_EXP;
>>>>        }
>>>>      else if (m_sig < SREAL_MIN_SIG)
>>>> @@ -153,15 +154,17 @@ sreal::normalize ()
>>>>    int64_t
>>>>    sreal::to_int () const
>>>>    {
>>>> +  int64_t sign = m_negative ? -1 : 1;
>>>> +
>>>>      if (m_exp <= -SREAL_BITS)
>>>>        return 0;
>>>>      if (m_exp >= SREAL_PART_BITS)
>>>> -    return INTTYPE_MAXIMUM (int64_t);
>>>> +    return sign * INTTYPE_MAXIMUM (int64_t);
>>>>      if (m_exp > 0)
>>>> -    return m_sig << m_exp;
>>>> +    return sign * (m_sig << m_exp);
>>>>      if (m_exp < 0)
>>>> -    return m_sig >> -m_exp;
>>>> -  return m_sig;
>>>> +    return sign * (m_sig >> -m_exp);
>>>> +  return sign * m_sig;
>>>>    }
>>>>
>>>>    /* Return *this + other.  */
>>>> @@ -169,9 +172,19 @@ sreal::to_int () const
>>>>    sreal
>>>>    sreal::operator+ (const sreal &other) const
>>>>    {
>>>> +  const sreal *a_p = this, *b_p = &other, *bb;
>>>> +
>>>> +  if (m_negative && !other.m_negative)
>>>> +    return other + *a_p;
>>>> +
>>>> +  if (!m_negative && other.m_negative)
>>>> +    return *a_p - -other;
>>>> +
>>>> +  gcc_assert (m_negative == other.m_negative);
>>>> +
>>>>      int dexp;
>>>>      sreal tmp, r;
>>>> -const sreal *a_p = this, *b_p = &other, *bb;
>>>> +  r.m_negative = a_p->m_negative;
>>>>
>>>>      if (*a_p < *b_p)
>>>>        {
>>>> @@ -211,10 +224,30 @@ sreal::operator- (const sreal &other) const
>>>>      int dexp;
>>>>      sreal tmp, r;
>>>>      const sreal *bb;
>>>> +  const sreal *a_p = this;
>>>> +
>>>> +  /* -a - b => -a + (-b).  */
>>>> +  if (m_negative && !other.m_negative)
>>>> +    return *a_p + -other;
>>>>
>>>> -  gcc_assert (*this >= other);
>>>> +  /* a - (-b) => a + b.  */
>>>> +  if (!m_negative && other.m_negative)
>>>> +    return *a_p + -other;
>>>> +
>>>> +  gcc_assert (m_negative == other.m_negative);
>>>> +
>>>> +  /* We want to substract a smaller number from bigger
>>>> +    for nonegative numbers.  */
>>>> +  if (!m_negative && *this < other)
>>>> +    return -(other - *this);
>>>> +
>>>> +  /* Example: -2 - (-3) => 3 - 2 */
>>>> +  if (m_negative && *this > other)
>>>> +    return -other - -(*this);
>>>>
>>>>      dexp = m_exp - other.m_exp;
>>>> +
>>>> +  r.m_negative = m_negative;
>>>>      r.m_exp = m_exp;
>>>>      if (dexp > SREAL_BITS)
>>>>        {
>>>> @@ -240,7 +273,7 @@ sreal::operator- (const sreal &other) const
>>>>    sreal
>>>>    sreal::operator* (const sreal &other) const
>>>>    {
>>>> -sreal r;
>>>> +  sreal r;
>>>>      if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
>>>>        {
>>>>          r.m_sig = 0;
>>>> @@ -252,6 +285,8 @@ sreal r;
>>>>          r.m_exp = m_exp + other.m_exp;
>>>>          r.normalize ();
>>>>        }
>>>> +
>>>> +  r.m_negative = m_negative ^ other.m_negative;
>>>>      return r;
>>>>    }
>>>>
>>>> @@ -261,9 +296,10 @@ sreal
>>>>    sreal::operator/ (const sreal &other) const
>>>>    {
>>>>      gcc_assert (other.m_sig != 0);
>>>> -sreal r;
>>>> +  sreal r;
>>>>      r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
>>>>      r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
>>>> +  r.m_negative = m_negative ^ other.m_negative;
>>>>      r.normalize ();
>>>>      return r;
>>>>    }
>>>> diff --git a/gcc/sreal.h b/gcc/sreal.h
>>>> index 461e28b..bfed3c7 100644
>>>> --- a/gcc/sreal.h
>>>> +++ b/gcc/sreal.h
>>>> @@ -1,4 +1,4 @@
>>>> -/* Definitions for simple data type for positive real numbers.
>>>> +/* Definitions for simple data type for real numbers.
>>>>       Copyright (C) 2002-2014 Free Software Foundation, Inc.
>>>>
>>>>    This file is part of GCC.
>>>> @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
>>>>
>>>>    #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>>>    #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>>>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>>>
>>>>    #define SREAL_BITS SREAL_PART_BITS
>>>>
>>>> @@ -34,10 +34,21 @@ class sreal
>>>>    {
>>>>    public:
>>>>      /* Construct an uninitialized sreal.  */
>>>> -  sreal () : m_sig (-1), m_exp (-1) {}
>>>> +  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
>>>>
>>>>      /* Construct a sreal.  */
>>>> -  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize
>>>> (); }
>>>> +  sreal (int64_t sig, int exp = 0) : m_exp (exp)
>>>> +  {
>>>> +    m_negative = sig < 0;
>>>> +
>>>> +    // TODO: speed up
>>>> +    if (sig < 0)
>>>> +      sig = -sig;
>>>
>>>
>>> also undefined behavior for sig == int64_min ...
>>>
>>>> +
>>>> +    m_sig = (uint64_t) sig;
>>>
>>>
>>> any reason for not making m_sig signed and using the sign of m_sig
>>> as sign of the sreal?
>>>
>>>> +
>>>> +    normalize ();
>>>> +  }
>>>>
>>>>      void dump (FILE *) const;
>>>>      int64_t to_int () const;
>>>> @@ -49,13 +60,58 @@ public:
>>>>
>>>>      bool operator< (const sreal &other) const
>>>>      {
>>>> -    return m_exp < other.m_exp
>>>> +    if (m_negative != other.m_negative)
>>>> +      return m_negative > other.m_negative;
>>>> +
>>>> +    bool r = m_exp < other.m_exp
>>>>          || (m_exp == other.m_exp && m_sig < other.m_sig);
>>>> +
>>>> +    return m_negative ? !r : r;
>>>>      }
>>>>
>>>>      bool operator== (const sreal &other) const
>>>>      {
>>>> -    return m_exp == other.m_exp && m_sig == other.m_sig;
>>>> +    return m_exp == other.m_exp && m_sig == other.m_sig
>>>> +                   && m_negative == other.m_negative;
>>>> +  }
>>>> +
>>>> +  sreal operator- () const
>>>> +  {
>>>> +    if (m_sig == 0)
>>>> +      return *this;
>>>> +
>>>> +    sreal tmp = *this;
>>>> +    tmp.m_negative = !tmp.m_negative;
>>>> +
>>>> +    return tmp;
>>>> +  }
>>>> +
>>>> +  sreal shift (int sig) const
>>>> +  {
>>>> +    sreal tmp = *this;
>>>> +    tmp.m_sig += sig;
>>>> +
>>>> +    return tmp;
>>>> +  }
>>>> +
>>>> +  /* Return zero constant.  */
>>>> +  inline static sreal zero ()
>>>> +  {
>>>> +    static const sreal zero = sreal (0);
>>>> +    return zero;
>>>> +  }
>>>> +
>>>> +  /* Return one constant.  */
>>>> +  inline static sreal one ()
>>>> +  {
>>>> +    static const sreal one = sreal (1);
>>>> +    return one;
>>>> +  }
>>>> +
>>>> +  /* Global minimum sreal can hold.  */
>>>> +  inline static sreal min ()
>>>> +  {
>>>> +    return sreal (LONG_MIN, 0);
>>>>      }
>>>>
>>>>    private:
>>>> @@ -63,7 +119,8 @@ private:
>>>>      void shift_right (int amount);
>>>>
>>>>      uint64_t m_sig;              /* Significant.  */
>>>> -  signed int m_exp;                    /* Exponent.  */
>>>> +  signed int m_exp: 31;                /* Exponent.  */
>>>> +  unsigned int m_negative: 1;  /* Negative sign.  */
>>>
>>>
>>> As this gets padded to 2 * 64bits I wonder if it is necessary to
>>> get the slowdowns for using bitfields here.  I'd have just used
>>>
>>>     uint64_t m_sig;               /* Significant.  */
>>>     signed int m_exp;                     /* Exponent.  */
>>>     bool m_negative;
>>>
>>> or making m_sig signed...
>>>
>>> Thanks,
>>> Richard.
>>
>>
>> Hello.
>>
>> I tries to fix all notes I was given in this thread. There's list of
>> updates:
>> 1) signedless_{plus}|{minus} was introduced and there's no more recursion
>> coming from operator+|-.
>> 2) Bitfields are not used.
>> 3) New function to_double is added.
>> 4) gcc_assert is converted to gcc_checking_assert.
>>
>> With having this patch applied I was able to reach the same time (difference
>> is in noise level) for Inkscape WPA phase.
>>
>> What do you think about it?
>
> What's the point of sreal::zero and sreal::one when sreal (0) and
> sreal (1) work and when you could add
>
>    sreal& operator=(int64_t sig) { new sreal (this) (sig); }
>
> ?
>
> +  /* Global minimum sreal can hold.  */
> +  inline static sreal min ()
> +  {
> +    return sreal (LONG_MIN, 0);
>     }

Hello.

Ok, this is simplified, one can use sreal a = 12345 and it works ;)

> that's a  new API, right?  There is no max () and I think that using
> LONG_MIN here is asking for trouble (host dependence).  The
> comment in the file says the max should be
> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>

Sure, sreal can store much bigger(smaller) numbers :)

> Where do you need sreal::to_double?  The host shouldn't perform
> double calculations so it can be only for dumping?  In which case
> the user should have used sreal::dump (), maybe with extra
> arguments.
>

That new function was request from Honza, only for debugging purpose.
I agree that dump should this kind of job.

If no other problem, I will run tests once more and commit it.
Thanks,
Martin

> Otherwise looks good to me and sorry for not noticing the above
> earlier.
>
> Thanks,
> Richard.
>
>> Thanks,
>> Martin
>>
>>
>>>>    };
>>>>
>>>>    extern void debug (sreal &ref);
>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
>>>>
>>>>    inline sreal &operator-= (sreal &a, const sreal &b)
>>>>    {
>>>> -return a = a - b;
>>>> +  return a = a - b;
>>>>    }
>>>>
>>>>    inline sreal &operator/= (sreal &a, const sreal &b)
>>>>    {
>>>> -return a = a / b;
>>>> +  return a = a / b;
>>>>    }
>>>>
>>>>    inline sreal &operator*= (sreal &a, const sreal &b)
>>>> --
>>>> 2.1.2
>>>>
>>>>
>>


[-- Attachment #2: sreal-v3.patch --]
[-- Type: text/x-patch, Size: 13466 bytes --]

From 56e485026db94a8b226fc6af3d2bd4adbd26f9c4 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Fri, 21 Nov 2014 12:07:40 +0100
Subject: [PATCH 1/2] Negative numbers added for sreal class.

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* predict.c (propagate_freq): More elegant sreal API is used.
	(estimate_bb_frequencies): Precomputed constants replaced by integer
	constants.
	* sreal.c (sreal::normalize): New function.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	* sreal.h: Definition of new functions added.
---
 gcc/predict.c |  30 ++++++++--------
 gcc/sreal.c   | 114 ++++++++++++++++++++++++++++++++++++++++++++--------------
 gcc/sreal.h   |  84 +++++++++++++++++++++++++++++++++++++------
 3 files changed, 175 insertions(+), 53 deletions(-)

diff --git a/gcc/predict.c b/gcc/predict.c
index 779af11..0cfe4a9 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
 		   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
-static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
+static sreal real_almost_one, real_br_prob_base,
 	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
 static void combine_predictions_for_insn (rtx_insn *, basic_block);
@@ -2541,13 +2541,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 	bb->count = bb->frequency = 0;
     }
 
-  BLOCK_INFO (head)->frequency = real_one;
+  BLOCK_INFO (head)->frequency = 1;
   last = head;
   for (bb = head; bb; bb = nextbb)
     {
       edge_iterator ei;
-      sreal cyclic_probability = real_zero;
-      sreal frequency = real_zero;
+      sreal cyclic_probability = 0;
+      sreal frequency = 0;
 
       nextbb = BLOCK_INFO (bb)->next;
       BLOCK_INFO (bb)->next = NULL;
@@ -2572,13 +2572,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 				  * BLOCK_INFO (e->src)->frequency /
 				  REG_BR_PROB_BASE);  */
 
-		sreal tmp (e->probability, 0);
+		sreal tmp = e->probability;
 		tmp *= BLOCK_INFO (e->src)->frequency;
 		tmp *= real_inv_br_prob_base;
 		frequency += tmp;
 	      }
 
-	  if (cyclic_probability == real_zero)
+	  if (cyclic_probability == 0)
 	    {
 	      BLOCK_INFO (bb)->frequency = frequency;
 	    }
@@ -2590,7 +2590,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	      /* BLOCK_INFO (bb)->frequency = frequency
 					      / (1 - cyclic_probability) */
 
-	      cyclic_probability = real_one - cyclic_probability;
+	      cyclic_probability = sreal (1) - cyclic_probability;
 	      BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
 	    }
 	}
@@ -2604,7 +2604,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	     = ((e->probability * BLOCK_INFO (bb)->frequency)
 	     / REG_BR_PROB_BASE); */
 
-	  sreal tmp (e->probability, 0);
+	  sreal tmp = e->probability;
 	  tmp *= BLOCK_INFO (bb)->frequency;
 	  EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
 	}
@@ -2886,13 +2886,11 @@ estimate_bb_frequencies (bool force)
       if (!real_values_initialized)
         {
 	  real_values_initialized = 1;
-	  real_zero = sreal (0, 0);
-	  real_one = sreal (1, 0);
-	  real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
-	  real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
+	  real_br_prob_base = REG_BR_PROB_BASE;
+	  real_bb_freq_max = BB_FREQ_MAX;
 	  real_one_half = sreal (1, -1);
-	  real_inv_br_prob_base = real_one / real_br_prob_base;
-	  real_almost_one = real_one - real_inv_br_prob_base;
+	  real_inv_br_prob_base = sreal (1) / real_br_prob_base;
+	  real_almost_one = sreal (1) - real_inv_br_prob_base;
 	}
 
       mark_dfs_back_edges ();
@@ -2910,7 +2908,7 @@ estimate_bb_frequencies (bool force)
 
 	  FOR_EACH_EDGE (e, ei, bb->succs)
 	    {
-	      EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
+	      EDGE_INFO (e)->back_edge_prob = e->probability;
 	      EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
 	    }
 	}
@@ -2919,7 +2917,7 @@ estimate_bb_frequencies (bool force)
          to outermost to examine frequencies for back edges.  */
       estimate_loops ();
 
-      freq_max = real_zero;
+      freq_max = 0;
       FOR_EACH_BB_FN (bb, cfun)
 	if (freq_max < BLOCK_INFO (bb)->frequency)
 	  freq_max = BLOCK_INFO (bb)->frequency;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 3f5456a..0337f9e 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -1,4 +1,4 @@
-/* Simple data type for positive real numbers for the GNU compiler.
+/* Simple data type for real numbers for the GNU compiler.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* This library supports positive real numbers and 0;
+/* This library supports real numbers;
    inf and nan are NOT supported.
    It is written to be simple and fast.
 
@@ -82,12 +82,12 @@ debug (sreal *ptr)
 void
 sreal::shift_right (int s)
 {
-  gcc_assert (s > 0);
-  gcc_assert (s <= SREAL_BITS);
+  gcc_checking_assert (s > 0);
+  gcc_checking_assert (s <= SREAL_BITS);
   /* Exponent should never be so large because shift_right is used only by
      sreal_add and sreal_sub ant thus the number cannot be shifted out from
      exponent range.  */
-  gcc_assert (m_exp + s <= SREAL_MAX_EXP);
+  gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
 
   m_exp += s;
 
@@ -102,6 +102,7 @@ sreal::normalize ()
 {
   if (m_sig == 0)
     {
+      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
   else if (m_sig < SREAL_MIN_SIG)
@@ -153,15 +154,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
+  int64_t sign = m_negative ? -1 : 1;
+
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
-    return INTTYPE_MAXIMUM (int64_t);
+    return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return m_sig << m_exp;
+    return sign * (m_sig << m_exp);
   if (m_exp < 0)
-    return m_sig >> -m_exp;
-  return m_sig;
+    return sign * (m_sig >> -m_exp);
+  return sign * m_sig;
 }
 
 /* Return *this + other.  */
@@ -169,18 +172,40 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
-  int dexp;
-  sreal tmp, r;
-const sreal *a_p = this, *b_p = &other, *bb;
+  const sreal *a_p = this, *b_p = &other;
 
-  if (*a_p < *b_p)
+  if (a_p->m_negative && !b_p->m_negative)
+    std::swap (a_p, b_p);
+
+  /* a + -b => a - b.  */
+  if (!a_p->m_negative && b_p->m_negative)
     {
-      const sreal *swap;
-      swap = a_p;
-      a_p = b_p;
-      b_p = swap;
+      sreal tmp = -(*b_p);
+      if (*a_p < tmp)
+	return signedless_minus (tmp, *a_p, false);
+      else
+	return signedless_minus (*a_p, tmp, true);
     }
 
+  gcc_checking_assert (a_p->m_negative == b_p->m_negative);
+
+  sreal r = signedless_plus (*a_p, *b_p, a_p->m_negative);
+
+  return r;
+}
+
+sreal
+sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
+{
+  const sreal *bb;
+  sreal r, tmp;
+  int dexp;
+  const sreal *a_p = &a;
+  const sreal *b_p = &b;
+
+  if (*a_p < *b_p)
+    std::swap (a_p, b_p);
+
   dexp = a_p->m_exp - b_p->m_exp;
   r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
@@ -200,6 +225,8 @@ const sreal *a_p = this, *b_p = &other, *bb;
 
   r.m_sig = a_p->m_sig + bb->m_sig;
   r.normalize ();
+
+  r.m_negative = negative;
   return r;
 }
 
@@ -208,30 +235,60 @@ const sreal *a_p = this, *b_p = &other, *bb;
 sreal
 sreal::operator- (const sreal &other) const
 {
+  /* -a - b => -a + (-b).  */
+  if (m_negative && !other.m_negative)
+    return signedless_plus (*this, -other, true);
+
+  /* a - (-b) => a + b.  */
+  if (!m_negative && other.m_negative)
+    return signedless_plus (*this, -other, false);
+
+  gcc_checking_assert (m_negative == other.m_negative);
+
+  /* We want to substract a smaller number from bigger
+    for nonegative numbers.  */
+  if (!m_negative && *this < other)
+    return -signedless_minus (other, *this, true);
+
+  /* Example: -2 - (-3) => 3 - 2 */
+  if (m_negative && *this > other)
+    return signedless_minus (-other, -(*this), true);
+
+  sreal r = signedless_minus (*this, other, m_negative);
+
+  return r;
+}
+
+sreal
+sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
+{
   int dexp;
   sreal tmp, r;
   const sreal *bb;
+  const sreal *a_p = &a;
+  const sreal *b_p = &b;
 
-  gcc_assert (*this >= other);
+  dexp = a_p->m_exp - b_p->m_exp;
 
-  dexp = m_exp - other.m_exp;
-  r.m_exp = m_exp;
+  r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
     {
-      r.m_sig = m_sig;
+      r.m_sig = a_p->m_sig;
       return r;
     }
   if (dexp == 0)
-    bb = &other;
+    bb = b_p;
   else
     {
-      tmp = other;
+      tmp = *b_p;
       tmp.shift_right (dexp);
       bb = &tmp;
     }
 
-  r.m_sig = m_sig - bb->m_sig;
+  r.m_sig = a_p->m_sig - bb->m_sig;
   r.normalize ();
+
+  r.m_negative = negative;
   return r;
 }
 
@@ -240,7 +297,7 @@ sreal::operator- (const sreal &other) const
 sreal
 sreal::operator* (const sreal &other) const
 {
-sreal r;
+  sreal r;
   if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
@@ -252,6 +309,8 @@ sreal r;
       r.m_exp = m_exp + other.m_exp;
       r.normalize ();
     }
+
+  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -260,10 +319,11 @@ sreal r;
 sreal
 sreal::operator/ (const sreal &other) const
 {
-  gcc_assert (other.m_sig != 0);
-sreal r;
+  gcc_checking_assert (other.m_sig != 0);
+  sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
+  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 461e28b..e647c4c 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -1,4 +1,4 @@
-/* Definitions for simple data type for positive real numbers.
+/* Definitions for simple data type for real numbers.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,9 +23,11 @@ along with GCC; see the file COPYING3.  If not see
 /* SREAL_PART_BITS has to be an even number.  */
 #define SREAL_PART_BITS 32
 
+#define UINT64_BITS	64
+
 #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
 #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
-#define SREAL_MAX_EXP (INT_MAX / 4)
+#define SREAL_MAX_EXP (INT_MAX / 8)
 
 #define SREAL_BITS SREAL_PART_BITS
 
@@ -34,14 +36,23 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1) {}
+  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
 
   /* Construct a sreal.  */
-  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
+  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  {
+    m_negative = sig < 0;
+
+    if (sig < 0)
+      sig = -sig;
+
+    m_sig = (uint64_t) sig;
+
+    normalize ();
+  }
 
   void dump (FILE *) const;
   int64_t to_int () const;
-
   sreal operator+ (const sreal &other) const;
   sreal operator- (const sreal &other) const;
   sreal operator* (const sreal &other) const;
@@ -49,21 +60,64 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    return m_exp < other.m_exp
+    if (m_negative != other.m_negative)
+      return m_negative > other.m_negative;
+
+    bool r = m_exp < other.m_exp
       || (m_exp == other.m_exp && m_sig < other.m_sig);
+
+    return m_negative ? !r : r;
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig;
+    return m_exp == other.m_exp && m_sig == other.m_sig
+		    && m_negative == other.m_negative;
+  }
+
+  sreal operator- () const
+  {
+    if (m_sig == 0)
+      return *this;
+
+    sreal tmp = *this;
+    tmp.m_negative = !tmp.m_negative;
+
+    return tmp;
+  }
+
+  sreal shift (int sig) const
+  {
+    sreal tmp = *this;
+    tmp.m_sig += sig;
+
+    return tmp;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal min ()
+  {
+    static sreal min = sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP);
+    return min;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal max ()
+  {
+    static sreal max = sreal (SREAL_MAX_SIG, SREAL_MAX_EXP);
+    return max;
   }
 
 private:
   void normalize ();
   void shift_right (int amount);
 
-  uint64_t m_sig;		/* Significant.  */
+  static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
+  static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
+
+  uint64_t m_sig;			/* Significant.  */
   signed int m_exp;			/* Exponent.  */
+  bool m_negative;			/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
@@ -76,12 +130,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
 
 inline sreal &operator-= (sreal &a, const sreal &b)
 {
-return a = a - b;
+  return a = a - b;
 }
 
 inline sreal &operator/= (sreal &a, const sreal &b)
 {
-return a = a / b;
+  return a = a / b;
 }
 
 inline sreal &operator*= (sreal &a, const sreal &b)
@@ -109,4 +163,14 @@ inline bool operator>= (const sreal &a, const sreal &b)
   return a == b || a > b;
 }
 
+inline sreal operator<< (const sreal &a, int exp)
+{
+  return a.shift (exp);
+}
+
+inline sreal operator>> (const sreal &a, int exp)
+{
+  return a.shift (-exp);
+}
+
 #endif
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-21 15:34         ` Martin Liška
@ 2014-11-21 15:46           ` Richard Biener
  2014-11-21 15:52             ` Martin Liška
  0 siblings, 1 reply; 38+ messages in thread
From: Richard Biener @ 2014-11-21 15:46 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:

> Hello.
>
> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>
>> that's a  new API, right?  There is no max () and I think that using
>> LONG_MIN here is asking for trouble (host dependence).  The
>> comment in the file says the max should be
>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>
>
> Sure, sreal can store much bigger(smaller) numbers :)
>
>> Where do you need sreal::to_double?  The host shouldn't perform
>> double calculations so it can be only for dumping?  In which case
>> the user should have used sreal::dump (), maybe with extra
>> arguments.
>>
>
> That new function was request from Honza, only for debugging purpose.
> I agree that dump should this kind of job.
>
> If no other problem, I will run tests once more and commit it.
> Thanks,
> Martin

-#define SREAL_MAX_EXP (INT_MAX / 4)
+#define SREAL_MAX_EXP (INT_MAX / 8)

this change doesn't look necessary anymore?

Btw, it's also odd that...

 #define SREAL_PART_BITS 32
...
 #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
 #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)

thus all m_sig values fit in 32bits but we still use a uint64_t m_sig ...
(the implementation uses 64bit for internal computations, but still
the storage is wasteful?)

Of course the way normalize() works requires that storage to be
64bits to store unnormalized values.

I'd say ok with the SREAL_MAX_EXP change reverted.

Thanks,
Richard.


>
>> Otherwise looks good to me and sorry for not noticing the above
>> earlier.
>>
>> Thanks,
>> Richard.
>>
>>> Thanks,
>>> Martin
>>>
>>>
>>>>>    };
>>>>>
>>>>>    extern void debug (sreal &ref);
>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal
>>>>> &b)
>>>>>
>>>>>    inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>    {
>>>>> -return a = a - b;
>>>>> +  return a = a - b;
>>>>>    }
>>>>>
>>>>>    inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>    {
>>>>> -return a = a / b;
>>>>> +  return a = a / b;
>>>>>    }
>>>>>
>>>>>    inline sreal &operator*= (sreal &a, const sreal &b)
>>>>> --
>>>>> 2.1.2
>>>>>
>>>>>
>>>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-21 15:46           ` Richard Biener
@ 2014-11-21 15:52             ` Martin Liška
  2014-11-27 17:56               ` Martin Liška
  0 siblings, 1 reply; 38+ messages in thread
From: Martin Liška @ 2014-11-21 15:52 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2562 bytes --]

On 11/21/2014 04:02 PM, Richard Biener wrote:
> On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:
>
>> Hello.
>>
>> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>>
>>> that's a  new API, right?  There is no max () and I think that using
>>> LONG_MIN here is asking for trouble (host dependence).  The
>>> comment in the file says the max should be
>>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>>
>>
>> Sure, sreal can store much bigger(smaller) numbers :)
>>
>>> Where do you need sreal::to_double?  The host shouldn't perform
>>> double calculations so it can be only for dumping?  In which case
>>> the user should have used sreal::dump (), maybe with extra
>>> arguments.
>>>
>>
>> That new function was request from Honza, only for debugging purpose.
>> I agree that dump should this kind of job.
>>
>> If no other problem, I will run tests once more and commit it.
>> Thanks,
>> Martin
>
> -#define SREAL_MAX_EXP (INT_MAX / 4)
> +#define SREAL_MAX_EXP (INT_MAX / 8)
>
> this change doesn't look necessary anymore?
>
> Btw, it's also odd that...
>
>   #define SREAL_PART_BITS 32
> ...
>   #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>   #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>
> thus all m_sig values fit in 32bits but we still use a uint64_t m_sig ...
> (the implementation uses 64bit for internal computations, but still
> the storage is wasteful?)
>
> Of course the way normalize() works requires that storage to be
> 64bits to store unnormalized values.
>
> I'd say ok with the SREAL_MAX_EXP change reverted.
>

Hi.

You are right, this change was done because I used one bit for 
m_negative (bitfield), not needed any more.

Final version attached.

Thank you,
Martin

> Thanks,
> Richard.
>
>
>>
>>> Otherwise looks good to me and sorry for not noticing the above
>>> earlier.
>>>
>>> Thanks,
>>> Richard.
>>>
>>>> Thanks,
>>>> Martin
>>>>
>>>>
>>>>>>     };
>>>>>>
>>>>>>     extern void debug (sreal &ref);
>>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal
>>>>>> &b)
>>>>>>
>>>>>>     inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>>     {
>>>>>> -return a = a - b;
>>>>>> +  return a = a - b;
>>>>>>     }
>>>>>>
>>>>>>     inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>>     {
>>>>>> -return a = a / b;
>>>>>> +  return a = a / b;
>>>>>>     }
>>>>>>
>>>>>>     inline sreal &operator*= (sreal &a, const sreal &b)
>>>>>> --
>>>>>> 2.1.2
>>>>>>
>>>>>>
>>>>
>>


[-- Attachment #2: sreal-v4.patch --]
[-- Type: text/x-patch, Size: 13387 bytes --]

From b28e4264b5f9965ca5ab4f52ce6f4c9df00d4800 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Fri, 21 Nov 2014 12:07:40 +0100
Subject: [PATCH 1/2] Negative numbers added for sreal class.

gcc/ChangeLog:

2014-11-13  Martin Liska  <mliska@suse.cz>

	* predict.c (propagate_freq): More elegant sreal API is used.
	(estimate_bb_frequencies): Precomputed constants replaced by integer
	constants.
	* sreal.c (sreal::normalize): New function.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	* sreal.h: Definition of new functions added.
---
 gcc/predict.c |  30 ++++++++--------
 gcc/sreal.c   | 114 ++++++++++++++++++++++++++++++++++++++++++++--------------
 gcc/sreal.h   |  82 +++++++++++++++++++++++++++++++++++++-----
 3 files changed, 174 insertions(+), 52 deletions(-)

diff --git a/gcc/predict.c b/gcc/predict.c
index 779af11..0cfe4a9 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -82,7 +82,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
 		   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
-static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
+static sreal real_almost_one, real_br_prob_base,
 	     real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
 static void combine_predictions_for_insn (rtx_insn *, basic_block);
@@ -2541,13 +2541,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 	bb->count = bb->frequency = 0;
     }
 
-  BLOCK_INFO (head)->frequency = real_one;
+  BLOCK_INFO (head)->frequency = 1;
   last = head;
   for (bb = head; bb; bb = nextbb)
     {
       edge_iterator ei;
-      sreal cyclic_probability = real_zero;
-      sreal frequency = real_zero;
+      sreal cyclic_probability = 0;
+      sreal frequency = 0;
 
       nextbb = BLOCK_INFO (bb)->next;
       BLOCK_INFO (bb)->next = NULL;
@@ -2572,13 +2572,13 @@ propagate_freq (basic_block head, bitmap tovisit)
 				  * BLOCK_INFO (e->src)->frequency /
 				  REG_BR_PROB_BASE);  */
 
-		sreal tmp (e->probability, 0);
+		sreal tmp = e->probability;
 		tmp *= BLOCK_INFO (e->src)->frequency;
 		tmp *= real_inv_br_prob_base;
 		frequency += tmp;
 	      }
 
-	  if (cyclic_probability == real_zero)
+	  if (cyclic_probability == 0)
 	    {
 	      BLOCK_INFO (bb)->frequency = frequency;
 	    }
@@ -2590,7 +2590,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	      /* BLOCK_INFO (bb)->frequency = frequency
 					      / (1 - cyclic_probability) */
 
-	      cyclic_probability = real_one - cyclic_probability;
+	      cyclic_probability = sreal (1) - cyclic_probability;
 	      BLOCK_INFO (bb)->frequency = frequency / cyclic_probability;
 	    }
 	}
@@ -2604,7 +2604,7 @@ propagate_freq (basic_block head, bitmap tovisit)
 	     = ((e->probability * BLOCK_INFO (bb)->frequency)
 	     / REG_BR_PROB_BASE); */
 
-	  sreal tmp (e->probability, 0);
+	  sreal tmp = e->probability;
 	  tmp *= BLOCK_INFO (bb)->frequency;
 	  EDGE_INFO (e)->back_edge_prob = tmp * real_inv_br_prob_base;
 	}
@@ -2886,13 +2886,11 @@ estimate_bb_frequencies (bool force)
       if (!real_values_initialized)
         {
 	  real_values_initialized = 1;
-	  real_zero = sreal (0, 0);
-	  real_one = sreal (1, 0);
-	  real_br_prob_base = sreal (REG_BR_PROB_BASE, 0);
-	  real_bb_freq_max = sreal (BB_FREQ_MAX, 0);
+	  real_br_prob_base = REG_BR_PROB_BASE;
+	  real_bb_freq_max = BB_FREQ_MAX;
 	  real_one_half = sreal (1, -1);
-	  real_inv_br_prob_base = real_one / real_br_prob_base;
-	  real_almost_one = real_one - real_inv_br_prob_base;
+	  real_inv_br_prob_base = sreal (1) / real_br_prob_base;
+	  real_almost_one = sreal (1) - real_inv_br_prob_base;
 	}
 
       mark_dfs_back_edges ();
@@ -2910,7 +2908,7 @@ estimate_bb_frequencies (bool force)
 
 	  FOR_EACH_EDGE (e, ei, bb->succs)
 	    {
-	      EDGE_INFO (e)->back_edge_prob = sreal (e->probability, 0);
+	      EDGE_INFO (e)->back_edge_prob = e->probability;
 	      EDGE_INFO (e)->back_edge_prob *= real_inv_br_prob_base;
 	    }
 	}
@@ -2919,7 +2917,7 @@ estimate_bb_frequencies (bool force)
          to outermost to examine frequencies for back edges.  */
       estimate_loops ();
 
-      freq_max = real_zero;
+      freq_max = 0;
       FOR_EACH_BB_FN (bb, cfun)
 	if (freq_max < BLOCK_INFO (bb)->frequency)
 	  freq_max = BLOCK_INFO (bb)->frequency;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 3f5456a..0337f9e 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -1,4 +1,4 @@
-/* Simple data type for positive real numbers for the GNU compiler.
+/* Simple data type for real numbers for the GNU compiler.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* This library supports positive real numbers and 0;
+/* This library supports real numbers;
    inf and nan are NOT supported.
    It is written to be simple and fast.
 
@@ -82,12 +82,12 @@ debug (sreal *ptr)
 void
 sreal::shift_right (int s)
 {
-  gcc_assert (s > 0);
-  gcc_assert (s <= SREAL_BITS);
+  gcc_checking_assert (s > 0);
+  gcc_checking_assert (s <= SREAL_BITS);
   /* Exponent should never be so large because shift_right is used only by
      sreal_add and sreal_sub ant thus the number cannot be shifted out from
      exponent range.  */
-  gcc_assert (m_exp + s <= SREAL_MAX_EXP);
+  gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
 
   m_exp += s;
 
@@ -102,6 +102,7 @@ sreal::normalize ()
 {
   if (m_sig == 0)
     {
+      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
   else if (m_sig < SREAL_MIN_SIG)
@@ -153,15 +154,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
+  int64_t sign = m_negative ? -1 : 1;
+
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
-    return INTTYPE_MAXIMUM (int64_t);
+    return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return m_sig << m_exp;
+    return sign * (m_sig << m_exp);
   if (m_exp < 0)
-    return m_sig >> -m_exp;
-  return m_sig;
+    return sign * (m_sig >> -m_exp);
+  return sign * m_sig;
 }
 
 /* Return *this + other.  */
@@ -169,18 +172,40 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
-  int dexp;
-  sreal tmp, r;
-const sreal *a_p = this, *b_p = &other, *bb;
+  const sreal *a_p = this, *b_p = &other;
 
-  if (*a_p < *b_p)
+  if (a_p->m_negative && !b_p->m_negative)
+    std::swap (a_p, b_p);
+
+  /* a + -b => a - b.  */
+  if (!a_p->m_negative && b_p->m_negative)
     {
-      const sreal *swap;
-      swap = a_p;
-      a_p = b_p;
-      b_p = swap;
+      sreal tmp = -(*b_p);
+      if (*a_p < tmp)
+	return signedless_minus (tmp, *a_p, false);
+      else
+	return signedless_minus (*a_p, tmp, true);
     }
 
+  gcc_checking_assert (a_p->m_negative == b_p->m_negative);
+
+  sreal r = signedless_plus (*a_p, *b_p, a_p->m_negative);
+
+  return r;
+}
+
+sreal
+sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
+{
+  const sreal *bb;
+  sreal r, tmp;
+  int dexp;
+  const sreal *a_p = &a;
+  const sreal *b_p = &b;
+
+  if (*a_p < *b_p)
+    std::swap (a_p, b_p);
+
   dexp = a_p->m_exp - b_p->m_exp;
   r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
@@ -200,6 +225,8 @@ const sreal *a_p = this, *b_p = &other, *bb;
 
   r.m_sig = a_p->m_sig + bb->m_sig;
   r.normalize ();
+
+  r.m_negative = negative;
   return r;
 }
 
@@ -208,30 +235,60 @@ const sreal *a_p = this, *b_p = &other, *bb;
 sreal
 sreal::operator- (const sreal &other) const
 {
+  /* -a - b => -a + (-b).  */
+  if (m_negative && !other.m_negative)
+    return signedless_plus (*this, -other, true);
+
+  /* a - (-b) => a + b.  */
+  if (!m_negative && other.m_negative)
+    return signedless_plus (*this, -other, false);
+
+  gcc_checking_assert (m_negative == other.m_negative);
+
+  /* We want to substract a smaller number from bigger
+    for nonegative numbers.  */
+  if (!m_negative && *this < other)
+    return -signedless_minus (other, *this, true);
+
+  /* Example: -2 - (-3) => 3 - 2 */
+  if (m_negative && *this > other)
+    return signedless_minus (-other, -(*this), true);
+
+  sreal r = signedless_minus (*this, other, m_negative);
+
+  return r;
+}
+
+sreal
+sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
+{
   int dexp;
   sreal tmp, r;
   const sreal *bb;
+  const sreal *a_p = &a;
+  const sreal *b_p = &b;
 
-  gcc_assert (*this >= other);
+  dexp = a_p->m_exp - b_p->m_exp;
 
-  dexp = m_exp - other.m_exp;
-  r.m_exp = m_exp;
+  r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
     {
-      r.m_sig = m_sig;
+      r.m_sig = a_p->m_sig;
       return r;
     }
   if (dexp == 0)
-    bb = &other;
+    bb = b_p;
   else
     {
-      tmp = other;
+      tmp = *b_p;
       tmp.shift_right (dexp);
       bb = &tmp;
     }
 
-  r.m_sig = m_sig - bb->m_sig;
+  r.m_sig = a_p->m_sig - bb->m_sig;
   r.normalize ();
+
+  r.m_negative = negative;
   return r;
 }
 
@@ -240,7 +297,7 @@ sreal::operator- (const sreal &other) const
 sreal
 sreal::operator* (const sreal &other) const
 {
-sreal r;
+  sreal r;
   if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
@@ -252,6 +309,8 @@ sreal r;
       r.m_exp = m_exp + other.m_exp;
       r.normalize ();
     }
+
+  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -260,10 +319,11 @@ sreal r;
 sreal
 sreal::operator/ (const sreal &other) const
 {
-  gcc_assert (other.m_sig != 0);
-sreal r;
+  gcc_checking_assert (other.m_sig != 0);
+  sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
+  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 461e28b..1362bf6 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -1,4 +1,4 @@
-/* Definitions for simple data type for positive real numbers.
+/* Definitions for simple data type for real numbers.
    Copyright (C) 2002-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 /* SREAL_PART_BITS has to be an even number.  */
 #define SREAL_PART_BITS 32
 
+#define UINT64_BITS	64
+
 #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
 #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
 #define SREAL_MAX_EXP (INT_MAX / 4)
@@ -34,14 +36,23 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1) {}
+  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
 
   /* Construct a sreal.  */
-  sreal (uint64_t sig, int exp) : m_sig (sig), m_exp (exp) { normalize (); }
+  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  {
+    m_negative = sig < 0;
+
+    if (sig < 0)
+      sig = -sig;
+
+    m_sig = (uint64_t) sig;
+
+    normalize ();
+  }
 
   void dump (FILE *) const;
   int64_t to_int () const;
-
   sreal operator+ (const sreal &other) const;
   sreal operator- (const sreal &other) const;
   sreal operator* (const sreal &other) const;
@@ -49,21 +60,64 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    return m_exp < other.m_exp
+    if (m_negative != other.m_negative)
+      return m_negative > other.m_negative;
+
+    bool r = m_exp < other.m_exp
       || (m_exp == other.m_exp && m_sig < other.m_sig);
+
+    return m_negative ? !r : r;
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig;
+    return m_exp == other.m_exp && m_sig == other.m_sig
+		    && m_negative == other.m_negative;
+  }
+
+  sreal operator- () const
+  {
+    if (m_sig == 0)
+      return *this;
+
+    sreal tmp = *this;
+    tmp.m_negative = !tmp.m_negative;
+
+    return tmp;
+  }
+
+  sreal shift (int sig) const
+  {
+    sreal tmp = *this;
+    tmp.m_sig += sig;
+
+    return tmp;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal min ()
+  {
+    static sreal min = sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP);
+    return min;
+  }
+
+  /* Global minimum sreal can hold.  */
+  inline static sreal max ()
+  {
+    static sreal max = sreal (SREAL_MAX_SIG, SREAL_MAX_EXP);
+    return max;
   }
 
 private:
   void normalize ();
   void shift_right (int amount);
 
-  uint64_t m_sig;		/* Significant.  */
+  static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
+  static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
+
+  uint64_t m_sig;			/* Significant.  */
   signed int m_exp;			/* Exponent.  */
+  bool m_negative;			/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
@@ -76,12 +130,12 @@ inline sreal &operator+= (sreal &a, const sreal &b)
 
 inline sreal &operator-= (sreal &a, const sreal &b)
 {
-return a = a - b;
+  return a = a - b;
 }
 
 inline sreal &operator/= (sreal &a, const sreal &b)
 {
-return a = a / b;
+  return a = a / b;
 }
 
 inline sreal &operator*= (sreal &a, const sreal &b)
@@ -109,4 +163,14 @@ inline bool operator>= (const sreal &a, const sreal &b)
   return a == b || a > b;
 }
 
+inline sreal operator<< (const sreal &a, int exp)
+{
+  return a.shift (exp);
+}
+
+inline sreal operator>> (const sreal &a, int exp)
+{
+  return a.shift (-exp);
+}
+
 #endif
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument.
  2014-11-13 20:45 ` [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument mliska
  2014-11-14  4:46   ` Jeff Law
@ 2014-11-24 19:25   ` H.J. Lu
  1 sibling, 0 replies; 38+ messages in thread
From: H.J. Lu @ 2014-11-24 19:25 UTC (permalink / raw)
  To: mliska; +Cc: GCC Patches

On Thu, Nov 13, 2014 at 12:10 PM, mliska <mliska@suse.cz> wrote:
> gcc/ChangeLog:
>
> 2014-11-13  Martin Liska  <mliska@suse.cz>
>
>         * ipa-inline.c (edge_badness): long is replaced by sreal
>         as fibonacci_heap template type.
>         (update_edge_key): Likewise.
>         (inline_small_functions): Likewise.

This caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64060
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64050

H.J.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-21 15:52             ` Martin Liška
@ 2014-11-27 17:56               ` Martin Liška
  2014-11-28 10:10                 ` Richard Biener
  0 siblings, 1 reply; 38+ messages in thread
From: Martin Liška @ 2014-11-27 17:56 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3042 bytes --]

On 11/21/2014 04:21 PM, Martin Liška wrote:
> On 11/21/2014 04:02 PM, Richard Biener wrote:
>> On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:
>>
>>> Hello.
>>>
>>> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>>>
>>>> that's a  new API, right?  There is no max () and I think that using
>>>> LONG_MIN here is asking for trouble (host dependence).  The
>>>> comment in the file says the max should be
>>>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>>>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>>>
>>>
>>> Sure, sreal can store much bigger(smaller) numbers :)
>>>
>>>> Where do you need sreal::to_double?  The host shouldn't perform
>>>> double calculations so it can be only for dumping?  In which case
>>>> the user should have used sreal::dump (), maybe with extra
>>>> arguments.
>>>>
>>>
>>> That new function was request from Honza, only for debugging purpose.
>>> I agree that dump should this kind of job.
>>>
>>> If no other problem, I will run tests once more and commit it.
>>> Thanks,
>>> Martin
>>
>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>
>> this change doesn't look necessary anymore?
>>
>> Btw, it's also odd that...
>>
>>   #define SREAL_PART_BITS 32
>> ...
>>   #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>   #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>
>> thus all m_sig values fit in 32bits but we still use a uint64_t m_sig ...
>> (the implementation uses 64bit for internal computations, but still
>> the storage is wasteful?)
>>
>> Of course the way normalize() works requires that storage to be
>> 64bits to store unnormalized values.
>>
>> I'd say ok with the SREAL_MAX_EXP change reverted.
>>
>
> Hi.
>
> You are right, this change was done because I used one bit for m_negative (bitfield), not needed any more.
>
> Final version attached.
>
> Thank you,
> Martin
>
>> Thanks,
>> Richard.
>>
>>
>>>
>>>> Otherwise looks good to me and sorry for not noticing the above
>>>> earlier.
>>>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>>> Thanks,
>>>>> Martin
>>>>>
>>>>>
>>>>>>>     };
>>>>>>>
>>>>>>>     extern void debug (sreal &ref);
>>>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal
>>>>>>> &b)
>>>>>>>
>>>>>>>     inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>>>     {
>>>>>>> -return a = a - b;
>>>>>>> +  return a = a - b;
>>>>>>>     }
>>>>>>>
>>>>>>>     inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>>>     {
>>>>>>> -return a = a / b;
>>>>>>> +  return a = a / b;
>>>>>>>     }
>>>>>>>
>>>>>>>     inline sreal &operator*= (sreal &a, const sreal &b)
>>>>>>> --
>>>>>>> 2.1.2
>>>>>>>
>>>>>>>
>>>>>
>>>
>

Hello.

After IRC discussions, I decided to give sreal another refactoring where I
use int64_t for m_sig.

This approach looks much easier and straightforward. I would like to
ask folk for comments?

I am able to run profiled bootstrap on x86_64-linux-pc and ppc64-linux-pc
and new regression is introduced.

Thanks,
Martin



[-- Attachment #2: 0001-New-sreal-implementation-which-uses-int64_t-as-m_sig.patch --]
[-- Type: text/x-patch, Size: 9479 bytes --]

From bff0b4b803271788cd90cfd4032ed6d4e6e95707 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Wed, 26 Nov 2014 15:46:42 +0100
Subject: [PATCH] New sreal implementation which uses int64_t as m_sig.

gcc/ChangeLog:

2014-11-27  Martin Liska  <mliska@suse.cz>

	* sreal.c (sreal::shift_right): New implementation
	for int64_t as m_sig.
	(sreal::normalize): Likewise.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	(sreal::operator*): Likewise.
	(sreal::operator/): Likewise.
	(sreal::signedless_minus): Removed.
	(sreal::signedless_plus): Removed.
	* sreal.h (sreal::operator<): New implementation
	for int64_t as m_sig.
---
 gcc/sreal.c | 129 +++++++++++++++++++-----------------------------------------
 gcc/sreal.h |  52 ++++++++++--------------
 2 files changed, 61 insertions(+), 120 deletions(-)

diff --git a/gcc/sreal.c b/gcc/sreal.c
index 2b5e3ae..304feb0 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -91,7 +91,7 @@ sreal::shift_right (int s)
 
   m_exp += s;
 
-  m_sig += (uint64_t) 1 << (s - 1);
+  m_sig += (int64_t) 1 << (s - 1);
   m_sig >>= s;
 }
 
@@ -100,43 +100,46 @@ sreal::shift_right (int s)
 void
 sreal::normalize ()
 {
+  int64_t s = m_sig < 0 ? -1 : 1;
+  uint64_t sig = m_sig == LONG_MIN ? LONG_MAX : std::abs (m_sig);
+
   if (m_sig == 0)
     {
-      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
-  else if (m_sig < SREAL_MIN_SIG)
+  else if (sig < SREAL_MIN_SIG)
     {
       do
 	{
-	  m_sig <<= 1;
+	  sig <<= 1;
 	  m_exp--;
+	  gcc_checking_assert (sig);
 	}
-      while (m_sig < SREAL_MIN_SIG);
+      while (sig < SREAL_MIN_SIG);
 
       /* Check underflow.  */
       if (m_exp < -SREAL_MAX_EXP)
 	{
 	  m_exp = -SREAL_MAX_EXP;
-	  m_sig = 0;
+	  sig = 0;
 	}
     }
-  else if (m_sig > SREAL_MAX_SIG)
+  else if (sig > SREAL_MAX_SIG)
     {
       int last_bit;
       do
 	{
-	  last_bit = m_sig & 1;
-	  m_sig >>= 1;
+	  last_bit = sig & 1;
+	  sig >>= 1;
 	  m_exp++;
 	}
-      while (m_sig > SREAL_MAX_SIG);
+      while (sig > SREAL_MAX_SIG);
 
       /* Round the number.  */
-      m_sig += last_bit;
-      if (m_sig > SREAL_MAX_SIG)
+      sig += last_bit;
+      if (sig > SREAL_MAX_SIG)
 	{
-	  m_sig >>= 1;
+	  sig >>= 1;
 	  m_exp++;
 	}
 
@@ -144,9 +147,11 @@ sreal::normalize ()
       if (m_exp > SREAL_MAX_EXP)
 	{
 	  m_exp = SREAL_MAX_EXP;
-	  m_sig = SREAL_MAX_SIG;
+	  sig = SREAL_MAX_SIG;
 	}
     }
+
+  m_sig = s * sig;
 }
 
 /* Return integer value of *this.  */
@@ -154,17 +159,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
-  int64_t sign = m_negative ? -1 : 1;
+  int64_t sign = m_sig < 0 ? -1 : 1;
 
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
     return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return sign * (m_sig << m_exp);
+    return m_sig << m_exp;
   if (m_exp < 0)
-    return sign * (m_sig >> -m_exp);
-  return sign * m_sig;
+    return m_sig >> -m_exp;
+  return m_sig;
 }
 
 /* Return *this + other.  */
@@ -172,36 +177,10 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
-  const sreal *a_p = this, *b_p = &other;
-
-  if (a_p->m_negative && !b_p->m_negative)
-    std::swap (a_p, b_p);
-
-  /* a + -b => a - b.  */
-  if (!a_p->m_negative && b_p->m_negative)
-    {
-      sreal tmp = -(*b_p);
-      if (*a_p < tmp)
-	return signedless_minus (tmp, *a_p, true);
-      else
-	return signedless_minus (*a_p, tmp, false);
-    }
-
-  gcc_checking_assert (a_p->m_negative == b_p->m_negative);
-
-  sreal r = signedless_plus (*a_p, *b_p, a_p->m_negative);
-
-  return r;
-}
-
-sreal
-sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
-{
-  const sreal *bb;
-  sreal r, tmp;
   int dexp;
-  const sreal *a_p = &a;
-  const sreal *b_p = &b;
+  sreal tmp, r;
+
+  const sreal *a_p = this, *b_p = &other, *bb;
 
   if (a_p->m_exp < b_p->m_exp)
     std::swap (a_p, b_p);
@@ -211,7 +190,6 @@ sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
   if (dexp > SREAL_BITS)
     {
       r.m_sig = a_p->m_sig;
-      r.m_negative = negative;
       return r;
     }
 
@@ -226,56 +204,32 @@ sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
 
   r.m_sig = a_p->m_sig + bb->m_sig;
   r.normalize ();
-
-  r.m_negative = negative;
   return r;
 }
 
+
 /* Return *this - other.  */
 
 sreal
 sreal::operator- (const sreal &other) const
 {
-  /* -a - b => -a + (-b).  */
-  if (m_negative && !other.m_negative)
-    return signedless_plus (*this, -other, true);
-
-  /* a - (-b) => a + b.  */
-  if (!m_negative && other.m_negative)
-    return signedless_plus (*this, -other, false);
-
-  gcc_checking_assert (m_negative == other.m_negative);
-
-  /* We want to substract a smaller number from bigger
-    for nonegative numbers.  */
-  if (!m_negative && *this < other)
-    return signedless_minus (other, *this, true);
-
-  /* Example: -2 - (-3) => 3 - 2 */
-  if (m_negative && *this > other)
-    return signedless_minus (-other, -(*this), false);
-
-  sreal r = signedless_minus (*this, other, m_negative);
-
-  return r;
-}
-
-sreal
-sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
-{
   int dexp;
   sreal tmp, r;
   const sreal *bb;
-  const sreal *a_p = &a;
-  const sreal *b_p = &b;
+  const sreal *a_p = this, *b_p = &other;
 
-  dexp = a_p->m_exp - b_p->m_exp;
+  int64_t sign = 1;
+  if (a_p->m_exp < b_p->m_exp)
+    {
+      sign = -1;
+      std::swap (a_p, b_p);
+    }
 
+  dexp = a_p->m_exp - b_p->m_exp;
   r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
     {
-      r.m_sig = a_p->m_sig;
-      r.m_negative = negative;
+      r.m_sig = sign * a_p->m_sig;
       return r;
     }
   if (dexp == 0)
@@ -287,10 +241,8 @@ sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
       bb = &tmp;
     }
 
-  r.m_sig = a_p->m_sig - bb->m_sig;
+  r.m_sig = sign * (a_p->m_sig - bb->m_sig);
   r.normalize ();
-
-  r.m_negative = negative;
   return r;
 }
 
@@ -300,7 +252,10 @@ sreal
 sreal::operator* (const sreal &other) const
 {
   sreal r;
-  if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
+  uint64_t asig = (uint64_t)std::abs (m_sig);
+  uint64_t other_asig = (uint64_t)std::abs (other.m_sig);
+
+  if (asig < SREAL_MIN_SIG || other_asig < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
       r.m_exp = -SREAL_MAX_EXP;
@@ -312,7 +267,6 @@ sreal::operator* (const sreal &other) const
       r.normalize ();
     }
 
-  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -325,7 +279,6 @@ sreal::operator/ (const sreal &other) const
   sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
-  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 3938c6e..8b3c6de 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -25,8 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 
 #define UINT64_BITS	64
 
-#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
-#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
+#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 2))
+#define SREAL_MAX_SIG (((uint64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
 #define SREAL_MAX_EXP (INT_MAX / 4)
 
 #define SREAL_BITS SREAL_PART_BITS
@@ -36,18 +36,11 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
+  sreal () : m_sig (-1), m_exp (-1) {}
 
   /* Construct a sreal.  */
-  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  sreal (int64_t sig, int exp = 0) : m_sig (sig), m_exp (exp)
   {
-    m_negative = sig < 0;
-
-    if (sig < 0)
-      sig = -sig;
-
-    m_sig = (uint64_t) sig;
-
     normalize ();
   }
 
@@ -60,33 +53,30 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    /* We negate result in case of negative numbers and
-       it would return true for equal negative numbers.  */
-    if (*this == other)
-      return false;
-
-    if (m_negative != other.m_negative)
-      return m_negative > other.m_negative;
-
-    bool r = m_exp < other.m_exp
-      || (m_exp == other.m_exp && m_sig < other.m_sig);
-
-    return m_negative ? !r : r;
+    if (m_exp == other.m_exp)
+      return m_sig < other.m_sig;
+    else
+    {
+      bool negative = m_sig < 0;
+      bool other_negative = other.m_sig < 0;
+
+      if (negative != other_negative)
+        return negative > other_negative;
+
+      bool r = m_exp < other.m_exp;
+      return negative ? !r : r;
+    }
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig
-		    && m_negative == other.m_negative;
+    return m_exp == other.m_exp && m_sig == other.m_sig;
   }
 
   sreal operator- () const
   {
-    if (m_sig == 0)
-      return *this;
-
     sreal tmp = *this;
-    tmp.m_negative = !tmp.m_negative;
+    tmp.m_sig *= -1;
 
     return tmp;
   }
@@ -125,13 +115,11 @@ public:
 private:
   void normalize ();
   void shift_right (int amount);
-
   static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
   static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
 
-  uint64_t m_sig;			/* Significant.  */
+  int64_t m_sig;			/* Significant.  */
   signed int m_exp;			/* Exponent.  */
-  bool m_negative;			/* Negative sign.  */
 };
 
 extern void debug (sreal &ref);
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-27 17:56               ` Martin Liška
@ 2014-11-28 10:10                 ` Richard Biener
  2014-12-08 16:53                   ` Martin Liška
  0 siblings, 1 reply; 38+ messages in thread
From: Richard Biener @ 2014-11-28 10:10 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Thu, Nov 27, 2014 at 6:08 PM, Martin Liška <mliska@suse.cz> wrote:
> On 11/21/2014 04:21 PM, Martin Liška wrote:
>>
>> On 11/21/2014 04:02 PM, Richard Biener wrote:
>>>
>>> On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:
>>>
>>>> Hello.
>>>>
>>>> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>>>>
>>>>> that's a  new API, right?  There is no max () and I think that using
>>>>> LONG_MIN here is asking for trouble (host dependence).  The
>>>>> comment in the file says the max should be
>>>>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>>>>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>>>>
>>>>
>>>> Sure, sreal can store much bigger(smaller) numbers :)
>>>>
>>>>> Where do you need sreal::to_double?  The host shouldn't perform
>>>>> double calculations so it can be only for dumping?  In which case
>>>>> the user should have used sreal::dump (), maybe with extra
>>>>> arguments.
>>>>>
>>>>
>>>> That new function was request from Honza, only for debugging purpose.
>>>> I agree that dump should this kind of job.
>>>>
>>>> If no other problem, I will run tests once more and commit it.
>>>> Thanks,
>>>> Martin
>>>
>>>
>>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>>
>>> this change doesn't look necessary anymore?
>>>
>>> Btw, it's also odd that...
>>>
>>>   #define SREAL_PART_BITS 32
>>> ...
>>>   #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>>   #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>>
>>> thus all m_sig values fit in 32bits but we still use a uint64_t m_sig ...
>>> (the implementation uses 64bit for internal computations, but still
>>> the storage is wasteful?)
>>>
>>> Of course the way normalize() works requires that storage to be
>>> 64bits to store unnormalized values.
>>>
>>> I'd say ok with the SREAL_MAX_EXP change reverted.
>>>
>>
>> Hi.
>>
>> You are right, this change was done because I used one bit for m_negative
>> (bitfield), not needed any more.
>>
>> Final version attached.
>>
>> Thank you,
>> Martin
>>
>>> Thanks,
>>> Richard.
>>>
>>>
>>>>
>>>>> Otherwise looks good to me and sorry for not noticing the above
>>>>> earlier.
>>>>>
>>>>> Thanks,
>>>>> Richard.
>>>>>
>>>>>> Thanks,
>>>>>> Martin
>>>>>>
>>>>>>
>>>>>>>>     };
>>>>>>>>
>>>>>>>>     extern void debug (sreal &ref);
>>>>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal
>>>>>>>> &b)
>>>>>>>>
>>>>>>>>     inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>>>>     {
>>>>>>>> -return a = a - b;
>>>>>>>> +  return a = a - b;
>>>>>>>>     }
>>>>>>>>
>>>>>>>>     inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>>>>     {
>>>>>>>> -return a = a / b;
>>>>>>>> +  return a = a / b;
>>>>>>>>     }
>>>>>>>>
>>>>>>>>     inline sreal &operator*= (sreal &a, const sreal &b)
>>>>>>>> --
>>>>>>>> 2.1.2
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>
>
> Hello.
>
> After IRC discussions, I decided to give sreal another refactoring where I
> use int64_t for m_sig.
>
> This approach looks much easier and straightforward. I would like to
> ask folk for comments?

I think you want to exclude LONG_MIN (how do you know that LONG_MIN
is min(int64_t)?) as a valid value for m_sig - after all SREAL_MIN_SIG
makes it symmetric.  Or simply use abs_hwi at

+  int64_t s = m_sig < 0 ? -1 : 1;
+  uint64_t sig = m_sig == LONG_MIN ? LONG_MAX : std::abs (m_sig);

-#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
-#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
+#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 2))
+#define SREAL_MAX_SIG (((uint64_t) 1 << (SREAL_PART_BITS - 1)) - 1)

shouldn't this also be -2 in the last line?

That is, you effectively use the MSB as a sign bit?

Btw, a further change would be to make m_sig 'signed int', matching
the "real" storage requirements according to SREAL_PART_BITS.
This would of course still require temporaries used for computation
to be 64bits and it would require normalization to work on the
temporaries.  But then we'd get down to 8 bytes storage ...

Richard.


> I am able to run profiled bootstrap on x86_64-linux-pc and ppc64-linux-pc
> and new regression is introduced.
>
> Thanks,
> Martin
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-11-28 10:10                 ` Richard Biener
@ 2014-12-08 16:53                   ` Martin Liška
  2014-12-09 14:15                     ` Richard Biener
  0 siblings, 1 reply; 38+ messages in thread
From: Martin Liška @ 2014-12-08 16:53 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4910 bytes --]

On 11/28/2014 10:32 AM, Richard Biener wrote:
> On Thu, Nov 27, 2014 at 6:08 PM, Martin Liška <mliska@suse.cz> wrote:
>> On 11/21/2014 04:21 PM, Martin Liška wrote:
>>>
>>> On 11/21/2014 04:02 PM, Richard Biener wrote:
>>>>
>>>> On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:
>>>>
>>>>> Hello.
>>>>>
>>>>> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>>>>>
>>>>>> that's a  new API, right?  There is no max () and I think that using
>>>>>> LONG_MIN here is asking for trouble (host dependence).  The
>>>>>> comment in the file says the max should be
>>>>>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>>>>>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>>>>>
>>>>>
>>>>> Sure, sreal can store much bigger(smaller) numbers :)
>>>>>
>>>>>> Where do you need sreal::to_double?  The host shouldn't perform
>>>>>> double calculations so it can be only for dumping?  In which case
>>>>>> the user should have used sreal::dump (), maybe with extra
>>>>>> arguments.
>>>>>>
>>>>>
>>>>> That new function was request from Honza, only for debugging purpose.
>>>>> I agree that dump should this kind of job.
>>>>>
>>>>> If no other problem, I will run tests once more and commit it.
>>>>> Thanks,
>>>>> Martin
>>>>
>>>>
>>>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>>>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>>>
>>>> this change doesn't look necessary anymore?
>>>>
>>>> Btw, it's also odd that...
>>>>
>>>>    #define SREAL_PART_BITS 32
>>>> ...
>>>>    #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>>>    #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>>>
>>>> thus all m_sig values fit in 32bits but we still use a uint64_t m_sig ...
>>>> (the implementation uses 64bit for internal computations, but still
>>>> the storage is wasteful?)
>>>>
>>>> Of course the way normalize() works requires that storage to be
>>>> 64bits to store unnormalized values.
>>>>
>>>> I'd say ok with the SREAL_MAX_EXP change reverted.
>>>>
>>>
>>> Hi.
>>>
>>> You are right, this change was done because I used one bit for m_negative
>>> (bitfield), not needed any more.
>>>
>>> Final version attached.
>>>
>>> Thank you,
>>> Martin
>>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>>
>>>>>
>>>>>> Otherwise looks good to me and sorry for not noticing the above
>>>>>> earlier.
>>>>>>
>>>>>> Thanks,
>>>>>> Richard.
>>>>>>
>>>>>>> Thanks,
>>>>>>> Martin
>>>>>>>
>>>>>>>
>>>>>>>>>      };
>>>>>>>>>
>>>>>>>>>      extern void debug (sreal &ref);
>>>>>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const sreal
>>>>>>>>> &b)
>>>>>>>>>
>>>>>>>>>      inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>>>>>      {
>>>>>>>>> -return a = a - b;
>>>>>>>>> +  return a = a - b;
>>>>>>>>>      }
>>>>>>>>>
>>>>>>>>>      inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>>>>>      {
>>>>>>>>> -return a = a / b;
>>>>>>>>> +  return a = a / b;
>>>>>>>>>      }
>>>>>>>>>
>>>>>>>>>      inline sreal &operator*= (sreal &a, const sreal &b)
>>>>>>>>> --
>>>>>>>>> 2.1.2
>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>
>>>
>>
>> Hello.
>>
>> After IRC discussions, I decided to give sreal another refactoring where I
>> use int64_t for m_sig.
>>
>> This approach looks much easier and straightforward. I would like to
>> ask folk for comments?
>
> I think you want to exclude LONG_MIN (how do you know that LONG_MIN
> is min(int64_t)?) as a valid value for m_sig - after all SREAL_MIN_SIG
> makes it symmetric.  Or simply use abs_hwi at

Hello.

I decided to use abs_hwi.

>
> +  int64_t s = m_sig < 0 ? -1 : 1;
> +  uint64_t sig = m_sig == LONG_MIN ? LONG_MAX : std::abs (m_sig);
>
> -#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
> -#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
> +#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 2))
> +#define SREAL_MAX_SIG (((uint64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
>
> shouldn't this also be -2 in the last line?

It's correct, in the first line, I s/'SREAL_PART_BITS - 1'/'SREAL_PART_BITS - 2' and
second one is also decremented: s/'SREAL_PART_BITS'/'REAL_PART_BITS - 1'.

>
> That is, you effectively use the MSB as a sign bit?

Yes. It uses signed integer with MSB as a sign bit.

>
> Btw, a further change would be to make m_sig 'signed int', matching
> the "real" storage requirements according to SREAL_PART_BITS.
> This would of course still require temporaries used for computation
> to be 64bits and it would require normalization to work on the
> temporaries.  But then we'd get down to 8 bytes storage ...

Agree, we can shrink the size for future.

I've been running tests, I hope this implementation is much nicer than
having bool m_negative. What do you think about trunk acceptation?

Thanks,
Martin

>
> Richard.
>
>
>> I am able to run profiled bootstrap on x86_64-linux-pc and ppc64-linux-pc
>> and new regression is introduced.
>>
>> Thanks,
>> Martin
>>
>>


[-- Attachment #2: 0001-New-sreal-implementation-which-uses-int64_t-as-m_sig.patch --]
[-- Type: text/x-patch, Size: 10387 bytes --]

From c275c48eb5f0f41f546bb7866d70c1fe066d6d62 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Wed, 26 Nov 2014 15:46:42 +0100
Subject: [PATCH] New sreal implementation which uses int64_t as m_sig.

gcc/ChangeLog:

2014-12-08  Martin Liska  <mliska@suse.cz>

	* sreal.c (sreal::shift_right): New implementation
	for int64_t as m_sig.
	(sreal::normalize): Likewise.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	(sreal::operator*): Likewise.
	(sreal::operator/): Likewise.
	(sreal::signedless_minus): Removed.
	(sreal::signedless_plus): Removed.
	(sreal::debug): const keyword is added.
	* sreal.h (sreal::operator<): New implementation
	for int64_t as m_sig.
	* ipa-inline.c (recursive_inlining): LONG_MIN is replaced
	with sreal::min ().
---
 gcc/ipa-inline.c |   2 +-
 gcc/sreal.c      | 129 +++++++++++++++++--------------------------------------
 gcc/sreal.h      |  56 ++++++++++--------------
 3 files changed, 62 insertions(+), 125 deletions(-)

diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 26335ec..a5044fd 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1311,7 +1311,7 @@ recursive_inlining (struct cgraph_edge *edge,
 		    vec<cgraph_edge *> *new_edges)
 {
   int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
-  edge_heap_t heap (LONG_MIN);
+  edge_heap_t heap (sreal::min ());
   struct cgraph_node *node;
   struct cgraph_edge *e;
   struct cgraph_node *master_clone = NULL, *next;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 2b5e3ae..9ff0109 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -61,13 +61,13 @@ sreal::dump (FILE *file) const
 }
 
 DEBUG_FUNCTION void
-debug (sreal &ref)
+debug (const sreal &ref)
 {
   ref.dump (stderr);
 }
 
 DEBUG_FUNCTION void
-debug (sreal *ptr)
+debug (const sreal *ptr)
 {
   if (ptr)
     debug (*ptr);
@@ -91,7 +91,7 @@ sreal::shift_right (int s)
 
   m_exp += s;
 
-  m_sig += (uint64_t) 1 << (s - 1);
+  m_sig += (int64_t) 1 << (s - 1);
   m_sig >>= s;
 }
 
@@ -100,43 +100,45 @@ sreal::shift_right (int s)
 void
 sreal::normalize ()
 {
+  int64_t s = m_sig < 0 ? -1 : 1;
+  HOST_WIDE_INT sig = abs_hwi (m_sig);
+
   if (m_sig == 0)
     {
-      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
-  else if (m_sig < SREAL_MIN_SIG)
+  else if (sig < SREAL_MIN_SIG)
     {
       do
 	{
-	  m_sig <<= 1;
+	  sig <<= 1;
 	  m_exp--;
 	}
-      while (m_sig < SREAL_MIN_SIG);
+      while (sig < SREAL_MIN_SIG);
 
       /* Check underflow.  */
       if (m_exp < -SREAL_MAX_EXP)
 	{
 	  m_exp = -SREAL_MAX_EXP;
-	  m_sig = 0;
+	  sig = 0;
 	}
     }
-  else if (m_sig > SREAL_MAX_SIG)
+  else if (sig > SREAL_MAX_SIG)
     {
       int last_bit;
       do
 	{
-	  last_bit = m_sig & 1;
-	  m_sig >>= 1;
+	  last_bit = sig & 1;
+	  sig >>= 1;
 	  m_exp++;
 	}
-      while (m_sig > SREAL_MAX_SIG);
+      while (sig > SREAL_MAX_SIG);
 
       /* Round the number.  */
-      m_sig += last_bit;
-      if (m_sig > SREAL_MAX_SIG)
+      sig += last_bit;
+      if (sig > SREAL_MAX_SIG)
 	{
-	  m_sig >>= 1;
+	  sig >>= 1;
 	  m_exp++;
 	}
 
@@ -144,9 +146,11 @@ sreal::normalize ()
       if (m_exp > SREAL_MAX_EXP)
 	{
 	  m_exp = SREAL_MAX_EXP;
-	  m_sig = SREAL_MAX_SIG;
+	  sig = SREAL_MAX_SIG;
 	}
     }
+
+  m_sig = s * sig;
 }
 
 /* Return integer value of *this.  */
@@ -154,17 +158,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
-  int64_t sign = m_negative ? -1 : 1;
+  int64_t sign = m_sig < 0 ? -1 : 1;
 
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
     return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return sign * (m_sig << m_exp);
+    return m_sig << m_exp;
   if (m_exp < 0)
-    return sign * (m_sig >> -m_exp);
-  return sign * m_sig;
+    return m_sig >> -m_exp;
+  return m_sig;
 }
 
 /* Return *this + other.  */
@@ -172,36 +176,10 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
-  const sreal *a_p = this, *b_p = &other;
-
-  if (a_p->m_negative && !b_p->m_negative)
-    std::swap (a_p, b_p);
-
-  /* a + -b => a - b.  */
-  if (!a_p->m_negative && b_p->m_negative)
-    {
-      sreal tmp = -(*b_p);
-      if (*a_p < tmp)
-	return signedless_minus (tmp, *a_p, true);
-      else
-	return signedless_minus (*a_p, tmp, false);
-    }
-
-  gcc_checking_assert (a_p->m_negative == b_p->m_negative);
-
-  sreal r = signedless_plus (*a_p, *b_p, a_p->m_negative);
-
-  return r;
-}
-
-sreal
-sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
-{
-  const sreal *bb;
-  sreal r, tmp;
   int dexp;
-  const sreal *a_p = &a;
-  const sreal *b_p = &b;
+  sreal tmp, r;
+
+  const sreal *a_p = this, *b_p = &other, *bb;
 
   if (a_p->m_exp < b_p->m_exp)
     std::swap (a_p, b_p);
@@ -211,7 +189,6 @@ sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
   if (dexp > SREAL_BITS)
     {
       r.m_sig = a_p->m_sig;
-      r.m_negative = negative;
       return r;
     }
 
@@ -226,56 +203,32 @@ sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
 
   r.m_sig = a_p->m_sig + bb->m_sig;
   r.normalize ();
-
-  r.m_negative = negative;
   return r;
 }
 
+
 /* Return *this - other.  */
 
 sreal
 sreal::operator- (const sreal &other) const
 {
-  /* -a - b => -a + (-b).  */
-  if (m_negative && !other.m_negative)
-    return signedless_plus (*this, -other, true);
-
-  /* a - (-b) => a + b.  */
-  if (!m_negative && other.m_negative)
-    return signedless_plus (*this, -other, false);
-
-  gcc_checking_assert (m_negative == other.m_negative);
-
-  /* We want to substract a smaller number from bigger
-    for nonegative numbers.  */
-  if (!m_negative && *this < other)
-    return signedless_minus (other, *this, true);
-
-  /* Example: -2 - (-3) => 3 - 2 */
-  if (m_negative && *this > other)
-    return signedless_minus (-other, -(*this), false);
-
-  sreal r = signedless_minus (*this, other, m_negative);
-
-  return r;
-}
-
-sreal
-sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
-{
   int dexp;
   sreal tmp, r;
   const sreal *bb;
-  const sreal *a_p = &a;
-  const sreal *b_p = &b;
+  const sreal *a_p = this, *b_p = &other;
 
-  dexp = a_p->m_exp - b_p->m_exp;
+  int64_t sign = 1;
+  if (a_p->m_exp < b_p->m_exp)
+    {
+      sign = -1;
+      std::swap (a_p, b_p);
+    }
 
+  dexp = a_p->m_exp - b_p->m_exp;
   r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
     {
-      r.m_sig = a_p->m_sig;
-      r.m_negative = negative;
+      r.m_sig = sign * a_p->m_sig;
       return r;
     }
   if (dexp == 0)
@@ -287,10 +240,8 @@ sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
       bb = &tmp;
     }
 
-  r.m_sig = a_p->m_sig - bb->m_sig;
+  r.m_sig = sign * (a_p->m_sig - bb->m_sig);
   r.normalize ();
-
-  r.m_negative = negative;
   return r;
 }
 
@@ -300,7 +251,7 @@ sreal
 sreal::operator* (const sreal &other) const
 {
   sreal r;
-  if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
+  if (std::abs (m_sig) < SREAL_MIN_SIG || std::abs (other.m_sig) < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
       r.m_exp = -SREAL_MAX_EXP;
@@ -312,7 +263,6 @@ sreal::operator* (const sreal &other) const
       r.normalize ();
     }
 
-  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -325,7 +275,6 @@ sreal::operator/ (const sreal &other) const
   sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
-  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 3938c6e..730f49c 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -25,8 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 
 #define UINT64_BITS	64
 
-#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
-#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
+#define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2))
+#define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
 #define SREAL_MAX_EXP (INT_MAX / 4)
 
 #define SREAL_BITS SREAL_PART_BITS
@@ -36,18 +36,11 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
+  sreal () : m_sig (-1), m_exp (-1) {}
 
   /* Construct a sreal.  */
-  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  sreal (int64_t sig, int exp = 0) : m_sig (sig), m_exp (exp)
   {
-    m_negative = sig < 0;
-
-    if (sig < 0)
-      sig = -sig;
-
-    m_sig = (uint64_t) sig;
-
     normalize ();
   }
 
@@ -60,33 +53,30 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    /* We negate result in case of negative numbers and
-       it would return true for equal negative numbers.  */
-    if (*this == other)
-      return false;
-
-    if (m_negative != other.m_negative)
-      return m_negative > other.m_negative;
-
-    bool r = m_exp < other.m_exp
-      || (m_exp == other.m_exp && m_sig < other.m_sig);
-
-    return m_negative ? !r : r;
+    if (m_exp == other.m_exp)
+      return m_sig < other.m_sig;
+    else
+    {
+      bool negative = m_sig < 0;
+      bool other_negative = other.m_sig < 0;
+
+      if (negative != other_negative)
+        return negative > other_negative;
+
+      bool r = m_exp < other.m_exp;
+      return negative ? !r : r;
+    }
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig
-		    && m_negative == other.m_negative;
+    return m_exp == other.m_exp && m_sig == other.m_sig;
   }
 
   sreal operator- () const
   {
-    if (m_sig == 0)
-      return *this;
-
     sreal tmp = *this;
-    tmp.m_negative = !tmp.m_negative;
+    tmp.m_sig *= -1;
 
     return tmp;
   }
@@ -125,17 +115,15 @@ public:
 private:
   void normalize ();
   void shift_right (int amount);
-
   static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
   static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
 
-  uint64_t m_sig;			/* Significant.  */
+  int64_t m_sig;			/* Significant.  */
   signed int m_exp;			/* Exponent.  */
-  bool m_negative;			/* Negative sign.  */
 };
 
-extern void debug (sreal &ref);
-extern void debug (sreal *ptr);
+extern void debug (const sreal &ref);
+extern void debug (const sreal *ptr);
 
 inline sreal &operator+= (sreal &a, const sreal &b)
 {
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-12-08 16:53                   ` Martin Liška
@ 2014-12-09 14:15                     ` Richard Biener
  2014-12-10 12:36                       ` Martin Liška
  0 siblings, 1 reply; 38+ messages in thread
From: Richard Biener @ 2014-12-09 14:15 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Mon, Dec 8, 2014 at 5:52 PM, Martin Liška <mliska@suse.cz> wrote:
> On 11/28/2014 10:32 AM, Richard Biener wrote:
>>
>> On Thu, Nov 27, 2014 at 6:08 PM, Martin Liška <mliska@suse.cz> wrote:
>>>
>>> On 11/21/2014 04:21 PM, Martin Liška wrote:
>>>>
>>>>
>>>> On 11/21/2014 04:02 PM, Richard Biener wrote:
>>>>>
>>>>>
>>>>> On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:
>>>>>
>>>>>> Hello.
>>>>>>
>>>>>> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>>>>>>
>>>>>>> that's a  new API, right?  There is no max () and I think that using
>>>>>>> LONG_MIN here is asking for trouble (host dependence).  The
>>>>>>> comment in the file says the max should be
>>>>>>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>>>>>>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>>>>>>
>>>>>>
>>>>>> Sure, sreal can store much bigger(smaller) numbers :)
>>>>>>
>>>>>>> Where do you need sreal::to_double?  The host shouldn't perform
>>>>>>> double calculations so it can be only for dumping?  In which case
>>>>>>> the user should have used sreal::dump (), maybe with extra
>>>>>>> arguments.
>>>>>>>
>>>>>>
>>>>>> That new function was request from Honza, only for debugging purpose.
>>>>>> I agree that dump should this kind of job.
>>>>>>
>>>>>> If no other problem, I will run tests once more and commit it.
>>>>>> Thanks,
>>>>>> Martin
>>>>>
>>>>>
>>>>>
>>>>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>>>>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>>>>
>>>>> this change doesn't look necessary anymore?
>>>>>
>>>>> Btw, it's also odd that...
>>>>>
>>>>>    #define SREAL_PART_BITS 32
>>>>> ...
>>>>>    #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>>>>    #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>>>>
>>>>> thus all m_sig values fit in 32bits but we still use a uint64_t m_sig
>>>>> ...
>>>>> (the implementation uses 64bit for internal computations, but still
>>>>> the storage is wasteful?)
>>>>>
>>>>> Of course the way normalize() works requires that storage to be
>>>>> 64bits to store unnormalized values.
>>>>>
>>>>> I'd say ok with the SREAL_MAX_EXP change reverted.
>>>>>
>>>>
>>>> Hi.
>>>>
>>>> You are right, this change was done because I used one bit for
>>>> m_negative
>>>> (bitfield), not needed any more.
>>>>
>>>> Final version attached.
>>>>
>>>> Thank you,
>>>> Martin
>>>>
>>>>> Thanks,
>>>>> Richard.
>>>>>
>>>>>
>>>>>>
>>>>>>> Otherwise looks good to me and sorry for not noticing the above
>>>>>>> earlier.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Richard.
>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Martin
>>>>>>>>
>>>>>>>>
>>>>>>>>>>      };
>>>>>>>>>>
>>>>>>>>>>      extern void debug (sreal &ref);
>>>>>>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const
>>>>>>>>>> sreal
>>>>>>>>>> &b)
>>>>>>>>>>
>>>>>>>>>>      inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>>>>>>      {
>>>>>>>>>> -return a = a - b;
>>>>>>>>>> +  return a = a - b;
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>>      inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>>>>>>      {
>>>>>>>>>> -return a = a / b;
>>>>>>>>>> +  return a = a / b;
>>>>>>>>>>      }
>>>>>>>>>>
>>>>>>>>>>      inline sreal &operator*= (sreal &a, const sreal &b)
>>>>>>>>>> --
>>>>>>>>>> 2.1.2
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>>
>>> Hello.
>>>
>>> After IRC discussions, I decided to give sreal another refactoring where
>>> I
>>> use int64_t for m_sig.
>>>
>>> This approach looks much easier and straightforward. I would like to
>>> ask folk for comments?
>>
>>
>> I think you want to exclude LONG_MIN (how do you know that LONG_MIN
>> is min(int64_t)?) as a valid value for m_sig - after all SREAL_MIN_SIG
>> makes it symmetric.  Or simply use abs_hwi at
>
>
> Hello.
>
> I decided to use abs_hwi.

That will ICE if you do

  sreal x (- __LONG_MAX__ - 1);

maybe that's the only case though.

 sreal::normalize ()
 {
+  int64_t s = m_sig < 0 ? -1 : 1;
+  HOST_WIDE_INT sig = abs_hwi (m_sig);
+
   if (m_sig == 0)
...
     }
+
+  m_sig = s * sig;
 }

it's a bit awkward to strip the sign and then put it back on this way.  Also
now using a signed 'sig' where it was unsigned before.  And keeping
the first test using m_sig instead of sig.

I'd simply have used 'unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);'
instead.

The rest of the patch is ok with the above change.

Thanks,
Richard.


>>
>> +  int64_t s = m_sig < 0 ? -1 : 1;
>> +  uint64_t sig = m_sig == LONG_MIN ? LONG_MAX : std::abs (m_sig);
>>
>> -#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>> -#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>> +#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 2))
>> +#define SREAL_MAX_SIG (((uint64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
>>
>> shouldn't this also be -2 in the last line?
>
>
> It's correct, in the first line, I s/'SREAL_PART_BITS - 1'/'SREAL_PART_BITS
> - 2' and
> second one is also decremented: s/'SREAL_PART_BITS'/'REAL_PART_BITS - 1'.
>
>>
>> That is, you effectively use the MSB as a sign bit?
>
>
> Yes. It uses signed integer with MSB as a sign bit.
>
>>
>> Btw, a further change would be to make m_sig 'signed int', matching
>> the "real" storage requirements according to SREAL_PART_BITS.
>> This would of course still require temporaries used for computation
>> to be 64bits and it would require normalization to work on the
>> temporaries.  But then we'd get down to 8 bytes storage ...
>
>
> Agree, we can shrink the size for future.
>
> I've been running tests, I hope this implementation is much nicer than
> having bool m_negative. What do you think about trunk acceptation?
>
> Thanks,
> Martin
>
>
>>
>> Richard.
>>
>>
>>> I am able to run profiled bootstrap on x86_64-linux-pc and ppc64-linux-pc
>>> and new regression is introduced.
>>>
>>> Thanks,
>>> Martin
>>>
>>>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 8/9] Negative numbers added for sreal class.
  2014-12-09 14:15                     ` Richard Biener
@ 2014-12-10 12:36                       ` Martin Liška
  0 siblings, 0 replies; 38+ messages in thread
From: Martin Liška @ 2014-12-10 12:36 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 6253 bytes --]

On 12/09/2014 03:15 PM, Richard Biener wrote:
> On Mon, Dec 8, 2014 at 5:52 PM, Martin Liška <mliska@suse.cz> wrote:
>> On 11/28/2014 10:32 AM, Richard Biener wrote:
>>>
>>> On Thu, Nov 27, 2014 at 6:08 PM, Martin Liška <mliska@suse.cz> wrote:
>>>>
>>>> On 11/21/2014 04:21 PM, Martin Liška wrote:
>>>>>
>>>>>
>>>>> On 11/21/2014 04:02 PM, Richard Biener wrote:
>>>>>>
>>>>>>
>>>>>> On Fri, Nov 21, 2014 at 3:39 PM, Martin Liška <mliska@suse.cz> wrote:
>>>>>>
>>>>>>> Hello.
>>>>>>>
>>>>>>> Ok, this is simplified, one can use sreal a = 12345 and it works ;)
>>>>>>>
>>>>>>>> that's a  new API, right?  There is no max () and I think that using
>>>>>>>> LONG_MIN here is asking for trouble (host dependence).  The
>>>>>>>> comment in the file says the max should be
>>>>>>>> sreal (SREAL_MAX_SIG, SREAL_MAX_EXP) and the min
>>>>>>>> sreal (-SREAL_MAX_SIG, SREAL_MAX_EXP)?
>>>>>>>>
>>>>>>>
>>>>>>> Sure, sreal can store much bigger(smaller) numbers :)
>>>>>>>
>>>>>>>> Where do you need sreal::to_double?  The host shouldn't perform
>>>>>>>> double calculations so it can be only for dumping?  In which case
>>>>>>>> the user should have used sreal::dump (), maybe with extra
>>>>>>>> arguments.
>>>>>>>>
>>>>>>>
>>>>>>> That new function was request from Honza, only for debugging purpose.
>>>>>>> I agree that dump should this kind of job.
>>>>>>>
>>>>>>> If no other problem, I will run tests once more and commit it.
>>>>>>> Thanks,
>>>>>>> Martin
>>>>>>
>>>>>>
>>>>>>
>>>>>> -#define SREAL_MAX_EXP (INT_MAX / 4)
>>>>>> +#define SREAL_MAX_EXP (INT_MAX / 8)
>>>>>>
>>>>>> this change doesn't look necessary anymore?
>>>>>>
>>>>>> Btw, it's also odd that...
>>>>>>
>>>>>>     #define SREAL_PART_BITS 32
>>>>>> ...
>>>>>>     #define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>>>>>     #define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>>>>>
>>>>>> thus all m_sig values fit in 32bits but we still use a uint64_t m_sig
>>>>>> ...
>>>>>> (the implementation uses 64bit for internal computations, but still
>>>>>> the storage is wasteful?)
>>>>>>
>>>>>> Of course the way normalize() works requires that storage to be
>>>>>> 64bits to store unnormalized values.
>>>>>>
>>>>>> I'd say ok with the SREAL_MAX_EXP change reverted.
>>>>>>
>>>>>
>>>>> Hi.
>>>>>
>>>>> You are right, this change was done because I used one bit for
>>>>> m_negative
>>>>> (bitfield), not needed any more.
>>>>>
>>>>> Final version attached.
>>>>>
>>>>> Thank you,
>>>>> Martin
>>>>>
>>>>>> Thanks,
>>>>>> Richard.
>>>>>>
>>>>>>
>>>>>>>
>>>>>>>> Otherwise looks good to me and sorry for not noticing the above
>>>>>>>> earlier.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Richard.
>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Martin
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>>>       };
>>>>>>>>>>>
>>>>>>>>>>>       extern void debug (sreal &ref);
>>>>>>>>>>> @@ -76,12 +133,12 @@ inline sreal &operator+= (sreal &a, const
>>>>>>>>>>> sreal
>>>>>>>>>>> &b)
>>>>>>>>>>>
>>>>>>>>>>>       inline sreal &operator-= (sreal &a, const sreal &b)
>>>>>>>>>>>       {
>>>>>>>>>>> -return a = a - b;
>>>>>>>>>>> +  return a = a - b;
>>>>>>>>>>>       }
>>>>>>>>>>>
>>>>>>>>>>>       inline sreal &operator/= (sreal &a, const sreal &b)
>>>>>>>>>>>       {
>>>>>>>>>>> -return a = a / b;
>>>>>>>>>>> +  return a = a / b;
>>>>>>>>>>>       }
>>>>>>>>>>>
>>>>>>>>>>>       inline sreal &operator*= (sreal &a, const sreal &b)
>>>>>>>>>>> --
>>>>>>>>>>> 2.1.2
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>
>>>>
>>>> Hello.
>>>>
>>>> After IRC discussions, I decided to give sreal another refactoring where
>>>> I
>>>> use int64_t for m_sig.
>>>>
>>>> This approach looks much easier and straightforward. I would like to
>>>> ask folk for comments?
>>>
>>>
>>> I think you want to exclude LONG_MIN (how do you know that LONG_MIN
>>> is min(int64_t)?) as a valid value for m_sig - after all SREAL_MIN_SIG
>>> makes it symmetric.  Or simply use abs_hwi at
>>
>>
>> Hello.
>>
>> I decided to use abs_hwi.
>
> That will ICE if you do
>
>    sreal x (- __LONG_MAX__ - 1);
>
> maybe that's the only case though.
>
>   sreal::normalize ()
>   {
> +  int64_t s = m_sig < 0 ? -1 : 1;
> +  HOST_WIDE_INT sig = abs_hwi (m_sig);
> +
>     if (m_sig == 0)
> ...
>       }
> +
> +  m_sig = s * sig;
>   }
>
> it's a bit awkward to strip the sign and then put it back on this way.  Also
> now using a signed 'sig' where it was unsigned before.  And keeping
> the first test using m_sig instead of sig.
>
> I'd simply have used 'unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);'
> instead.
>
> The rest of the patch is ok with the above change.
>
> Thanks,
> Richard.

Hello.

You are right that unsigned type would be more suitable.
I send final version that I plan to commit.

Thanks,
Martin

>
>
>>>
>>> +  int64_t s = m_sig < 0 ? -1 : 1;
>>> +  uint64_t sig = m_sig == LONG_MIN ? LONG_MAX : std::abs (m_sig);
>>>
>>> -#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
>>> -#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
>>> +#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 2))
>>> +#define SREAL_MAX_SIG (((uint64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
>>>
>>> shouldn't this also be -2 in the last line?
>>
>>
>> It's correct, in the first line, I s/'SREAL_PART_BITS - 1'/'SREAL_PART_BITS
>> - 2' and
>> second one is also decremented: s/'SREAL_PART_BITS'/'REAL_PART_BITS - 1'.
>>
>>>
>>> That is, you effectively use the MSB as a sign bit?
>>
>>
>> Yes. It uses signed integer with MSB as a sign bit.
>>
>>>
>>> Btw, a further change would be to make m_sig 'signed int', matching
>>> the "real" storage requirements according to SREAL_PART_BITS.
>>> This would of course still require temporaries used for computation
>>> to be 64bits and it would require normalization to work on the
>>> temporaries.  But then we'd get down to 8 bytes storage ...
>>
>>
>> Agree, we can shrink the size for future.
>>
>> I've been running tests, I hope this implementation is much nicer than
>> having bool m_negative. What do you think about trunk acceptation?
>>
>> Thanks,
>> Martin
>>
>>
>>>
>>> Richard.
>>>
>>>
>>>> I am able to run profiled bootstrap on x86_64-linux-pc and ppc64-linux-pc
>>>> and new regression is introduced.
>>>>
>>>> Thanks,
>>>> Martin
>>>>
>>>>
>>


[-- Attachment #2: 0001-New-sreal-implementation-which-uses-int64_t-as-m_sig.patch --]
[-- Type: text/x-patch, Size: 10414 bytes --]

From b3a25b754e076c6a50b091ea783c2fd045a79647 Mon Sep 17 00:00:00 2001
From: mliska <mliska@suse.cz>
Date: Wed, 26 Nov 2014 15:46:42 +0100
Subject: [PATCH] New sreal implementation which uses int64_t as m_sig.

gcc/ChangeLog:

2014-12-08  Martin Liska  <mliska@suse.cz>

	* sreal.c (sreal::shift_right): New implementation
	for int64_t as m_sig.
	(sreal::normalize): Likewise.
	(sreal::to_int): Likewise.
	(sreal::operator+): Likewise.
	(sreal::operator-): Likewise.
	(sreal::operator*): Likewise.
	(sreal::operator/): Likewise.
	(sreal::signedless_minus): Removed.
	(sreal::signedless_plus): Removed.
	(sreal::debug): const keyword is added.
	* sreal.h (sreal::operator<): New implementation
	for int64_t as m_sig.
	* ipa-inline.c (recursive_inlining): LONG_MIN is replaced
	with sreal::min ().
---
 gcc/ipa-inline.c |   2 +-
 gcc/sreal.c      | 131 +++++++++++++++++--------------------------------------
 gcc/sreal.h      |  56 ++++++++++--------------
 3 files changed, 63 insertions(+), 126 deletions(-)

diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index f62760f..9f600b0 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1311,7 +1311,7 @@ recursive_inlining (struct cgraph_edge *edge,
 		    vec<cgraph_edge *> *new_edges)
 {
   int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
-  edge_heap_t heap (LONG_MIN);
+  edge_heap_t heap (sreal::min ());
   struct cgraph_node *node;
   struct cgraph_edge *e;
   struct cgraph_node *master_clone = NULL, *next;
diff --git a/gcc/sreal.c b/gcc/sreal.c
index 2b5e3ae..bc3af23 100644
--- a/gcc/sreal.c
+++ b/gcc/sreal.c
@@ -61,13 +61,13 @@ sreal::dump (FILE *file) const
 }
 
 DEBUG_FUNCTION void
-debug (sreal &ref)
+debug (const sreal &ref)
 {
   ref.dump (stderr);
 }
 
 DEBUG_FUNCTION void
-debug (sreal *ptr)
+debug (const sreal *ptr)
 {
   if (ptr)
     debug (*ptr);
@@ -91,7 +91,7 @@ sreal::shift_right (int s)
 
   m_exp += s;
 
-  m_sig += (uint64_t) 1 << (s - 1);
+  m_sig += (int64_t) 1 << (s - 1);
   m_sig >>= s;
 }
 
@@ -100,43 +100,45 @@ sreal::shift_right (int s)
 void
 sreal::normalize ()
 {
-  if (m_sig == 0)
+  int64_t s = m_sig < 0 ? -1 : 1;
+  unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
+
+  if (sig == 0)
     {
-      m_negative = 0;
       m_exp = -SREAL_MAX_EXP;
     }
-  else if (m_sig < SREAL_MIN_SIG)
+  else if (sig < SREAL_MIN_SIG)
     {
       do
 	{
-	  m_sig <<= 1;
+	  sig <<= 1;
 	  m_exp--;
 	}
-      while (m_sig < SREAL_MIN_SIG);
+      while (sig < SREAL_MIN_SIG);
 
       /* Check underflow.  */
       if (m_exp < -SREAL_MAX_EXP)
 	{
 	  m_exp = -SREAL_MAX_EXP;
-	  m_sig = 0;
+	  sig = 0;
 	}
     }
-  else if (m_sig > SREAL_MAX_SIG)
+  else if (sig > SREAL_MAX_SIG)
     {
       int last_bit;
       do
 	{
-	  last_bit = m_sig & 1;
-	  m_sig >>= 1;
+	  last_bit = sig & 1;
+	  sig >>= 1;
 	  m_exp++;
 	}
-      while (m_sig > SREAL_MAX_SIG);
+      while (sig > SREAL_MAX_SIG);
 
       /* Round the number.  */
-      m_sig += last_bit;
-      if (m_sig > SREAL_MAX_SIG)
+      sig += last_bit;
+      if (sig > SREAL_MAX_SIG)
 	{
-	  m_sig >>= 1;
+	  sig >>= 1;
 	  m_exp++;
 	}
 
@@ -144,9 +146,11 @@ sreal::normalize ()
       if (m_exp > SREAL_MAX_EXP)
 	{
 	  m_exp = SREAL_MAX_EXP;
-	  m_sig = SREAL_MAX_SIG;
+	  sig = SREAL_MAX_SIG;
 	}
     }
+
+  m_sig = s * sig;
 }
 
 /* Return integer value of *this.  */
@@ -154,17 +158,17 @@ sreal::normalize ()
 int64_t
 sreal::to_int () const
 {
-  int64_t sign = m_negative ? -1 : 1;
+  int64_t sign = m_sig < 0 ? -1 : 1;
 
   if (m_exp <= -SREAL_BITS)
     return 0;
   if (m_exp >= SREAL_PART_BITS)
     return sign * INTTYPE_MAXIMUM (int64_t);
   if (m_exp > 0)
-    return sign * (m_sig << m_exp);
+    return m_sig << m_exp;
   if (m_exp < 0)
-    return sign * (m_sig >> -m_exp);
-  return sign * m_sig;
+    return m_sig >> -m_exp;
+  return m_sig;
 }
 
 /* Return *this + other.  */
@@ -172,36 +176,10 @@ sreal::to_int () const
 sreal
 sreal::operator+ (const sreal &other) const
 {
-  const sreal *a_p = this, *b_p = &other;
-
-  if (a_p->m_negative && !b_p->m_negative)
-    std::swap (a_p, b_p);
-
-  /* a + -b => a - b.  */
-  if (!a_p->m_negative && b_p->m_negative)
-    {
-      sreal tmp = -(*b_p);
-      if (*a_p < tmp)
-	return signedless_minus (tmp, *a_p, true);
-      else
-	return signedless_minus (*a_p, tmp, false);
-    }
-
-  gcc_checking_assert (a_p->m_negative == b_p->m_negative);
-
-  sreal r = signedless_plus (*a_p, *b_p, a_p->m_negative);
-
-  return r;
-}
-
-sreal
-sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
-{
-  const sreal *bb;
-  sreal r, tmp;
   int dexp;
-  const sreal *a_p = &a;
-  const sreal *b_p = &b;
+  sreal tmp, r;
+
+  const sreal *a_p = this, *b_p = &other, *bb;
 
   if (a_p->m_exp < b_p->m_exp)
     std::swap (a_p, b_p);
@@ -211,7 +189,6 @@ sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
   if (dexp > SREAL_BITS)
     {
       r.m_sig = a_p->m_sig;
-      r.m_negative = negative;
       return r;
     }
 
@@ -226,56 +203,32 @@ sreal::signedless_plus (const sreal &a, const sreal &b, bool negative)
 
   r.m_sig = a_p->m_sig + bb->m_sig;
   r.normalize ();
-
-  r.m_negative = negative;
   return r;
 }
 
+
 /* Return *this - other.  */
 
 sreal
 sreal::operator- (const sreal &other) const
 {
-  /* -a - b => -a + (-b).  */
-  if (m_negative && !other.m_negative)
-    return signedless_plus (*this, -other, true);
-
-  /* a - (-b) => a + b.  */
-  if (!m_negative && other.m_negative)
-    return signedless_plus (*this, -other, false);
-
-  gcc_checking_assert (m_negative == other.m_negative);
-
-  /* We want to substract a smaller number from bigger
-    for nonegative numbers.  */
-  if (!m_negative && *this < other)
-    return signedless_minus (other, *this, true);
-
-  /* Example: -2 - (-3) => 3 - 2 */
-  if (m_negative && *this > other)
-    return signedless_minus (-other, -(*this), false);
-
-  sreal r = signedless_minus (*this, other, m_negative);
-
-  return r;
-}
-
-sreal
-sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
-{
   int dexp;
   sreal tmp, r;
   const sreal *bb;
-  const sreal *a_p = &a;
-  const sreal *b_p = &b;
+  const sreal *a_p = this, *b_p = &other;
 
-  dexp = a_p->m_exp - b_p->m_exp;
+  int64_t sign = 1;
+  if (a_p->m_exp < b_p->m_exp)
+    {
+      sign = -1;
+      std::swap (a_p, b_p);
+    }
 
+  dexp = a_p->m_exp - b_p->m_exp;
   r.m_exp = a_p->m_exp;
   if (dexp > SREAL_BITS)
     {
-      r.m_sig = a_p->m_sig;
-      r.m_negative = negative;
+      r.m_sig = sign * a_p->m_sig;
       return r;
     }
   if (dexp == 0)
@@ -287,10 +240,8 @@ sreal::signedless_minus (const sreal &a, const sreal &b, bool negative)
       bb = &tmp;
     }
 
-  r.m_sig = a_p->m_sig - bb->m_sig;
+  r.m_sig = sign * (a_p->m_sig - bb->m_sig);
   r.normalize ();
-
-  r.m_negative = negative;
   return r;
 }
 
@@ -300,7 +251,7 @@ sreal
 sreal::operator* (const sreal &other) const
 {
   sreal r;
-  if (m_sig < SREAL_MIN_SIG || other.m_sig < SREAL_MIN_SIG)
+  if (std::abs (m_sig) < SREAL_MIN_SIG || std::abs (other.m_sig) < SREAL_MIN_SIG)
     {
       r.m_sig = 0;
       r.m_exp = -SREAL_MAX_EXP;
@@ -312,7 +263,6 @@ sreal::operator* (const sreal &other) const
       r.normalize ();
     }
 
-  r.m_negative = m_negative ^ other.m_negative;
   return r;
 }
 
@@ -325,7 +275,6 @@ sreal::operator/ (const sreal &other) const
   sreal r;
   r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig;
   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
-  r.m_negative = m_negative ^ other.m_negative;
   r.normalize ();
   return r;
 }
diff --git a/gcc/sreal.h b/gcc/sreal.h
index 3938c6e..730f49c 100644
--- a/gcc/sreal.h
+++ b/gcc/sreal.h
@@ -25,8 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 
 #define UINT64_BITS	64
 
-#define SREAL_MIN_SIG ((uint64_t) 1 << (SREAL_PART_BITS - 1))
-#define SREAL_MAX_SIG (((uint64_t) 1 << SREAL_PART_BITS) - 1)
+#define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2))
+#define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
 #define SREAL_MAX_EXP (INT_MAX / 4)
 
 #define SREAL_BITS SREAL_PART_BITS
@@ -36,18 +36,11 @@ class sreal
 {
 public:
   /* Construct an uninitialized sreal.  */
-  sreal () : m_sig (-1), m_exp (-1), m_negative (0) {}
+  sreal () : m_sig (-1), m_exp (-1) {}
 
   /* Construct a sreal.  */
-  sreal (int64_t sig, int exp = 0) : m_exp (exp)
+  sreal (int64_t sig, int exp = 0) : m_sig (sig), m_exp (exp)
   {
-    m_negative = sig < 0;
-
-    if (sig < 0)
-      sig = -sig;
-
-    m_sig = (uint64_t) sig;
-
     normalize ();
   }
 
@@ -60,33 +53,30 @@ public:
 
   bool operator< (const sreal &other) const
   {
-    /* We negate result in case of negative numbers and
-       it would return true for equal negative numbers.  */
-    if (*this == other)
-      return false;
-
-    if (m_negative != other.m_negative)
-      return m_negative > other.m_negative;
-
-    bool r = m_exp < other.m_exp
-      || (m_exp == other.m_exp && m_sig < other.m_sig);
-
-    return m_negative ? !r : r;
+    if (m_exp == other.m_exp)
+      return m_sig < other.m_sig;
+    else
+    {
+      bool negative = m_sig < 0;
+      bool other_negative = other.m_sig < 0;
+
+      if (negative != other_negative)
+        return negative > other_negative;
+
+      bool r = m_exp < other.m_exp;
+      return negative ? !r : r;
+    }
   }
 
   bool operator== (const sreal &other) const
   {
-    return m_exp == other.m_exp && m_sig == other.m_sig
-		    && m_negative == other.m_negative;
+    return m_exp == other.m_exp && m_sig == other.m_sig;
   }
 
   sreal operator- () const
   {
-    if (m_sig == 0)
-      return *this;
-
     sreal tmp = *this;
-    tmp.m_negative = !tmp.m_negative;
+    tmp.m_sig *= -1;
 
     return tmp;
   }
@@ -125,17 +115,15 @@ public:
 private:
   void normalize ();
   void shift_right (int amount);
-
   static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
   static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
 
-  uint64_t m_sig;			/* Significant.  */
+  int64_t m_sig;			/* Significant.  */
   signed int m_exp;			/* Exponent.  */
-  bool m_negative;			/* Negative sign.  */
 };
 
-extern void debug (sreal &ref);
-extern void debug (sreal *ptr);
+extern void debug (const sreal &ref);
+extern void debug (const sreal *ptr);
 
 inline sreal &operator+= (sreal &a, const sreal &b)
 {
-- 
2.1.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2014-12-10 12:36 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-13 20:39 [PATCH 1/9] New fibonacci heap and sreal enhancement mliska
2014-11-13 20:39 ` [PATCH 4/9] tracer ported to new fibonacci_heap data structure mliska
2014-11-14  4:31   ` Jeff Law
2014-11-13 20:39 ` [PATCH 6/9] fibonacci_heap is used for var-tracking mliska
2014-11-14  4:45   ` Jeff Law
2014-11-13 20:39 ` [PATCH 7/9] Old libiberty fib_heap removed mliska
2014-11-13 23:54   ` Jan Hubicka
2014-11-14  1:30     ` Jeff Law
2014-11-13 20:39 ` [PATCH 3/9] fibonacci_heap is used for bb-reoder purpose mliska
2014-11-14  4:32   ` Jeff Law
2014-11-19 18:42   ` H.J. Lu
2014-11-13 20:39 ` [PATCH 5/9] bt-load is ported to fibonacci_heap mliska
2014-11-14  4:34   ` Jeff Law
2014-11-13 20:45 ` [PATCH 9/9] ipa-inline uses sreal for as fibonacci_heap template argument mliska
2014-11-14  4:46   ` Jeff Law
2014-11-24 19:25   ` H.J. Lu
2014-11-13 20:50 ` [PATCH 2/9] New template fibonacci_heap class introduced mliska
2014-11-13 21:14   ` mliska
2014-11-13 23:42   ` Jan Hubicka
2014-11-14  5:19   ` Jeff Law
2014-11-14 12:37   ` Florian Weimer
2014-11-13 20:51 ` [PATCH 8/9] Negative numbers added for sreal class mliska
2014-11-13 21:31   ` mliska
2014-11-13 23:44   ` Jan Hubicka
2014-11-14  4:57     ` Trevor Saunders
2014-11-14  4:29   ` Jeff Law
2014-11-14 10:58   ` Richard Biener
2014-11-21 11:30     ` Martin Liška
2014-11-21 12:18       ` Richard Biener
2014-11-21 15:34         ` Martin Liška
2014-11-21 15:46           ` Richard Biener
2014-11-21 15:52             ` Martin Liška
2014-11-27 17:56               ` Martin Liška
2014-11-28 10:10                 ` Richard Biener
2014-12-08 16:53                   ` Martin Liška
2014-12-09 14:15                     ` Richard Biener
2014-12-10 12:36                       ` Martin Liška
2014-11-13 23:42 ` [PATCH 1/9] New fibonacci heap and sreal enhancement Jan Hubicka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).