This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
x*alloc optimizations
- To: egcs at cygnus dot com
- Subject: x*alloc optimizations
- From: Richard Henderson <rth at cygnus dot com>
- Date: Sat, 16 May 1998 14:53:45 -0700
- Reply-To: Richard Henderson <rth at cygnus dot com>
Two things.
(1) Since we define xrealloc, we can trust it to do the right thing
when given a NULL initial argument.
(2) Using calloc instead of malloc+bzero can be more efficient. At
least glibc's calloc knows that space newly acquired from the
system is already zero. This is particularaly relevant to the
large memory blocks gcc tends to allocate during optimization.
r~
Sat May 16 14:24:34 1998 Richard Henderson <rth@cygnus.com>
* c-common.c (c_expand_start_cond): Trust xrealloc to function
correctly with first parameter NULL.
* c-typeck.c (PUSH_SPELLING): Likewise.
(get_spelling): Likewise.
* scan.c (make_sstring_space): Likewise.
* dbxout.c (dbxout_init): Use xcalloc instead of xmalloc+bzero.
* dwarf2out.c (dwarf2out_frame_init): Likewise.
* except.c (find_exception_handler_labels): Likewise.
* final.c (shorten_branches): Likewise.
* flow.c (find_basic_blocks): Likewise.
* global.c (global_alloc): Likewise.
* haifa-sched.c (build_control_flow): Likewise.
* stmt.c (check_for_full_enumeration_handling): Likewise.
(estimate_case_costs): Likewise.
* local-alloc.c (local_alloc): Likewise.
* rtl.h, tree.h: Prototype xcalloc.
* toplev.c (xcalloc): New function.
Index: c-common.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.c,v
retrieving revision 1.20
diff -c -p -d -r1.20 c-common.c
*** c-common.c 1998/05/06 21:06:41 1.20
--- c-common.c 1998/05/16 21:22:15
*************** c_expand_start_cond (cond, exitflag, com
*** 87,98 ****
int compstmt_count;
{
/* Make sure there is enough space on the stack. */
! if (if_stack_space == 0)
! {
! if_stack_space = 10;
! if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt));
! }
! else if (if_stack_space == if_stack_pointer)
{
if_stack_space += 10;
if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt));
--- 87,93 ----
int compstmt_count;
{
/* Make sure there is enough space on the stack. */
! if (if_stack_space == if_stack_pointer)
{
if_stack_space += 10;
if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt));
Index: c-typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-typeck.c,v
retrieving revision 1.16
diff -c -p -d -r1.16 c-typeck.c
*** c-typeck.c 1998/05/06 21:06:44 1.16
--- c-typeck.c 1998/05/16 21:22:16
*************** static int spelling_size; /* Size of th
*** 4612,4624 ****
if (depth >= spelling_size) \
{ \
spelling_size += 10; \
! if (spelling_base == 0) \
! spelling_base \
! = (struct spelling *) xmalloc (spelling_size * sizeof (struct spelling)); \
! else \
! spelling_base \
! = (struct spelling *) xrealloc (spelling_base, \
! spelling_size * sizeof (struct spelling)); \
RESTORE_SPELLING_DEPTH (depth); \
} \
\
--- 4612,4619 ----
if (depth >= spelling_size) \
{ \
spelling_size += 10; \
! spelling_base = (struct spelling *) \
! xrealloc (spelling_base, spelling_size * sizeof (struct spelling)); \
RESTORE_SPELLING_DEPTH (depth); \
} \
\
*************** get_spelling (errtype)
*** 4714,4720 ****
char *errtype;
{
static char *buffer;
! static int size = -1;
if (errtype == &initialization_message)
{
--- 4709,4715 ----
char *errtype;
{
static char *buffer;
! static int size;
if (errtype == &initialization_message)
{
*************** get_spelling (errtype)
*** 4723,4730 ****
register int needed = sizeof (message) + spelling_length () + 1;
char *temp;
- if (size < 0)
- buffer = (char *) xmalloc (size = needed);
if (needed > size)
buffer = (char *) xrealloc (buffer, size = needed);
--- 4718,4723 ----
Index: dbxout.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/dbxout.c,v
retrieving revision 1.17
diff -c -p -d -r1.17 dbxout.c
*** dbxout.c 1998/05/05 23:16:55 1.17
--- dbxout.c 1998/05/16 21:22:16
*************** dbxout_init (asm_file, input_file_name,
*** 377,384 ****
asmfile = asm_file;
typevec_len = 100;
! typevec = (struct typeinfo *) xmalloc (typevec_len * sizeof typevec[0]);
! bzero ((char *) typevec, typevec_len * sizeof typevec[0]);
/* Convert Ltext into the appropriate format for local labels in case
the system doesn't insert underscores in front of user generated
--- 377,383 ----
asmfile = asm_file;
typevec_len = 100;
! typevec = (struct typeinfo *) xcalloc (typevec_len, sizeof typevec[0]);
/* Convert Ltext into the appropriate format for local labels in case
the system doesn't insert underscores in front of user generated
Index: dwarf2out.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/dwarf2out.c,v
retrieving revision 1.50
diff -c -p -d -r1.50 dwarf2out.c
*** dwarf2out.c 1998/05/06 21:06:53 1.50
--- dwarf2out.c 1998/05/16 21:22:17
*************** void
*** 1906,1914 ****
dwarf2out_frame_init ()
{
/* Allocate the initial hunk of the fde_table. */
! fde_table
! = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
! bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
fde_table_allocated = FDE_TABLE_INCREMENT;
fde_table_in_use = 0;
--- 1906,1912 ----
dwarf2out_frame_init ()
{
/* Allocate the initial hunk of the fde_table. */
! fde_table = (dw_fde_ref) xcalloc (FDE_TABLE_INCREMENT, sizeof (dw_fde_node));
fde_table_allocated = FDE_TABLE_INCREMENT;
fde_table_in_use = 0;
*************** dwarf2out_init (asm_out_file, main_input
*** 9720,9727 ****
primary_filename = main_input_filename;
/* Allocate the initial hunk of the file_table. */
! file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *));
! bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *));
file_table_allocated = FILE_TABLE_INCREMENT;
/* Skip the first entry - file numbers begin at 1. */
--- 9718,9724 ----
primary_filename = main_input_filename;
/* Allocate the initial hunk of the file_table. */
! file_table = (char **) xcalloc (FILE_TABLE_INCREMENT, sizeof (char *));
file_table_allocated = FILE_TABLE_INCREMENT;
/* Skip the first entry - file numbers begin at 1. */
*************** dwarf2out_init (asm_out_file, main_input
*** 9729,9765 ****
/* Allocate the initial hunk of the decl_die_table. */
decl_die_table
! = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
! bzero ((char *) decl_die_table,
! DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
decl_die_table_in_use = 0;
/* Allocate the initial hunk of the decl_scope_table. */
decl_scope_table
! = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT
! * sizeof (decl_scope_node));
! bzero ((char *) decl_scope_table,
! DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node));
decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
decl_scope_depth = 0;
/* Allocate the initial hunk of the abbrev_die_table. */
abbrev_die_table
! = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT
* sizeof (dw_die_ref));
- bzero ((char *) abbrev_die_table,
- ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
/* Zero-th entry is allocated, but unused */
abbrev_die_table_in_use = 1;
/* Allocate the initial hunk of the line_info_table. */
line_info_table
! = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT
! * sizeof (dw_line_info_entry));
! bzero ((char *) line_info_table,
! LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
/* Zero-th entry is allocated, but unused */
line_info_table_in_use = 1;
--- 9726,9754 ----
/* Allocate the initial hunk of the decl_die_table. */
decl_die_table
! = (dw_die_ref *) xcalloc (DECL_DIE_TABLE_INCREMENT, sizeof (dw_die_ref));
decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
decl_die_table_in_use = 0;
/* Allocate the initial hunk of the decl_scope_table. */
decl_scope_table
! = (decl_scope_node *) xcalloc (DECL_SCOPE_TABLE_INCREMENT,
! sizeof (decl_scope_node));
decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
decl_scope_depth = 0;
/* Allocate the initial hunk of the abbrev_die_table. */
abbrev_die_table
! = (dw_die_ref *) xcalloc (ABBREV_DIE_TABLE_INCREMENT,
* sizeof (dw_die_ref));
abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
/* Zero-th entry is allocated, but unused */
abbrev_die_table_in_use = 1;
/* Allocate the initial hunk of the line_info_table. */
line_info_table
! = (dw_line_info_ref) xcalloc (LINE_INFO_TABLE_INCREMENT,
! sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
/* Zero-th entry is allocated, but unused */
line_info_table_in_use = 1;
Index: except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.c,v
retrieving revision 1.44.2.1
diff -c -p -d -r1.44.2.1 except.c
*** except.c 1998/05/09 00:52:02 1.44.2.1
--- except.c 1998/05/16 21:22:17
*************** find_exception_handler_labels ()
*** 1675,1685 ****
/* Generate a handy reference to each label. */
! /* We call xmalloc here instead of alloca; we did the latter in the past,
but found that it can sometimes end up being asked to allocate space
for more than 1 million labels. */
! labels = (rtx *) xmalloc ((max_labelno - min_labelno) * sizeof (rtx));
! bzero ((char *) labels, (max_labelno - min_labelno) * sizeof (rtx));
/* Arrange for labels to be indexed directly by CODE_LABEL_NUMBER. */
labels -= min_labelno;
--- 1675,1684 ----
/* Generate a handy reference to each label. */
! /* We call xcalloc here instead of alloca; we did the latter in the past,
but found that it can sometimes end up being asked to allocate space
for more than 1 million labels. */
! labels = (rtx *) xcalloc ((max_labelno - min_labelno), sizeof (rtx));
/* Arrange for labels to be indexed directly by CODE_LABEL_NUMBER. */
labels -= min_labelno;
Index: final.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/final.c,v
retrieving revision 1.40
diff -c -p -d -r1.40 final.c
*** final.c 1998/05/06 14:21:02 1.40
--- final.c 1998/05/16 21:22:17
*************** shorten_branches (first)
*** 988,995 ****
max_labelno = max_label_num ();
min_labelno = get_first_label_num ();
label_align
! = (short*) xmalloc ((max_labelno - min_labelno + 1) * sizeof (short));
! bzero (label_align, (max_labelno - min_labelno + 1) * sizeof (short));
uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
--- 988,994 ----
max_labelno = max_label_num ();
min_labelno = get_first_label_num ();
label_align
! = (short*) xcalloc ((max_labelno - min_labelno + 1), sizeof (short));
uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
*************** shorten_branches (first)
*** 1074,1096 ****
/* Allocate the rest of the arrays. */
insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
! insn_addresses = (int *) xmalloc (max_uid * sizeof (int));
/* Syntax errors can lead to labels being outside of the main insn stream.
Initialize insn_addresses, so that we get reproducible results. */
! bzero ((char *)insn_addresses, max_uid * sizeof *insn_addresses);
! uid_align = (rtx *) xmalloc (max_uid * sizeof *uid_align);
!
! varying_length = (char *) xmalloc (max_uid * sizeof (char));
! bzero (varying_length, max_uid);
/* Initialize uid_align. We scan instructions
from end to start, and keep in align_tab[n] the last seen insn
that does an alignment of at least n+1, i.e. the successor
in the alignment chain for an insn that does / has a known
alignment of n. */
!
! bzero ((char *) uid_align, max_uid * sizeof *uid_align);
for (i = MAX_CODE_ALIGN; --i >= 0; )
align_tab[i] = NULL_RTX;
--- 1073,1091 ----
/* Allocate the rest of the arrays. */
insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
!
/* Syntax errors can lead to labels being outside of the main insn stream.
Initialize insn_addresses, so that we get reproducible results. */
! insn_addresses = (int *) xcalloc (max_uid, sizeof (*insn_addresses));
! varying_length = (char *) xcalloc (max_uid, sizeof (char));
/* Initialize uid_align. We scan instructions
from end to start, and keep in align_tab[n] the last seen insn
that does an alignment of at least n+1, i.e. the successor
in the alignment chain for an insn that does / has a known
alignment of n. */
! uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align);
for (i = MAX_CODE_ALIGN; --i >= 0; )
align_tab[i] = NULL_RTX;
Index: flow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flow.c,v
retrieving revision 1.40
diff -c -p -d -r1.40 flow.c
*** flow.c 1998/05/06 21:07:03 1.40
--- flow.c 1998/05/16 21:22:18
*************** find_basic_blocks (f, nregs, file, live_
*** 363,370 ****
basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short));
uid_block_number
= (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int));
! uid_volatile = (char *) xmalloc (max_uid_for_flow + 1);
! bzero (uid_volatile, max_uid_for_flow + 1);
find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p);
}
--- 363,369 ----
basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short));
uid_block_number
= (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int));
! uid_volatile = (char *) xcalloc (max_uid_for_flow + 1, 1);
find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p);
}
Index: global.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/global.c,v
retrieving revision 1.10
diff -c -p -d -r1.10 global.c
*** global.c 1998/04/18 01:02:04 1.10
--- global.c 1998/05/16 21:22:18
*************** global_alloc (file)
*** 491,500 ****
/* We used to use alloca here, but the size of what it would try to
allocate would occasionally cause it to exceed the stack limit and
cause unpredictable core dumps. Some examples were > 2Mb in size. */
! conflicts = (INT_TYPE *) xmalloc (max_allocno * allocno_row_words
! * sizeof (INT_TYPE));
! bzero ((char *) conflicts,
! max_allocno * allocno_row_words * sizeof (INT_TYPE));
allocnos_live = (INT_TYPE *) alloca (allocno_row_words * sizeof (INT_TYPE));
--- 491,498 ----
/* We used to use alloca here, but the size of what it would try to
allocate would occasionally cause it to exceed the stack limit and
cause unpredictable core dumps. Some examples were > 2Mb in size. */
! conflicts = (INT_TYPE *) xcalloc (max_allocno * allocno_row_words,
! sizeof (INT_TYPE));
allocnos_live = (INT_TYPE *) alloca (allocno_row_words * sizeof (INT_TYPE));
Index: haifa-sched.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/haifa-sched.c,v
retrieving revision 1.48.2.1
diff -c -p -d -r1.48.2.1 haifa-sched.c
*** haifa-sched.c 1998/05/09 00:52:13 1.48.2.1
--- haifa-sched.c 1998/05/16 21:22:18
*************** build_control_flow (s_preds, s_succs, nu
*** 1154,1166 ****
/* Account for entry/exit edges. */
nr_edges += 2;
! in_edges = (int *) xmalloc (n_basic_blocks * sizeof (int));
! out_edges = (int *) xmalloc (n_basic_blocks * sizeof (int));
! bzero ((char *) in_edges, n_basic_blocks * sizeof (int));
! bzero ((char *) out_edges, n_basic_blocks * sizeof (int));
!
! edge_table = (edge *) xmalloc ((nr_edges) * sizeof (edge));
! bzero ((char *) edge_table, ((nr_edges) * sizeof (edge)));
nr_edges = 0;
for (i = 0; i < n_basic_blocks; i++)
--- 1154,1162 ----
/* Account for entry/exit edges. */
nr_edges += 2;
! in_edges = (int *) xcalloc (n_basic_blocks, sizeof (int));
! out_edges = (int *) xcalloc (n_basic_blocks, sizeof (int));
! edge_table = (edge *) xcalloc (nr_edges, sizeof (edge));
nr_edges = 0;
for (i = 0; i < n_basic_blocks; i++)
Index: local-alloc.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/local-alloc.c,v
retrieving revision 1.15
diff -c -p -d -r1.15 local-alloc.c
*** local-alloc.c 1998/04/03 16:36:06 1.15
--- local-alloc.c 1998/05/16 21:22:19
*************** local_alloc ()
*** 419,428 ****
reload will allocate them. */
scratch_list_length = max_qty;
! scratch_list = (rtx *) xmalloc (scratch_list_length * sizeof (rtx));
! bzero ((char *) scratch_list, scratch_list_length * sizeof (rtx));
! scratch_block = (int *) xmalloc (scratch_list_length * sizeof (int));
! bzero ((char *) scratch_block, scratch_list_length * sizeof (int));
scratch_index = 0;
qty_phys_reg = (short *) alloca (max_qty * sizeof (short));
--- 419,426 ----
reload will allocate them. */
scratch_list_length = max_qty;
! scratch_list = (rtx *) xcalloc (scratch_list_length, sizeof (rtx));
! scratch_block = (int *) xcalloc (scratch_list_length, sizeof (int));
scratch_index = 0;
qty_phys_reg = (short *) alloca (max_qty * sizeof (short));
Index: rtl.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.29.2.1
diff -c -p -d -r1.29.2.1 rtl.h
*** rtl.h 1998/05/09 00:52:18 1.29.2.1
--- rtl.h 1998/05/16 21:22:19
*************** extern rtx read_rtx PROTO((FILE *));
*** 709,717 ****
--- 709,719 ----
cast their pointers to char *, and all of the xrealloc's don't use
void * yet. */
extern char *xmalloc PROTO((size_t));
+ extern char *xcalloc PROTO((size_t, size_t));
extern char *xrealloc PROTO((void *, size_t));
#else
extern char *xmalloc ();
+ extern char *xcalloc ();
extern char *xrealloc ();
#endif
Index: scan.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/scan.c,v
retrieving revision 1.5
diff -c -p -d -r1.5 scan.c
*** scan.c 1998/05/06 12:56:53 1.5
--- scan.c 1998/05/16 21:22:19
*************** make_sstring_space (str, count)
*** 35,44 ****
if (new_size <= cur_size)
return;
! if (str->base == NULL)
! str->base = xmalloc (new_size);
! else
! str->base = xrealloc (str->base, new_size);
str->ptr = str->base + cur_size;
str->limit = str->base + new_size;
}
--- 35,41 ----
if (new_size <= cur_size)
return;
! str->base = xrealloc (str->base, new_size);
str->ptr = str->base + cur_size;
str->limit = str->base + new_size;
}
Index: stmt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/stmt.c,v
retrieving revision 1.39.2.1
diff -c -p -d -r1.39.2.1 stmt.c
*** stmt.c 1998/05/09 00:52:19 1.39.2.1
--- stmt.c 1998/05/16 21:22:20
*************** check_for_full_enumeration_handling (typ
*** 4597,4608 ****
bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
if (size > 0 && size < 600000
! /* We deliberately use malloc here - not xmalloc. */
! && (cases_seen = (unsigned char *) malloc (bytes_needed)) != NULL)
{
long i;
tree v = TYPE_VALUES (type);
- bzero (cases_seen, bytes_needed);
/* The time complexity of this code is normally O(N), where
N being the number of members in the enumerated type.
--- 4597,4607 ----
bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
if (size > 0 && size < 600000
! /* We deliberately use calloc here - not xcalloc. */
! && (cases_seen = (unsigned char *) calloc (bytes_needed, 1)) != NULL)
{
long i;
tree v = TYPE_VALUES (type);
/* The time complexity of this code is normally O(N), where
N being the number of members in the enumerated type.
*************** estimate_case_costs (node)
*** 5166,5173 ****
if (cost_table == NULL)
{
! cost_table = ((short *) xmalloc (129 * sizeof (short))) + 1;
! bzero ((char *) (cost_table - 1), 129 * sizeof (short));
for (i = 0; i < 128; i++)
{
--- 5165,5171 ----
if (cost_table == NULL)
{
! cost_table = ((short *) xcalloc (129, sizeof (short))) + 1;
for (i = 0; i < 128; i++)
{
Index: toplev.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/toplev.c,v
retrieving revision 1.62.2.2
diff -c -p -d -r1.62.2.2 toplev.c
*** toplev.c 1998/05/09 16:13:01 1.62.2.2
--- toplev.c 1998/05/16 21:22:20
*************** xmalloc (size)
*** 1920,1925 ****
--- 1920,1937 ----
return value;
}
+ /* Same as `calloc' but report error if no memory available. */
+
+ char *
+ xcalloc (nelt, size)
+ unsigned nelt, size;
+ {
+ register char *value = (char *) calloc (nelt, size);
+ if (value == 0 && nelt != 0 && size != 0)
+ fatal ("virtual memory exhausted");
+ return value;
+ }
+
/* Same as `realloc' but report error if no memory available.
Also handle null PTR even if the vendor realloc gets it wrong. */
Index: tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.28.2.1
diff -c -p -d -r1.28.2.1 tree.h
*** tree.h 1998/05/09 00:52:24 1.28.2.1
--- tree.h 1998/05/16 21:22:22
*************** extern int floor_log2_wide P
*** 1245,1253 ****
--- 1245,1255 ----
cast their pointers to char *, and all of the xrealloc's don't use
void * yet. */
extern char *xmalloc PROTO((size_t));
+ extern char *xcalloc PROTO((size_t, size_t));
extern char *xrealloc PROTO((void *, size_t));
#else
extern char *xmalloc ();
+ extern char *xcalloc ();
extern char *xrealloc ();
#endif