develooper Front page | perl.cvs.parrot | Postings from December 2008

[svn:parrot] r33884 - trunk/compilers/pirc/new

From:
kjs
Date:
December 14, 2008 08:26
Subject:
[svn:parrot] r33884 - trunk/compilers/pirc/new
Message ID:
20081214162604.369EACBA12@x12.develooper.com
Author: kjs
Date: Sun Dec 14 08:26:03 2008
New Revision: 33884

Modified:
   trunk/compilers/pirc/new/pirregalloc.c
   trunk/compilers/pirc/new/pirregalloc.h

Log:
[pirc] implement re-use of live_interval objects; no need to malloc() and free(), if they can be cached.

Modified: trunk/compilers/pirc/new/pirregalloc.c
==============================================================================
--- trunk/compilers/pirc/new/pirregalloc.c	(original)
+++ trunk/compilers/pirc/new/pirregalloc.c	Sun Dec 14 08:26:03 2008
@@ -24,23 +24,20 @@
 
 */
 
-
 /*
 
-=item C<lsr_allocator *
-new_linear_scan_register_allocator(void)>
+=item C<static void
+reset_register_count(lsr_allocator * const lsr)>
 
-Constructor for a linear scan register allocator.
-Initializates the allocator, and returns it.
+Reset the register counters; there's one counter for each register
+type (string, num, int, pmc).
 
 =cut
 
 */
-lsr_allocator *
-new_linear_scan_register_allocator(struct lexer_state *lexer) {
-    lsr_allocator *lsr = (lsr_allocator *)mem_sys_allocate_zeroed(sizeof (lsr_allocator));
+static void
+reset_register_count(lsr_allocator * const lsr) {
     int i;
-
     /* the "r" field keeps track of the number of registers that must be allocated by
      * parrot. In the original implementation, "r" is constant, and indicates the number
      * of available registers. In parrot, this is flexible, so we increment it only
@@ -50,6 +47,22 @@
      */
     for (i = 0; i < 4; ++i)
         lsr->r[i] = 1;
+}
+
+/*
+
+=item C<lsr_allocator *
+new_linear_scan_register_allocator(struct lexer_state * lexer)>
+
+Constructor for a linear scan register allocator.
+Initializates the allocator, and returns it.
+
+=cut
+
+*/
+lsr_allocator *
+new_linear_scan_register_allocator(struct lexer_state *lexer) {
+    lsr_allocator *lsr = (lsr_allocator *)mem_sys_allocate_zeroed(sizeof (lsr_allocator));
 
     lsr->lexer = lexer;
 
@@ -135,15 +148,31 @@
 PARROT_WARN_UNUSED_RESULT
 live_interval *
 new_live_interval(lsr_allocator * const lsr, unsigned firstuse_location, pir_type type) {
-    live_interval *i = (live_interval *)mem_sys_allocate_zeroed(sizeof (live_interval));
-    static int count = 0;
+    live_interval *i;
+    /* check whether there's an interval object that we can re-use, to prevent
+     * memory malloc() and free()s.
+     */
+    if (lsr->cached_intervals) {
+
+        i = lsr->cached_intervals;
+        lsr->cached_intervals = i->nextc;
+
+        /* clear fields */
+        i->nexti = i->previ   = NULL;
+        i->nexta = i->preva   = NULL;
+        i->nextc = NULL;
+    }
+    else {
+        /* there's no interval object to be re-used (none allocated yet, or all are used). */
+        i = (live_interval *)mem_sys_allocate_zeroed(sizeof (live_interval));
+    }
 
     /* this is the first usage of the register, and up to now also the last */
     i->startpoint = i->endpoint = firstuse_location;
 
-    /*fprintf(stderr, "Live interval %d (location: %u)\n", ++count, firstuse_location);*/
     add_live_interval(lsr, i, type);
     return i;
+
 }
 
 /*
@@ -242,6 +271,7 @@
         return;
     }
 
+    /* look for the right place to insert; sort on increasing end point */
     while (iter->nexta && iter->endpoint < i->endpoint) {
         iter = iter->nexta;
     }
@@ -415,6 +445,24 @@
 
 /*
 
+=item C<static void
+cache_interval_objects(lsr_allocator * const lsr, live_interval * interval)>
+
+Store the interval C<interval> on a caching list; whenever a new C<live_interval>
+object is requested, these interval objects can be re-used, instead of malloc()ing
+a new one.
+
+=cut
+
+*/
+static void
+cache_interval_object(lsr_allocator * const lsr, live_interval * interval) {
+    interval->nextc = lsr->cached_intervals;
+    lsr->cached_intervals = interval;
+}
+
+/*
+
 =item C<void
 linear_scan_register_allocation(lsr_allocator * const lsr)>
 
@@ -428,10 +476,17 @@
 void
 linear_scan_register_allocation(lsr_allocator * const lsr) {
     live_interval * i;
+    live_interval *tmp;
     pir_type type = 0; /* types run from 0 to 4; see pircompunit.h */
 
+    reset_register_count(lsr);
+
     for (type = 0; type < 4; ++type) { /* handle each of the 4 parrot types separately. */
 
+        /* cache the objects on the active list for reuse */
+        for (i = lsr->active[type]; i != NULL; i = i->nexta)
+            cache_interval_object(lsr, i);
+
         /* intialize active intervals list to NULL */
         lsr->active[type] = NULL;
 
@@ -440,6 +495,11 @@
         */
         for (i = lsr->intervals[type]; i != NULL; i = i->nexti) {
 
+            /* expire all intervals whose endpoint is smaller than i's start
+             * point; that means that i can be mapped to a register that was
+             * previously assigned to one of the expired intervals; that one
+             * is no longer needed (hence it expired).
+             */
             expire_old_intervals(lsr, i, type);
 
             /* get a free register */
@@ -453,10 +513,15 @@
             add_interval_to_active(lsr, i, type);
         }
 
+         /* cache the objects on the list for reuse */
+        for (tmp = lsr->intervals[type]; tmp != NULL; tmp = tmp->nexti)
+            cache_interval_object(lsr, tmp);
+
         /* clear list of intervals */
         lsr->intervals[type] = NULL;
     }
 
+    /* update the register usage in the current subroutine structure. */
     update_sub_register_usage(lsr->lexer, lsr->r);
 
 }

Modified: trunk/compilers/pirc/new/pirregalloc.h
==============================================================================
--- trunk/compilers/pirc/new/pirregalloc.h	(original)
+++ trunk/compilers/pirc/new/pirregalloc.h	Sun Dec 14 08:26:03 2008
@@ -47,6 +47,9 @@
         struct   live_interval *preva;
 /*    } prev; */
 
+    /* pointer to next on the cached objects list. */
+    struct live_interval *nextc;
+
 } live_interval;
 
 /* structure to store a second-hand register, so we can re-use it later. */
@@ -68,6 +71,11 @@
     /* reusable registers; were used by variables, which are now "dead"; (1 list per type) */
     free_reg      *free_regs[4];
 
+    /* list of cached intervals; don't malloc/free objects, but keep them on a list
+     * and re-used malloc()ed objects. Only free them when destroying the lsr.
+     */
+    live_interval *cached_intervals;
+
     /* list of free_reg objects that we can re-use, to save memory allocations. */
     free_reg      *cached_regs;
 



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About