home *** CD-ROM | disk | FTP | other *** search
- /* $Id: partset.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */
- /*
- This software is subject to the terms of the IBM Jikes Compiler
- License Agreement available at the following URL:
- http://www.ibm.com/research/jikes.
- Copyright (C) 1983, 1999, International Business Machines Corporation
- and others. All Rights Reserved.
- You must accept the terms of that agreement to use this software.
- */
- static char hostfile[] = __FILE__;
-
- #include "common.h"
- #include "header.h"
-
- #define B_ASSIGN_SET(s1, dest, s2, source, bound) \
- { int j; \
- for (j = 0; j < bound; j++) \
- s1[dest * bound + j] = s2[source * bound + j]; \
- }
-
- #define B_SET_UNION(s1, dest, s2, source, bound) \
- { int j; \
- for (j = 0; j < bound; j++) \
- s1[dest * bound + j] |= s2[source * bound + j]; \
- }
-
- static BOOLEAN equal_sets(SET_PTR set1, int indx1,
- SET_PTR set2, int indx2, int bound);
-
-
- /*********************************************************************/
- /* PARTSET: */
- /*********************************************************************/
- /* This procedure, PARTSET, is invoked to apply a heuristic of the */
- /* Optimal Partitioning algorithm to a COLLECTION of subsets. The */
- /* size of each subset in COLLECTION is passed in a parallel vector: */
- /* ELEMENT_SIZE. Let SET_SIZE be the length of the bit_strings used */
- /* to represent the subsets in COLLECTION, the universe of the */
- /* subsets is the set of integers: [1..SET_SIZE]. */
- /* The third argument, LIST, is a vector identifying the order in */
- /* which the subsets in COLLECTION must be processed when they are */
- /* output. */
- /* The last two arguments, START and STACK are output parameters. */
- /* We recall that the output of Optimal Partitioning is two vectors: */
- /* a BASE vector and a RANGE vector... START is the base vector. */
- /* It is used to indicate the starting position in the range */
- /* vector for each subset. When a subset shares elements with */
- /* another subset, this is indicated by in index in START being */
- /* negative. START also contains an extra "fence" element. I.e., */
- /* it has one more element than COLLECTION. */
- /* STACK is a vector used to construct a partition of the elements */
- /* of COLLECTION. That partition is used later (in ctabs or tabutil) */
- /* to output the final range vector... */
- /* */
- /*********************************************************************/
- /* */
- /* We first merge all sets that are identical. A hash table is used */
- /* to keep track of subsets that have already been seen. */
- /* DOMAIN_TABLE is used as the base of the hash table. DOMAIN_LINK */
- /* is used to link subsets that collided. */
- /* */
- /* The next step is to partition the unique subsets in the hash */
- /* table based on the number of elements they contain. The vector */
- /* PARTITION is used for that purpose. */
- /* */
- /* Finally, we attempt to overlay as many subsets as possible by */
- /* performing the following steps: */
- /* */
- /* 1) Choose a base set in the partition with the largest subsets */
- /* and push it into a stack. (using the vector STACK) */
- /* */
- /* 2) Iterate over the remaining non_empty elements of the partitions*/
- /* in decreasing order of the size of the subsets contained in the*/
- /* element in question. If there exists a subset in the element */
- /* which is a subset of the subset on top of the stack, currently */
- /* being constructed, remove it from the partition, and push it */
- /* into the stack. Repeat step 2 until the partition is empty. */
- /* */
- /*********************************************************************/
- void partset(SET_PTR collection,
- short *element_size, short *list,
- short *start, short *stack, int set_size)
- {
- unsigned long hash_address;
-
- int collection_size,
- offset,
- i,
- previous,
- base_set,
- size_root,
- next_size,
- size,
- bctype,
- j,
- index,
- subset;
-
- short domain_table[STATE_TABLE_SIZE],
- *domain_link,
- *size_list,
- *partition,
- *next,
- *head;
-
- BOOLEAN *is_a_base;
-
- SET_PTR temp_set;
-
- collection_size = num_states;
- if (set_size == num_terminals)
- {
- bctype = term_set_size;
- collection_size = num_states;
- }
- else if (set_size == num_non_terminals)
- {
- bctype = non_term_set_size;
- collection_size = num_states;
- }
- else /* called from scope processing */
- {
- bctype = num_states / SIZEOF_BC
- + (num_states % SIZEOF_BC ? 1 : 0);
- collection_size = set_size;
- set_size = num_states;
- }
- size_list = Allocate_short_array(set_size + 1);
- partition = Allocate_short_array(set_size + 1);
- domain_link = Allocate_short_array(collection_size + 1);
- head = Allocate_short_array(collection_size + 1);
- next = Allocate_short_array(collection_size + 1);
- is_a_base = Allocate_boolean_array(collection_size + 1);
- temp_set = (SET_PTR)
- calloc(1, bctype * sizeof(BOOLEAN_CELL));
- if (temp_set == NULL)
- nospace(__FILE__, __LINE__);
-
- /********************************************************************/
- /* DOMAIN_TABLE is the base of a hash table used to compute the set */
- /* of unique subsets in COLLECTION. Collisions are resolved by links*/
- /* which are implemented in DOMAIN_LINK. */
- /* HEAD is an array containing either the value OMEGA which */
- /* indicates that the corresponding subset in COLLECTION is */
- /* identical to another set, or it contains the "root" of a list of */
- /* subsets that are identical. The elements of the list are placed */
- /* in the array NEXT. When a state is at te root of a list, it is */
- /* used as a representative of that list. */
- /********************************************************************/
- for (i = 0; i <= STATE_TABLE_UBOUND; i++)
- domain_table[i] = NIL;
-
- /*************************************************************/
- /* We now iterate over the states and attempt to insert each */
- /* domain set into the hash table... */
- /*************************************************************/
- for (index = 1; index <= collection_size; index++)
- {
- hash_address = 0;
- for (i = 0; i < bctype; i++)
- hash_address += collection[index * bctype + i];
-
- hash_address %= STATE_TABLE_SIZE;
-
- /***************************************************************/
- /* Next, we search the hash table to see if the subset was */
- /* already inserted in it. If we find such a subset, we simply */
- /* add INDEX to a list associated with the subset found and */
- /* mark it as a duplicate by setting the head of its list to */
- /* OMEGA. Otherwise, we have a new set... */
- /***************************************************************/
- for (i = domain_table[hash_address]; i != NIL; i = domain_link[i])
- {
- if (equal_sets(collection, index, collection, i, bctype))
- {
- head[index] = OMEGA;
- next[index] = head[i];
- head[i] = index;
- goto continu;
- }
- }
-
- /*************************************************************/
- /* ...Subset indicated by INDEX not previously seen. Insert */
- /* it into the hash table, and initialize a new list with it.*/
- /*************************************************************/
- domain_link[index] = domain_table[hash_address];
- domain_table[hash_address] = index;
- head[index] = NIL; /* Start a new list */
- continu: ;
- }
-
- /*************************************************************/
- /* We now partition all the unique sets in the hash table */
- /* based on the number of elements they contain... */
- /* NEXT is also used to construct these lists. Recall that */
- /* the unique elements are roots of lists. Hence, their */
- /* corresponding HEAD elements are used, but their */
- /* corresponding NEXT field is still unused. */
- /*************************************************************/
- for (i = 0; i <= set_size; i++)
- partition[i] = NIL;
-
- for (index = 1; index <= collection_size; index++)
- {
- if (head[index] != OMEGA) /* Subset representative */
- {
- size = element_size[index];
- next[index] = partition[size];
- partition[size] = index;
- }
- }
-
- /*************************************************************/
- /* ...Construct a list of all the elements of PARTITION */
- /* that are not empty. Only elements in this list will be */
- /* considered for subset merging later ... */
- /* Note that since the elements of PARTITION are added to */
- /* the list in ascending order and in stack-fashion, the */
- /* resulting list will be sorted in descending order. */
- /*************************************************************/
- size_root = NIL;
- for (i = 0; i <= set_size; i++)
- {
- if (partition[i] != NIL)
- {
- size_list[i] = size_root;
- size_root = i;
- }
- }
-
- /*************************************************************/
- /* Merge subsets that are mergeable using heuristic described*/
- /* above. The vector IS_A_BASE is used to mark subsets */
- /* chosen as bases. */
- /*************************************************************/
- for (i = 0; i <= collection_size; i++)
- is_a_base[i] = FALSE;
- for (size = size_root; size != NIL; size = size_list[size])
- { /* For biggest partition there is */
- for (base_set = partition[size];
- base_set != NIL; base_set = next[base_set])
- { /* For each set in it... */
- /*****************************************************/
- /* Mark the state as a base state, and initialize */
- /* its stack. The list representing the stack will */
- /* be circular... */
- /*****************************************************/
- is_a_base[base_set] = TRUE;
- stack[base_set] = base_set;
-
- /**************************************************************/
- /* For remaining elements in partitions in decreasing order...*/
- /**************************************************************/
-
- for (next_size = size_list[size];
- next_size != NIL; next_size = size_list[next_size])
- {
- previous = NIL; /* mark head of list */
-
- /**************************************************/
- /* Iterate over subsets in the partition until we */
- /* find one that is a subset of the subset on top */
- /* of the stack. If none is found, we go on to */
- /* the next element of the partition. Otherwise, */
- /* we push the new subset on top of the stack and */
- /* go on to the next element of the partition. */
- /* INDEX identifies the state currently on top */
- /* of the stack. */
- /**************************************************/
- for (subset = partition[next_size];
- subset != NIL;
- previous = subset, subset = next[subset])
- {
- index = stack[base_set];
- B_ASSIGN_SET(temp_set, 0, collection, index, bctype);
- B_SET_UNION(temp_set, 0, collection, subset, bctype);
-
- /* SUBSET is a subset of INDEX?*/
- if (equal_sets(temp_set, 0, collection, index, bctype))
- {
- if (previous == NIL)
- partition[next_size] = next[subset];
- else
- next[previous] = next[subset];
- stack[subset] = stack[base_set];
- stack[base_set] = subset;
- break; /* for (subset = partition[next_size]... */
- }
- }
- }
- }
- }
-
- /*************************************************************/
- /* Iterate over the states in the order in which they are to */
- /* be output, and assign an offset location to each state. */
- /* Notice that an extra element is added to the size of each */
- /* base subset for the "fence" element. */
- /*************************************************************/
- offset = 1;
- for (i= 1; i<= collection_size; i++)
- {
- base_set = list[i];
- if (is_a_base[base_set])
- {
- start[base_set] = offset;
- /***********************************************************/
- /* Assign the same offset to each subset that is */
- /* identical to the BASE_SET subset in question. Also, */
- /* mark the fact that this is a copy by using the negative */
- /* value of the OFFSET. */
- /***********************************************************/
- for (index = head[base_set]; index != NIL; index = next[index])
- start[index] = - start[base_set];
-
- size = element_size[base_set] + 1;
- offset += size;
- SHORT_CHECK(offset);
-
- /*********************************************************/
- /* Now, assign offset values to each subset of the */
- /* BASE_SET. Once again, we mark them as sharing elements*/
- /* by using the negative value of the OFFSET. */
- /* Recall that the stack is constructed as a circular */
- /* list. Therefore, its end is reached when we go back */
- /* to the root... In this case, the root is already */
- /* processed, so we stop when we reach it. */
- /*********************************************************/
- for (index = stack[base_set];
- index != base_set; index = stack[index])
- {
- size = element_size[index] + 1;
- start[index] = -(offset - size);
-
- /*****************************************************/
- /* INDEX identifies a subset of BASE_SET. Assign the */
- /* same offset as INDEX to each subset j that is */
- /* identical to the subset INDEX. */
- /*****************************************************/
- for (j = head[index]; j != NIL; j = next[j])
- start[j] = start[index];
- }
- }
- }
- start[collection_size+1] = offset;
-
- ffree(size_list);
- ffree(partition);
- ffree(domain_link);
- ffree(head);
- ffree(next);
- ffree(is_a_base);
- ffree(temp_set);
-
- return;
- }
-
-
- /****************************************************************************/
- /* EQUAL_SETS: */
- /****************************************************************************/
- /* EQUAL_SETS checks to see if two sets are equal and returns True or False */
- /****************************************************************************/
- static BOOLEAN equal_sets(SET_PTR set1, int indx1,
- SET_PTR set2, int indx2, int bound)
- {
- register int i;
-
- for (i = 0; i < bound; i++)
- {
- if (set1[indx1 * bound + i] != set2[indx2 * bound + i])
- return(0);
- }
-
- return(TRUE);
- }
-