Changes in include:
* partition.h: New file. Changes in libiberty: * Makefile.in (CFILES): Add partition.c. (REQUIRED_OFILES): Add partition.o. (partition.o): New rule. * partition.c: New file. Changes in gcc: * Makefile.in (ssa.o): New rule. (OBJS): Add ssa.o. (STAGESTUFF): Add *.ssa and *.ussa. (mostlyclean): Delete *.ssa, *.ussa, */*.ssa, */*.ussa. * rtl.def (PHI): New RTL expression. * rtl.h (clear_log_links): New declaration. (convert_to_ssa): Likewise. (convert_from_ssa): Likewise. * flow.c (split_edge): If the entry node falls through to the split edge's source block, split the entry edge. (clear_log_links): New function. * toplev.c (ssa_dump): New variable. (flag_ssa): Likewise. (f_options): Add "ssa". (compile_file): Create SSA dump files. (rest_of_compilation): Go to and from SSA if enabled. (decide_d_option): Handle -de for SSA dump files. * ssa.c: New file. From-SVN: r32465
This commit is contained in:
parent
ea7f51a4af
commit
d9d4fb433e
@ -1,3 +1,25 @@
|
||||
2000-03-09 Richard Henderson <rth@cygnus.com>
|
||||
Alex Samuel <samuel@codesourcery.com> and others
|
||||
|
||||
* Makefile.in (ssa.o): New rule.
|
||||
(OBJS): Add ssa.o.
|
||||
(STAGESTUFF): Add *.ssa and *.ussa.
|
||||
(mostlyclean): Delete *.ssa, *.ussa, */*.ssa, */*.ussa.
|
||||
* rtl.def (PHI): New RTL expression.
|
||||
* rtl.h (clear_log_links): New declaration.
|
||||
(convert_to_ssa): Likewise.
|
||||
(convert_from_ssa): Likewise.
|
||||
* flow.c (split_edge): If the entry node falls through to the
|
||||
split edge's source block, split the entry edge.
|
||||
(clear_log_links): New function.
|
||||
* toplev.c (ssa_dump): New variable.
|
||||
(flag_ssa): Likewise.
|
||||
(f_options): Add "ssa".
|
||||
(compile_file): Create SSA dump files.
|
||||
(rest_of_compilation): Go to and from SSA if enabled.
|
||||
(decide_d_option): Handle -de for SSA dump files.
|
||||
* ssa.c: New file.
|
||||
|
||||
Thu Mar 9 20:01:38 2000 Jim Wilson <wilson@cygnus.com>
|
||||
|
||||
* expr.c (expand_assignment): For a CALL_EXPR, special case PARM_DECL
|
||||
|
@ -674,7 +674,7 @@ OBJS = diagnostic.o \
|
||||
insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \
|
||||
profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o \
|
||||
mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o \
|
||||
predict.o lists.o ggc-common.o $(GGC) simplify-rtx.o
|
||||
predict.o lists.o ggc-common.o $(GGC) simplify-rtx.o ssa.o
|
||||
|
||||
# GEN files are listed separately, so they can be built before doing parallel
|
||||
# makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load
|
||||
@ -704,6 +704,7 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
|
||||
gcov$(exeext) *.bp \
|
||||
*.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop \
|
||||
*.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.gcse *.flow2 *.peephole2 \
|
||||
*.ssa *.ussa \
|
||||
*.[si] libcpp.a \
|
||||
$(LANG_STAGESTUFF)
|
||||
|
||||
@ -1565,6 +1566,8 @@ resource.o : resource.c $(CONFIG_H) $(RTL_H) hard-reg-set.h system.h \
|
||||
insn-attr.h
|
||||
lcm.o : lcm.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
|
||||
real.h insn-config.h insn-attr.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H)
|
||||
ssa.o : ssa.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) $(BASIC_BLOCK_H) \
|
||||
output.h insn-config.h
|
||||
profile.o : profile.c $(CONFIG_H) system.h $(RTL_H) flags.h insn-flags.h \
|
||||
gcov-io.h $(TREE_H) output.h $(REGS_H) toplev.h function.h insn-config.h \
|
||||
ggc.h
|
||||
@ -2355,11 +2358,11 @@ mostlyclean: $(INTL_MOSTLYCLEAN) lang.mostlyclean
|
||||
# Delete debugging dump files.
|
||||
-rm -f *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop
|
||||
-rm -f *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.addressof
|
||||
-rm -f *.regmove *.mach *.bp *.gcse *.flow2 *.peephole2
|
||||
-rm -f *.regmove *.mach *.bp *.gcse *.flow2 *.peephole2 *.ssa *.ussa
|
||||
-rm -f */*.greg */*.lreg */*.combine */*.flow */*.cse */*.jump */*.rtl
|
||||
-rm -f */*.tree */*.loop */*.dbr */*.jump2 */*.sched */*.cse2
|
||||
-rm -f */*.sched2 */*.stack */*.regmove */*.gcse */*.flow2
|
||||
-rm -f */*.peephole2
|
||||
-rm -f */*.peephole2 */*.ssa */*.ussa
|
||||
# Delete some files made during installation.
|
||||
-rm -f specs float.h-* enquire SYSCALLS.c.X SYSCALLS.c
|
||||
-rm -f collect collect2 mips-tfile mips-tdump alloca.s
|
||||
|
16
gcc/flow.c
16
gcc/flow.c
@ -362,6 +362,7 @@ static void fixup_reorder_chain PARAMS ((void));
|
||||
it being unused. */
|
||||
void verify_flow_info PARAMS ((void));
|
||||
int flow_loop_outside_edge_p PARAMS ((const struct loop *, edge));
|
||||
void clear_log_links PARAMS ((rtx));
|
||||
|
||||
/* Find basic blocks of the current function.
|
||||
F is the first insn of the function and NREGS the number of register
|
||||
@ -1369,7 +1370,8 @@ split_edge (edge_in)
|
||||
basic_block jump_block;
|
||||
rtx pos;
|
||||
|
||||
if ((e->flags & EDGE_CRITICAL) == 0)
|
||||
if ((e->flags & EDGE_CRITICAL) == 0
|
||||
&& e->src != ENTRY_BLOCK_PTR)
|
||||
{
|
||||
/* Non critical -- we can simply add a jump to the end
|
||||
of the existing predecessor. */
|
||||
@ -7047,7 +7049,6 @@ flow_loop_outside_edge_p (loop, e)
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct reorder_block_def {
|
||||
int flags;
|
||||
int index;
|
||||
@ -7769,3 +7770,14 @@ reorder_basic_blocks ()
|
||||
flow_loops_free (&loops_info);
|
||||
}
|
||||
|
||||
|
||||
/* Clear LOG_LINKS fields of insns in a chain. */
|
||||
void
|
||||
clear_log_links (insns)
|
||||
rtx insns;
|
||||
{
|
||||
rtx i;
|
||||
for (i = insns; i; i = NEXT_INSN (i))
|
||||
if (GET_RTX_CLASS (GET_CODE (i)) == 'i')
|
||||
LOG_LINKS (i) = 0;
|
||||
}
|
||||
|
15
gcc/rtl.def
15
gcc/rtl.def
@ -880,6 +880,21 @@ DEF_RTL_EXPR(CONSTANT_P_RTX, "constant_p_rtx", "e", 'x')
|
||||
after we select a call method. */
|
||||
DEF_RTL_EXPR(CALL_PLACEHOLDER, "call_placeholder", "uuuu", 'x')
|
||||
|
||||
/* The SSA phi operator.
|
||||
|
||||
The argument is a vector of 2N rtxes. Element 2N+1 is a CONST_INT
|
||||
containing the block number of the predecessor through which control
|
||||
has passed when the register at element 2N is used.
|
||||
|
||||
Note that PHI may only appear at the beginning of a basic block.
|
||||
|
||||
??? There may be multiple PHI insns, but they are all evaluated
|
||||
in parallel. This probably ought to be changed to use a real
|
||||
PARALLEL, as that would be less confusing and more in the spirit
|
||||
of canonical RTL. It is, however, easier to manipulate this way. */
|
||||
DEF_RTL_EXPR(PHI, "phi", "E", 'x')
|
||||
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
mode:c
|
||||
|
@ -1149,6 +1149,7 @@ void free_EXPR_LIST_node PARAMS ((rtx));
|
||||
void free_INSN_LIST_node PARAMS ((rtx));
|
||||
rtx alloc_INSN_LIST PARAMS ((rtx, rtx));
|
||||
rtx alloc_EXPR_LIST PARAMS ((int, rtx, rtx));
|
||||
void clear_log_links PARAMS ((rtx));
|
||||
|
||||
/* regclass.c */
|
||||
|
||||
@ -1710,6 +1711,10 @@ extern rtx addr_side_effect_eval PARAMS ((rtx, int, int));
|
||||
extern int stack_regs_mentioned PARAMS ((rtx insn));
|
||||
#endif
|
||||
|
||||
/* In ssa.c */
|
||||
extern void convert_to_ssa PARAMS ((void));
|
||||
extern void convert_from_ssa PARAMS ((void));
|
||||
|
||||
/* In toplev.c */
|
||||
|
||||
extern rtx stack_limit_rtx;
|
||||
|
39
gcc/toplev.c
39
gcc/toplev.c
@ -257,6 +257,7 @@ int stack_reg_dump = 0;
|
||||
#ifdef MACHINE_DEPENDENT_REORG
|
||||
int mach_dep_reorg_dump = 0;
|
||||
#endif
|
||||
int ssa_dump = 0;
|
||||
static int flag_print_mem = 0;
|
||||
static int version_flag = 0;
|
||||
static char * filename = 0;
|
||||
@ -695,6 +696,9 @@ int flag_gnu_linker = 0;
|
||||
int flag_gnu_linker = 1;
|
||||
#endif
|
||||
|
||||
/* Enable SSA. */
|
||||
int flag_ssa = 0;
|
||||
|
||||
/* Tag all structures with __attribute__(packed) */
|
||||
int flag_pack_struct = 0;
|
||||
|
||||
@ -997,6 +1001,8 @@ lang_independent_options f_options[] =
|
||||
"Suppress output of instruction numbers and line number notes in debugging dumps"},
|
||||
{"instrument-functions", &flag_instrument_function_entry_exit, 1,
|
||||
"Instrument function entry/exit with profiling calls"},
|
||||
{"ssa", &flag_ssa, 1,
|
||||
"Enable SSA optimizations" },
|
||||
{"leading-underscore", &flag_leading_underscore, 1,
|
||||
"External symbols have a leading underscore" },
|
||||
{"ident", &flag_no_ident, 0,
|
||||
@ -2152,6 +2158,11 @@ compile_file (name)
|
||||
if (graph_dump_format != no_graph)
|
||||
clean_graph_dump_file (dump_base_name, ".03.addressof");
|
||||
}
|
||||
if (ssa_dump)
|
||||
{
|
||||
clean_dump_file (".033.ssa");
|
||||
clean_dump_file (".037.ussa");
|
||||
}
|
||||
if (gcse_dump)
|
||||
{
|
||||
clean_dump_file (".04.gcse");
|
||||
@ -3125,6 +3136,30 @@ rest_of_compilation (decl)
|
||||
if (ggc_p)
|
||||
ggc_collect ();
|
||||
|
||||
if (flag_ssa)
|
||||
{
|
||||
if (ssa_dump)
|
||||
open_dump_file (".033.ssa", decl_printable_name (decl, 2));
|
||||
convert_to_ssa ();
|
||||
if (ssa_dump)
|
||||
close_dump_file (print_rtl_with_bb, insns);
|
||||
|
||||
if (ssa_dump)
|
||||
open_dump_file (".037.ussa", decl_printable_name (decl, 2));
|
||||
convert_from_ssa ();
|
||||
/* New registers have been created. Rescan their usage. */
|
||||
reg_scan (insns, max_reg_num (), 1);
|
||||
if (ssa_dump)
|
||||
close_dump_file (print_rtl_with_bb, insns);
|
||||
|
||||
/* Life analysis used in SSA adds log_links but these shouldn't
|
||||
be there until the flow stage, so clear them away. */
|
||||
clear_log_links (insns);
|
||||
|
||||
if (ggc_p)
|
||||
ggc_collect ();
|
||||
}
|
||||
|
||||
/* Perform global cse. */
|
||||
|
||||
if (optimize > 0 && flag_gcse)
|
||||
@ -4021,6 +4056,7 @@ decode_d_option (arg)
|
||||
mach_dep_reorg_dump = 1;
|
||||
#endif
|
||||
peephole2_dump = 1;
|
||||
ssa_dump = 1;
|
||||
break;
|
||||
case 'A':
|
||||
flag_debug_asm = 1;
|
||||
@ -4039,6 +4075,9 @@ decode_d_option (arg)
|
||||
dbr_sched_dump = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'e':
|
||||
ssa_dump = 1;
|
||||
break;
|
||||
case 'f':
|
||||
flow_dump = 1;
|
||||
break;
|
||||
|
@ -1,3 +1,7 @@
|
||||
2000-03-09 Alex Samuel <samuel@codesourcery.com>
|
||||
|
||||
* partition.h: New file.
|
||||
|
||||
2000-03-09 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* hashtab.h (struct htab): Add del_f.
|
||||
|
81
include/partition.h
Normal file
81
include/partition.h
Normal file
@ -0,0 +1,81 @@
|
||||
/* List implentation of a partition of consecutive integers.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
Contributed by CodeSourcery, LLC.
|
||||
|
||||
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, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* This package implements a partition of consecutive integers. The
|
||||
elements are partitioned into classes. Each class is represented
|
||||
by one of its elements, the canonical element, which is chosen
|
||||
arbitrarily from elements in the class. The principal operations
|
||||
on a partition are FIND, which takes an element, determines its
|
||||
class, and returns the canonical element for that class, and UNION,
|
||||
which unites the two classes that contain two given elements into a
|
||||
single class.
|
||||
|
||||
The list implementation used here provides constant-time finds. By
|
||||
storing the size of each class with the class's canonical element,
|
||||
it is able to perform unions over all the classes in the partition
|
||||
in O (N log N) time. */
|
||||
|
||||
#ifndef _PARTITION_H
|
||||
#define _PARTITION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <ansidecl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct partition_elem
|
||||
{
|
||||
/* The canonical element that represents the class containing this
|
||||
element. */
|
||||
int class_element;
|
||||
/* The next element in this class. Elements in each class form a
|
||||
circular list. */
|
||||
struct partition_elem* next;
|
||||
/* The number of elements in this class. Valid only if this is the
|
||||
canonical element for its class. */
|
||||
unsigned class_count;
|
||||
};
|
||||
|
||||
typedef struct partition_def
|
||||
{
|
||||
/* The number of elements in this partition. */
|
||||
int num_elements;
|
||||
/* The elements in the partition. */
|
||||
struct partition_elem elements[1];
|
||||
} *partition;
|
||||
|
||||
extern partition partition_new PARAMS((int));
|
||||
extern void partition_delete PARAMS((partition));
|
||||
extern int partition_union PARAMS((partition,
|
||||
int,
|
||||
int));
|
||||
extern void partition_print PARAMS((partition,
|
||||
FILE*));
|
||||
|
||||
/* Returns the canonical element corresponding to the class containing
|
||||
ELEMENT__ in PARTITION__. */
|
||||
|
||||
#define partition_find(partition__, element__) \
|
||||
((partition__)->elements[(element__)].class_element)
|
||||
|
||||
#endif /* _PARTITION_H */
|
@ -1,3 +1,10 @@
|
||||
2000-03-09 Alex Samuel <samuel@codesourcery.com>
|
||||
|
||||
* Makefile.in (CFILES): Add partition.c.
|
||||
(REQUIRED_OFILES): Add partition.o.
|
||||
(partition.o): New rule.
|
||||
* partition.c: New file.
|
||||
|
||||
2000-03-09 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* hashtab.c (htab_create): Set del_f.
|
||||
|
@ -123,21 +123,22 @@ HFILES = alloca-conf.h
|
||||
# NOTE: If you add new files to the library, add them to this list
|
||||
# (alphabetical), and add them to REQUIRED_OFILES or funcs in
|
||||
# configure.in.
|
||||
CFILES = asprintf.c alloca.c argv.c atexit.c basename.c bcmp.c bcopy.c \
|
||||
CFILES = asprintf.c alloca.c argv.c atexit.c basename.c bcmp.c bcopy.c \
|
||||
bzero.c calloc.c choose-temp.c clock.c concat.c cplus-dem.c fdmatch.c \
|
||||
fnmatch.c getcwd.c getpwd.c getopt.c getopt1.c getpagesize.c \
|
||||
getruntime.c floatformat.c hashtab.c hex.c index.c insque.c memchr.c \
|
||||
memcmp.c memcpy.c memmove.c memset.c mkstemps.c objalloc.c obstack.c \
|
||||
pexecute.c putenv.c random.c rename.c rindex.c setenv.c sigsetmask.c \
|
||||
spaces.c splay-tree.c strcasecmp.c strncasecmp.c strchr.c strdup.c \
|
||||
strerror.c strrchr.c strsignal.c strstr.c strtod.c strtol.c strtoul.c \
|
||||
tmpnam.c vasprintf.c vfork.c vfprintf.c vprintf.c vsprintf.c \
|
||||
waitpid.c xatexit.c xexit.c xmalloc.c xmemdup.c xstrdup.c xstrerror.c
|
||||
fnmatch.c getcwd.c getpwd.c getopt.c getopt1.c getpagesize.c \
|
||||
getruntime.c floatformat.c hashtab.c hex.c index.c insque.c memchr.c \
|
||||
memcmp.c memcpy.c memmove.c memset.c mkstemps.c objalloc.c obstack.c \
|
||||
partition.c pexecute.c putenv.c random.c rename.c rindex.c \
|
||||
setenv.c sigsetmask.c spaces.c splay-tree.c strcasecmp.c \
|
||||
strncasecmp.c strchr.c strdup.c strerror.c strrchr.c \
|
||||
strsignal.c strstr.c strtod.c strtol.c strtoul.c tmpnam.c \
|
||||
vasprintf.c vfork.c vfprintf.c vprintf.c vsprintf.c waitpid.c \
|
||||
xatexit.c xexit.c xmalloc.c xmemdup.c xstrdup.c xstrerror.c
|
||||
|
||||
# These are always included in the library.
|
||||
REQUIRED_OFILES = argv.o choose-temp.o concat.o cplus-dem.o \
|
||||
fdmatch.o fnmatch.o getopt.o getopt1.o getpwd.o getruntime.o hashtab.o \
|
||||
hex.o floatformat.o objalloc.o obstack.o pexecute.o spaces.o \
|
||||
hex.o floatformat.o objalloc.o obstack.o partition.o pexecute.o spaces.o \
|
||||
splay-tree.o strerror.o strsignal.o xatexit.o xexit.o xmalloc.o \
|
||||
xmemdup.o xstrdup.o xstrerror.o
|
||||
|
||||
@ -271,6 +272,7 @@ floatformat.o: $(INCDIR)/floatformat.h
|
||||
mkstemps.o: config.h
|
||||
objalloc.o: $(INCDIR)/objalloc.h
|
||||
obstack.o: config.h $(INCDIR)/obstack.h
|
||||
partition.o: $(INCDIR)/partition.h
|
||||
pexecute.o: config.h $(INCDIR)/libiberty.h
|
||||
setenv.o: config.h
|
||||
spaces.o: $(INCDIR)/libiberty.h
|
||||
|
185
libiberty/partition.c
Normal file
185
libiberty/partition.c
Normal file
@ -0,0 +1,185 @@
|
||||
/* List implentation of a partition of consecutive integers.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
Contributed by CodeSourcery, LLC.
|
||||
|
||||
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, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "partition.h"
|
||||
|
||||
/* Creates a partition of NUM_ELEMENTS elements. Initially each
|
||||
element is in a class by itself. */
|
||||
|
||||
partition
|
||||
partition_new (num_elements)
|
||||
int num_elements;
|
||||
{
|
||||
int e;
|
||||
|
||||
partition part = (partition)
|
||||
xmalloc (sizeof (struct partition_def) +
|
||||
(num_elements - 1) * sizeof (struct partition_elem));
|
||||
part->num_elements = num_elements;
|
||||
for (e = 0; e < num_elements; ++e)
|
||||
{
|
||||
part->elements[e].class_element = e;
|
||||
part->elements[e].next = &(part->elements[e]);
|
||||
part->elements[e].class_count = 1;
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/* Freeds a partition. */
|
||||
|
||||
void
|
||||
partition_delete (part)
|
||||
partition part;
|
||||
{
|
||||
free (part);
|
||||
}
|
||||
|
||||
/* Unites the classes containing ELEM1 and ELEM2 into a single class
|
||||
of partition PART. If ELEM1 and ELEM2 are already in the same
|
||||
class, does nothing. Returns the canonical element of the
|
||||
resulting union class. */
|
||||
|
||||
int
|
||||
partition_union (part, elem1, elem2)
|
||||
partition part;
|
||||
int elem1;
|
||||
int elem2;
|
||||
{
|
||||
struct partition_elem *elements = part->elements;
|
||||
struct partition_elem *e1;
|
||||
struct partition_elem *e2;
|
||||
struct partition_elem *p;
|
||||
struct partition_elem *old_next;
|
||||
/* The canonical element of the resulting union class. */
|
||||
int class_element = elements[elem1].class_element;
|
||||
|
||||
/* If they're already in the same class, do nothing. */
|
||||
if (class_element == elements[elem2].class_element)
|
||||
return class_element;
|
||||
|
||||
/* Make sure ELEM1 is in the larger class of the two. If not, swap
|
||||
them. This way we always scan the shorter list. */
|
||||
if (elements[elem1].class_count < elements[elem2].class_count)
|
||||
{
|
||||
int temp = elem1;
|
||||
elem1 = elem2;
|
||||
elem2 = temp;
|
||||
class_element = elements[elem1].class_element;
|
||||
}
|
||||
|
||||
e1 = &(elements[elem1]);
|
||||
e2 = &(elements[elem2]);
|
||||
|
||||
/* Keep a count of the number of elements in the list. */
|
||||
elements[class_element].class_count
|
||||
+= elements[e2->class_element].class_count;
|
||||
|
||||
/* Update the class fields in elem2's class list. */
|
||||
e2->class_element = class_element;
|
||||
for (p = e2->next; p != e2; p = p->next)
|
||||
p->class_element = class_element;
|
||||
|
||||
/* Splice ELEM2's class list into ELEM1's. These are circular
|
||||
lists. */
|
||||
old_next = e1->next;
|
||||
e1->next = e2->next;
|
||||
e2->next = old_next;
|
||||
|
||||
return class_element;
|
||||
}
|
||||
|
||||
/* Compare elements ELEM1 and ELEM2 from array of integers, given a
|
||||
pointer to each. Used to qsort such an array. */
|
||||
|
||||
static int
|
||||
elem_compare (elem1, elem2)
|
||||
const void *elem1;
|
||||
const void *elem2;
|
||||
{
|
||||
int e1 = * (int *) elem1;
|
||||
int e2 = * (int *) elem2;
|
||||
if (e1 < e2)
|
||||
return -1;
|
||||
else if (e1 > e2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prints PART to the file pointer FP. The elements of each
|
||||
class are sorted. */
|
||||
|
||||
void
|
||||
partition_print (part, fp)
|
||||
partition part;
|
||||
FILE *fp;
|
||||
{
|
||||
char *done;
|
||||
int num_elements = part->num_elements;
|
||||
struct partition_elem *elements = part->elements;
|
||||
int *class_elements;
|
||||
int e;
|
||||
|
||||
/* Flag the elements we've already printed. */
|
||||
done = (char *) xmalloc (num_elements);
|
||||
memset (done, 0, num_elements);
|
||||
|
||||
/* A buffer used to sort elements in a class. */
|
||||
class_elements = (int *) xmalloc (num_elements * sizeof (int));
|
||||
|
||||
fputc ('[', fp);
|
||||
for (e = 0; e < num_elements; ++e)
|
||||
/* If we haven't printed this element, print its entire class. */
|
||||
if (! done[e])
|
||||
{
|
||||
int c = e;
|
||||
int count = elements[elements[e].class_element].class_count;
|
||||
int i;
|
||||
|
||||
/* Collect the elements in this class. */
|
||||
for (i = 0; i < count; ++i) {
|
||||
class_elements[i] = c;
|
||||
done[c] = 1;
|
||||
c = elements[c].next - elements;
|
||||
}
|
||||
/* Sort them. */
|
||||
qsort ((void *) class_elements, count, sizeof (int), &elem_compare);
|
||||
/* Print them. */
|
||||
fputc ('(', fp);
|
||||
for (i = 0; i < count; ++i)
|
||||
fprintf (fp, i == 0 ? "%d" : " %d", class_elements[i]);
|
||||
fputc (')', fp);
|
||||
}
|
||||
fputc (']', fp);
|
||||
|
||||
free (done);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user