Makefile.in (recog.o): Don't depend on resource.h.
* Makefile.in (recog.o): Don't depend on resource.h. * recog.c: Don't include resource.h. (recog_last_allowed_insn): Remove. (recog_next_insn): Remove. (struct peep2_insn_data): New. (peep2_insn_data, peep2_current): New. (peep2_next_insn): New. (peep2_regno_dead_p, peep2_reg_dead_p): New. (peep2_find_free_register): New. (peephole2_optimize): Track life information by insn as we go. * recog.h: Update declarations. * resource.c (find_free_register, reg_dead_p): Remove. * resource.h: Remove their declarations. * toplev.c: Include hard-reg-set.h before recog.h. * genconfig.c (max_insns_per_peep2): New. (gen_peephole2): New. (main): Call it. * genemit.c (output_peephole2_scratches): Generate calls to peep2_find_free_register; adjust surrounding code. (main): Have insn-emit.c include hard-reg-set.h before recog.h. * genrecog.c (change_state): Don't track last_insn. (write_action): Write into *_pmatch_len before accepting. (write_tree): Adjust peephole2_insns and subroutines to match. * config/i386/i386.md (all peepholes): Use peep2_regno_dead_p. From-SVN: r34208
This commit is contained in:
parent
30196c1ff4
commit
2328013936
11 changed files with 407 additions and 214 deletions
|
@ -1,3 +1,32 @@
|
|||
2000-05-27 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* Makefile.in (recog.o): Don't depend on resource.h.
|
||||
* recog.c: Don't include resource.h.
|
||||
(recog_last_allowed_insn): Remove.
|
||||
(recog_next_insn): Remove.
|
||||
(struct peep2_insn_data): New.
|
||||
(peep2_insn_data, peep2_current): New.
|
||||
(peep2_next_insn): New.
|
||||
(peep2_regno_dead_p, peep2_reg_dead_p): New.
|
||||
(peep2_find_free_register): New.
|
||||
(peephole2_optimize): Track life information by insn as we go.
|
||||
* recog.h: Update declarations.
|
||||
* resource.c (find_free_register, reg_dead_p): Remove.
|
||||
* resource.h: Remove their declarations.
|
||||
* toplev.c: Include hard-reg-set.h before recog.h.
|
||||
|
||||
* genconfig.c (max_insns_per_peep2): New.
|
||||
(gen_peephole2): New.
|
||||
(main): Call it.
|
||||
* genemit.c (output_peephole2_scratches): Generate calls to
|
||||
peep2_find_free_register; adjust surrounding code.
|
||||
(main): Have insn-emit.c include hard-reg-set.h before recog.h.
|
||||
* genrecog.c (change_state): Don't track last_insn.
|
||||
(write_action): Write into *_pmatch_len before accepting.
|
||||
(write_tree): Adjust peephole2_insns and subroutines to match.
|
||||
|
||||
* config/i386/i386.md (all peepholes): Use peep2_regno_dead_p.
|
||||
|
||||
2000-05-27 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* function.c (thread_prologue_epilogue_insns): Don't move the
|
||||
|
|
|
@ -1382,7 +1382,7 @@ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \
|
|||
dbxout.h $(BASIC_BLOCK_H)
|
||||
recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) function.h $(BASIC_BLOCK_H) \
|
||||
$(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
|
||||
insn-flags.h insn-codes.h real.h toplev.h output.h resource.h
|
||||
insn-flags.h insn-codes.h real.h toplev.h output.h
|
||||
reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) $(RECOG_H) \
|
||||
$(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h \
|
||||
varray.h function.h
|
||||
|
|
|
@ -9591,10 +9591,11 @@
|
|||
[(match_scratch:SI 1 "r")
|
||||
(set (match_operand:SI 0 "memory_operand" "")
|
||||
(const_int 0))]
|
||||
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
|
||||
"! optimize_size
|
||||
&& ! TARGET_USE_MOV0
|
||||
&& TARGET_SPLIT_LONG_MOVES"
|
||||
&& TARGET_SPLIT_LONG_MOVES
|
||||
&& get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 1) (const_int 0))
|
||||
(clobber (reg:CC 17))])
|
||||
(set (match_dup 0) (match_dup 1))]
|
||||
|
@ -9604,10 +9605,11 @@
|
|||
[(match_scratch:HI 1 "r")
|
||||
(set (match_operand:HI 0 "memory_operand" "")
|
||||
(const_int 0))]
|
||||
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
|
||||
"! optimize_size
|
||||
&& ! TARGET_USE_MOV0
|
||||
&& TARGET_SPLIT_LONG_MOVES"
|
||||
&& TARGET_SPLIT_LONG_MOVES
|
||||
&& get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 2) (const_int 0))
|
||||
(clobber (reg:CC 17))])
|
||||
(set (match_dup 0) (match_dup 1))]
|
||||
|
@ -9617,10 +9619,11 @@
|
|||
[(match_scratch:QI 1 "q")
|
||||
(set (match_operand:QI 0 "memory_operand" "")
|
||||
(const_int 0))]
|
||||
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
|
||||
"! optimize_size
|
||||
&& ! TARGET_USE_MOV0
|
||||
&& TARGET_SPLIT_LONG_MOVES"
|
||||
&& TARGET_SPLIT_LONG_MOVES
|
||||
&& get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 2) (const_int 0))
|
||||
(clobber (reg:CC 17))])
|
||||
(set (match_dup 0) (match_dup 1))]
|
||||
|
@ -9630,7 +9633,8 @@
|
|||
[(match_scratch:SI 2 "r")
|
||||
(set (match_operand:SI 0 "memory_operand" "")
|
||||
(match_operand:SI 1 "immediate_operand" ""))]
|
||||
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
|
||||
"! optimize_size
|
||||
&& get_attr_length (insn) >= ix86_cost->large_insn
|
||||
&& TARGET_SPLIT_LONG_MOVES"
|
||||
[(set (match_dup 2) (match_dup 1))
|
||||
(set (match_dup 0) (match_dup 2))]
|
||||
|
@ -9675,14 +9679,14 @@
|
|||
;; represented using a modRM byte. The XOR replacement is long decoded,
|
||||
;; so this split helps here as well.
|
||||
;;
|
||||
;; Note: Can't do this as a regular split because reg_dead_p assumes
|
||||
;; resource info is live.
|
||||
;; Note: Can't do this as a regular split because we can't get proper
|
||||
;; lifetime information then.
|
||||
|
||||
(define_peephole2
|
||||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||||
(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
|
||||
"!optimize_size
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)
|
||||
&& ((TARGET_PENTIUM
|
||||
&& (GET_CODE (operands[0]) != MEM
|
||||
|| !memory_displacement_operand (operands[0], SImode)))
|
||||
|
@ -9696,7 +9700,7 @@
|
|||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||||
(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
|
||||
"!optimize_size
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)
|
||||
&& ((TARGET_PENTIUM
|
||||
&& (GET_CODE (operands[0]) != MEM
|
||||
|| !memory_displacement_operand (operands[0], HImode)))
|
||||
|
@ -9710,7 +9714,7 @@
|
|||
[(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
|
||||
(not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
|
||||
"!optimize_size
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)
|
||||
&& ((TARGET_PENTIUM
|
||||
&& (GET_CODE (operands[0]) != MEM
|
||||
|| !memory_displacement_operand (operands[0], QImode)))
|
||||
|
@ -9873,7 +9877,7 @@
|
|||
|| GET_MODE (operands[0]) == HImode
|
||||
|| GET_MODE (operands[0]) == SImode)
|
||||
&& (! TARGET_USE_MOV0 || optimize_size)
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 0) (const_int 0))
|
||||
(clobber (reg:CC 17))])]
|
||||
"operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]));")
|
||||
|
@ -9885,7 +9889,7 @@
|
|||
"(GET_MODE (operands[0]) == HImode
|
||||
|| GET_MODE (operands[0]) == SImode)
|
||||
&& (optimize_size || TARGET_PENTIUM)
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 0) (const_int -1))
|
||||
(clobber (reg:CC 17))])]
|
||||
"operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]));")
|
||||
|
@ -9896,7 +9900,7 @@
|
|||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(plus:SI (match_dup 0)
|
||||
(match_operand:SI 1 "nonmemory_operand" "")))]
|
||||
"reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
|
||||
"peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
|
||||
(clobber (reg:CC 17))])]
|
||||
"")
|
||||
|
@ -9905,7 +9909,8 @@
|
|||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(mult:SI (match_dup 0)
|
||||
(match_operand:SI 1 "immediate_operand" "")))]
|
||||
"reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
|
||||
"exact_log2 (INTVAL (operands[1])) >= 0
|
||||
&& peep2_regno_dead_p (0, FLAGS_REG)"
|
||||
[(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))
|
||||
(clobber (reg:CC 17))])]
|
||||
"operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));")
|
||||
|
|
|
@ -42,6 +42,9 @@ static int have_peephole2_flag;
|
|||
/* Maximum number of insns seen in a split. */
|
||||
static int max_insns_per_split = 1;
|
||||
|
||||
/* Maximum number of input insns for peephole2. */
|
||||
static int max_insns_per_peep2;
|
||||
|
||||
static int clobbers_seen_this_insn;
|
||||
static int dup_operands_seen_this_insn;
|
||||
|
||||
|
@ -239,6 +242,26 @@ gen_peephole (peep)
|
|||
walk_insn_part (XVECEXP (peep, 0, i), 1, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_peephole2 (peep)
|
||||
rtx peep;
|
||||
{
|
||||
int i, n;
|
||||
|
||||
/* Look through the patterns that are matched
|
||||
to compute the maximum operand number. */
|
||||
for (i = XVECLEN (peep, 0) - 1; i >= 0; --i)
|
||||
walk_insn_part (XVECEXP (peep, 0, i), 1, 0);
|
||||
|
||||
/* Look at the number of insns this insn can be matched from. */
|
||||
for (i = XVECLEN (peep, 0) - 1, n = 0; i >= 0; --i)
|
||||
if (GET_CODE (XVECEXP (peep, 0, i)) != MATCH_DUP
|
||||
&& GET_CODE (XVECEXP (peep, 0, i)) != MATCH_SCRATCH)
|
||||
n++;
|
||||
if (n > max_insns_per_peep2)
|
||||
max_insns_per_peep2 = n;
|
||||
}
|
||||
|
||||
extern int main PARAMS ((int, char **));
|
||||
|
||||
int
|
||||
|
@ -289,7 +312,7 @@ from the machine description file `md'. */\n\n");
|
|||
|
||||
case DEFINE_PEEPHOLE2:
|
||||
have_peephole2_flag = 1;
|
||||
gen_split (desc);
|
||||
gen_peephole2 (desc);
|
||||
break;
|
||||
|
||||
case DEFINE_PEEPHOLE:
|
||||
|
@ -302,9 +325,8 @@ from the machine description file `md'. */\n\n");
|
|||
}
|
||||
}
|
||||
|
||||
printf ("\n#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
|
||||
|
||||
printf ("\n#define MAX_DUP_OPERANDS %d\n", max_dup_operands);
|
||||
printf ("#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
|
||||
printf ("#define MAX_DUP_OPERANDS %d\n", max_dup_operands);
|
||||
|
||||
/* This is conditionally defined, in case the user writes code which emits
|
||||
more splits than we can readily see (and knows s/he does it). */
|
||||
|
@ -328,7 +350,10 @@ from the machine description file `md'. */\n\n");
|
|||
printf ("#define HAVE_peephole 1\n");
|
||||
|
||||
if (have_peephole2_flag)
|
||||
{
|
||||
printf ("#define HAVE_peephole2 1\n");
|
||||
printf ("#define MAX_INSNS_PER_PEEP2 %d\n", max_insns_per_peep2);
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
|
||||
|
|
|
@ -699,10 +699,7 @@ output_peephole2_scratches (split)
|
|||
int i;
|
||||
int insn_nr = 0;
|
||||
|
||||
printf (" rtx first_insn ATTRIBUTE_UNUSED;\n");
|
||||
printf (" rtx last_insn ATTRIBUTE_UNUSED;\n");
|
||||
printf (" HARD_REG_SET _regs_allocated;\n");
|
||||
|
||||
printf (" CLEAR_HARD_REG_SET (_regs_allocated);\n");
|
||||
|
||||
for (i = 0; i < XVECLEN (split, 0); i++)
|
||||
|
@ -721,15 +718,11 @@ output_peephole2_scratches (split)
|
|||
}
|
||||
else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH)
|
||||
cur_insn_nr++;
|
||||
printf (" first_insn = recog_next_insn (curr_insn, %d);\n", insn_nr);
|
||||
if (last_insn_nr > insn_nr)
|
||||
printf (" last_insn = recog_next_insn (curr_insn, %d);\n",
|
||||
last_insn_nr - 1);
|
||||
else
|
||||
printf (" last_insn = 0;\n");
|
||||
printf (" if ((operands[%d] = find_free_register (first_insn, last_insn, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
|
||||
|
||||
printf (" if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
|
||||
return NULL;\n",
|
||||
XINT (elt, 0),
|
||||
insn_nr, last_insn_nr,
|
||||
XSTR (elt, 1),
|
||||
GET_MODE_NAME (GET_MODE (elt)));
|
||||
|
||||
|
@ -777,8 +770,8 @@ from the machine description file `md'. */\n\n");
|
|||
printf ("#include \"insn-config.h\"\n");
|
||||
printf ("#include \"insn-flags.h\"\n");
|
||||
printf ("#include \"insn-codes.h\"\n");
|
||||
printf ("#include \"recog.h\"\n");
|
||||
printf ("#include \"hard-reg-set.h\"\n");
|
||||
printf ("#include \"recog.h\"\n");
|
||||
printf ("#include \"resource.h\"\n");
|
||||
printf ("#include \"reload.h\"\n\n");
|
||||
printf ("#define FAIL return (end_sequence (), _val)\n");
|
||||
|
|
|
@ -272,8 +272,8 @@ static struct decision *write_switch
|
|||
static void write_cond
|
||||
PARAMS ((struct decision_test *, int, enum routine_type));
|
||||
static void write_action
|
||||
PARAMS ((struct decision_test *, int, int, struct decision *,
|
||||
enum routine_type));
|
||||
PARAMS ((struct decision *, struct decision_test *, int, int,
|
||||
struct decision *, enum routine_type));
|
||||
static int is_unconditional
|
||||
PARAMS ((struct decision_test *, enum routine_type));
|
||||
static int write_node
|
||||
|
@ -1578,10 +1578,6 @@ change_state (oldpos, newpos, afterward, indent)
|
|||
if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
|
||||
break;
|
||||
|
||||
/* Make sure to reset the last_insn pointer when popping back up. */
|
||||
if (old_has_insn >= 0 && new_has_insn < 0)
|
||||
printf ("%slast_insn = insn;\n", indent);
|
||||
|
||||
/* Go down to desired level. */
|
||||
while (depth < ndepth)
|
||||
{
|
||||
|
@ -1591,21 +1587,20 @@ change_state (oldpos, newpos, afterward, indent)
|
|||
/* We can only fail if we're moving down the tree. */
|
||||
if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
|
||||
{
|
||||
printf ("%slast_insn = recog_next_insn (insn, %d);\n",
|
||||
printf ("%stem = peep2_next_insn (%d);\n",
|
||||
indent, newpos[depth] - 'A');
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%stem = recog_next_insn (insn, %d);\n",
|
||||
printf ("%stem = peep2_next_insn (%d);\n",
|
||||
indent, newpos[depth] - 'A');
|
||||
printf ("%sif (tem == NULL_RTX)\n", indent);
|
||||
if (afterward)
|
||||
printf ("%s goto L%d;\n", indent, afterward->number);
|
||||
else
|
||||
printf ("%s goto ret0;\n", indent);
|
||||
printf ("%slast_insn = tem;\n", indent);
|
||||
}
|
||||
printf ("%sx%d = PATTERN (last_insn);\n", indent, depth + 1);
|
||||
printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
|
||||
}
|
||||
else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
|
||||
printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
|
||||
|
@ -1888,7 +1883,8 @@ write_cond (p, depth, subroutine_type)
|
|||
perform a state change. For the `accept' tests we must do more work. */
|
||||
|
||||
static void
|
||||
write_action (test, depth, uncond, success, subroutine_type)
|
||||
write_action (p, test, depth, uncond, success, subroutine_type)
|
||||
struct decision *p;
|
||||
struct decision_test *test;
|
||||
int depth, uncond;
|
||||
struct decision *success;
|
||||
|
@ -1942,9 +1938,20 @@ write_action (test, depth, uncond, success, subroutine_type)
|
|||
break;
|
||||
|
||||
case PEEPHOLE2:
|
||||
{
|
||||
int match_len = 0, i;
|
||||
|
||||
for (i = strlen (p->position) - 1; i >= 0; --i)
|
||||
if (p->position[i] >= 'A' && p->position[i] <= 'Z')
|
||||
{
|
||||
match_len = p->position[i] - 'A';
|
||||
break;
|
||||
}
|
||||
printf ("%s*_pmatch_len = %d;\n", indent, match_len);
|
||||
printf ("%stem = gen_peephole2_%d (insn, operands);\n",
|
||||
indent, test->u.insn.code_number);
|
||||
printf ("%sif (tem != 0)\n%s goto ret1;\n", indent, indent);
|
||||
printf ("%sif (tem != 0)\n%s return tem;\n", indent, indent);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2027,7 +2034,7 @@ write_node (p, depth, subroutine_type)
|
|||
printf (")\n");
|
||||
}
|
||||
|
||||
write_action (last_test, depth, uncond, p->success.first, subroutine_type);
|
||||
write_action (p, last_test, depth, uncond, p->success.first, subroutine_type);
|
||||
|
||||
return uncond > 0;
|
||||
}
|
||||
|
@ -2090,7 +2097,7 @@ write_tree (head, prevpos, type, initial)
|
|||
};
|
||||
|
||||
static const char * const call_suffix[] = {
|
||||
", pnum_clobbers", "", ", _plast_insn"
|
||||
", pnum_clobbers", "", ", _pmatch_len"
|
||||
};
|
||||
|
||||
/* This node has been broken out into a separate subroutine.
|
||||
|
@ -2167,12 +2174,13 @@ split%s (x0, insn)\n\
|
|||
rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
|
||||
break;
|
||||
case PEEPHOLE2:
|
||||
printf ("%srtx peephole2%s PARAMS ((rtx, rtx, rtx *));\n", s_or_e, extension);
|
||||
printf ("%srtx peephole2%s PARAMS ((rtx, rtx, int *));\n",
|
||||
s_or_e, extension);
|
||||
printf ("%srtx\n\
|
||||
peephole2%s (x0, insn, _plast_insn)\n\
|
||||
peephole2%s (x0, insn, _pmatch_len)\n\
|
||||
register rtx x0;\n\
|
||||
rtx insn ATTRIBUTE_UNUSED;\n\
|
||||
rtx *_plast_insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
|
||||
int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2180,8 +2188,6 @@ peephole2%s (x0, insn, _plast_insn)\n\
|
|||
for (i = 1; i <= max_depth; i++)
|
||||
printf (" register rtx x%d ATTRIBUTE_UNUSED;\n", i);
|
||||
|
||||
if (type == PEEPHOLE2)
|
||||
printf (" register rtx last_insn = insn;\n");
|
||||
printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
|
||||
|
||||
if (head->first)
|
||||
|
@ -2189,8 +2195,6 @@ peephole2%s (x0, insn, _plast_insn)\n\
|
|||
else
|
||||
printf (" goto ret0;\n");
|
||||
|
||||
if (type == PEEPHOLE2)
|
||||
printf (" ret1:\n *_plast_insn = last_insn;\n return tem;\n");
|
||||
printf (" ret0:\n return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
|
||||
}
|
||||
|
||||
|
|
325
gcc/recog.c
325
gcc/recog.c
|
@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "toplev.h"
|
||||
#include "basic-block.h"
|
||||
#include "output.h"
|
||||
#include "resource.h"
|
||||
|
||||
#ifndef STACK_PUSH_CODE
|
||||
#ifdef STACK_GROWS_DOWNWARD
|
||||
|
@ -2682,100 +2681,340 @@ split_all_insns (upd_life)
|
|||
}
|
||||
|
||||
#ifdef HAVE_peephole2
|
||||
/* This is the last insn we'll allow recog_next_insn to consider. */
|
||||
static rtx recog_last_allowed_insn;
|
||||
|
||||
/* Return the Nth non-note insn after INSN, or return NULL_RTX if it does
|
||||
not exist. Used by the recognizer to find the next insn to match in a
|
||||
multi-insn pattern. */
|
||||
rtx
|
||||
recog_next_insn (insn, n)
|
||||
struct peep2_insn_data
|
||||
{
|
||||
rtx insn;
|
||||
regset live_before;
|
||||
};
|
||||
|
||||
static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1];
|
||||
static int peep2_current;
|
||||
|
||||
/* A non-insn marker indicating the last insn of the block.
|
||||
The live_before regset for this element is correct, indicating
|
||||
global_live_at_end for the block. */
|
||||
#define PEEP2_EOB pc_rtx
|
||||
|
||||
/* Return the Nth non-note insn after `current', or return NULL_RTX if it
|
||||
does not exist. Used by the recognizer to find the next insn to match
|
||||
in a multi-insn pattern. */
|
||||
|
||||
rtx
|
||||
peep2_next_insn (n)
|
||||
int n;
|
||||
{
|
||||
if (insn != NULL_RTX)
|
||||
{
|
||||
while (n > 0)
|
||||
{
|
||||
if (insn == recog_last_allowed_insn)
|
||||
if (n >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
abort ();
|
||||
|
||||
n += peep2_current;
|
||||
if (n >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
n -= MAX_INSNS_PER_PEEP2 + 1;
|
||||
|
||||
if (peep2_insn_data[n].insn == PEEP2_EOB)
|
||||
return NULL_RTX;
|
||||
return peep2_insn_data[n].insn;
|
||||
}
|
||||
|
||||
insn = NEXT_INSN (insn);
|
||||
if (insn == NULL_RTX)
|
||||
/* Return true if REGNO is dead before the Nth non-note insn
|
||||
after `current'. */
|
||||
|
||||
int
|
||||
peep2_regno_dead_p (ofs, regno)
|
||||
int ofs;
|
||||
int regno;
|
||||
{
|
||||
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
abort ();
|
||||
|
||||
ofs += peep2_current;
|
||||
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
ofs -= MAX_INSNS_PER_PEEP2 + 1;
|
||||
|
||||
if (peep2_insn_data[ofs].insn == NULL_RTX)
|
||||
abort ();
|
||||
|
||||
return ! REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno);
|
||||
}
|
||||
|
||||
/* Similarly for a REG. */
|
||||
|
||||
int
|
||||
peep2_reg_dead_p (ofs, reg)
|
||||
int ofs;
|
||||
rtx reg;
|
||||
{
|
||||
int regno, n;
|
||||
|
||||
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
abort ();
|
||||
|
||||
ofs += peep2_current;
|
||||
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
ofs -= MAX_INSNS_PER_PEEP2 + 1;
|
||||
|
||||
if (peep2_insn_data[ofs].insn == NULL_RTX)
|
||||
abort ();
|
||||
|
||||
regno = REGNO (reg);
|
||||
n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
|
||||
while (--n >= 0)
|
||||
if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno + n))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try to find a hard register of mode MODE, matching the register class in
|
||||
CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
|
||||
remains available until the end of LAST_INSN. LAST_INSN may be NULL_RTX,
|
||||
in which case the only condition is that the register must be available
|
||||
before CURRENT_INSN.
|
||||
Registers that already have bits set in REG_SET will not be considered.
|
||||
|
||||
If an appropriate register is available, it will be returned and the
|
||||
corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
|
||||
returned. */
|
||||
|
||||
rtx
|
||||
peep2_find_free_register (from, to, class_str, mode, reg_set)
|
||||
int from, to;
|
||||
const char *class_str;
|
||||
enum machine_mode mode;
|
||||
HARD_REG_SET *reg_set;
|
||||
{
|
||||
static int search_ofs;
|
||||
enum reg_class class;
|
||||
HARD_REG_SET live;
|
||||
int i;
|
||||
|
||||
if (from >= MAX_INSNS_PER_PEEP2 + 1 || to >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
abort ();
|
||||
|
||||
from += peep2_current;
|
||||
if (from >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
from -= MAX_INSNS_PER_PEEP2 + 1;
|
||||
to += peep2_current;
|
||||
if (to >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
to -= MAX_INSNS_PER_PEEP2 + 1;
|
||||
|
||||
if (peep2_insn_data[from].insn == NULL_RTX)
|
||||
abort ();
|
||||
REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
|
||||
|
||||
while (from != to)
|
||||
{
|
||||
HARD_REG_SET this_live;
|
||||
|
||||
if (++from >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
from = 0;
|
||||
if (peep2_insn_data[from].insn == NULL_RTX)
|
||||
abort ();
|
||||
REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
|
||||
IOR_HARD_REG_SET (live, this_live);
|
||||
}
|
||||
|
||||
class = (class_str[0] == 'r' ? GENERAL_REGS
|
||||
: REG_CLASS_FROM_LETTER (class_str[0]));
|
||||
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
{
|
||||
int raw_regno, regno, success, j;
|
||||
|
||||
/* Distribute the free registers as much as possible. */
|
||||
raw_regno = search_ofs + i;
|
||||
if (raw_regno >= FIRST_PSEUDO_REGISTER)
|
||||
raw_regno -= FIRST_PSEUDO_REGISTER;
|
||||
#ifdef REG_ALLOC_ORDER
|
||||
regno = reg_alloc_order[raw_regno];
|
||||
#else
|
||||
regno = raw_regno;
|
||||
#endif
|
||||
|
||||
/* Don't allocate fixed registers. */
|
||||
if (fixed_regs[regno])
|
||||
continue;
|
||||
/* Make sure the register is of the right class. */
|
||||
if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
|
||||
continue;
|
||||
/* And can support the mode we need. */
|
||||
if (! HARD_REGNO_MODE_OK (regno, mode))
|
||||
continue;
|
||||
/* And that we don't create an extra save/restore. */
|
||||
if (! call_used_regs[regno] && ! regs_ever_live[regno])
|
||||
continue;
|
||||
/* And we don't clobber traceback for noreturn functions. */
|
||||
if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
|
||||
&& (! reload_completed || frame_pointer_needed))
|
||||
continue;
|
||||
|
||||
success = 1;
|
||||
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
|
||||
{
|
||||
if (TEST_HARD_REG_BIT (*reg_set, regno + j)
|
||||
|| TEST_HARD_REG_BIT (live, regno + j))
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
|
||||
SET_HARD_REG_BIT (*reg_set, regno + j);
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
|
||||
n -= 1;
|
||||
/* Start the next search with the next register. */
|
||||
if (++raw_regno >= FIRST_PSEUDO_REGISTER)
|
||||
raw_regno = 0;
|
||||
search_ofs = raw_regno;
|
||||
|
||||
return gen_rtx_REG (mode, regno);
|
||||
}
|
||||
}
|
||||
|
||||
return insn;
|
||||
search_ofs = 0;
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Perform the peephole2 optimization pass. */
|
||||
|
||||
void
|
||||
peephole2_optimize (dump_file)
|
||||
FILE *dump_file ATTRIBUTE_UNUSED;
|
||||
{
|
||||
regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2];
|
||||
rtx insn, prev;
|
||||
int i, changed;
|
||||
regset live;
|
||||
int i, b;
|
||||
#ifdef HAVE_conditional_execution
|
||||
sbitmap blocks;
|
||||
int changed;
|
||||
#endif
|
||||
|
||||
/* ??? TODO: Arrange with resource.c to start at bb->global_live_at_end
|
||||
and backtrack insn by insn as we proceed through the block. In this
|
||||
way we'll not need to keep searching forward from the beginning of
|
||||
basic blocks to find register life info. */
|
||||
|
||||
init_resource_info (NULL);
|
||||
/* Initialize the regsets we're going to use. */
|
||||
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
|
||||
peep2_insn_data[i].live_before = INITIALIZE_REG_SET (rs_heads[i]);
|
||||
live = INITIALIZE_REG_SET (rs_heads[i]);
|
||||
|
||||
#ifdef HAVE_conditional_execution
|
||||
blocks = sbitmap_alloc (n_basic_blocks);
|
||||
sbitmap_zero (blocks);
|
||||
changed = 0;
|
||||
#else
|
||||
count_or_remove_death_notes (NULL, 1);
|
||||
#endif
|
||||
|
||||
for (i = n_basic_blocks - 1; i >= 0; --i)
|
||||
for (b = n_basic_blocks - 1; b >= 0; --b)
|
||||
{
|
||||
basic_block bb = BASIC_BLOCK (i);
|
||||
basic_block bb = BASIC_BLOCK (b);
|
||||
struct propagate_block_info *pbi;
|
||||
|
||||
/* Since we don't update life info until the very end, we can't
|
||||
allow matching instructions that we've replaced before. Walk
|
||||
backward through the basic block so that we don't have to
|
||||
care about subsequent life info; recog_last_allowed_insn to
|
||||
restrict how far forward we will allow the match to proceed. */
|
||||
/* Indicate that all slots except the last holds invalid data. */
|
||||
for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
|
||||
peep2_insn_data[i].insn = NULL_RTX;
|
||||
|
||||
/* Indicate that the last slot contains live_after data. */
|
||||
peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB;
|
||||
peep2_current = MAX_INSNS_PER_PEEP2;
|
||||
|
||||
/* Start up propagation. */
|
||||
COPY_REG_SET (live, bb->global_live_at_end);
|
||||
COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
|
||||
|
||||
#ifdef HAVE_conditional_execution
|
||||
pbi = init_propagate_block_info (bb, live, NULL, 0);
|
||||
#else
|
||||
pbi = init_propagate_block_info (bb, live, NULL, PROP_DEATH_NOTES);
|
||||
#endif
|
||||
|
||||
recog_last_allowed_insn = NEXT_INSN (bb->end);
|
||||
for (insn = bb->end; ; insn = prev)
|
||||
{
|
||||
prev = PREV_INSN (insn);
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
rtx try, last_insn;
|
||||
rtx try;
|
||||
int match_len;
|
||||
|
||||
try = peephole2_insns (PATTERN (insn), insn, &last_insn);
|
||||
/* Record this insn. */
|
||||
if (--peep2_current < 0)
|
||||
peep2_current = MAX_INSNS_PER_PEEP2;
|
||||
peep2_insn_data[peep2_current].insn = insn;
|
||||
propagate_one_insn (pbi, insn);
|
||||
COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
|
||||
|
||||
/* Match the peephole. */
|
||||
try = peephole2_insns (PATTERN (insn), insn, &match_len);
|
||||
if (try != NULL)
|
||||
{
|
||||
flow_delete_insn_chain (insn, last_insn);
|
||||
i = match_len + peep2_current;
|
||||
if (i >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
i -= MAX_INSNS_PER_PEEP2 + 1;
|
||||
|
||||
/* Replace the old sequence with the new. */
|
||||
flow_delete_insn_chain (insn, peep2_insn_data[i].insn);
|
||||
try = emit_insn_after (try, prev);
|
||||
|
||||
if (last_insn == bb->end)
|
||||
/* Adjust the basic block boundaries. */
|
||||
if (peep2_insn_data[i].insn == bb->end)
|
||||
bb->end = try;
|
||||
if (insn == bb->head)
|
||||
bb->head = NEXT_INSN (prev);
|
||||
|
||||
recog_last_allowed_insn = NEXT_INSN (prev);
|
||||
SET_BIT (blocks, i);
|
||||
#ifdef HAVE_conditional_execution
|
||||
/* With conditional execution, we cannot back up the
|
||||
live information so easily, since the conditional
|
||||
death data structures are not so self-contained.
|
||||
So record that we've made a modification to this
|
||||
block and update life information at the end. */
|
||||
SET_BIT (blocks, b);
|
||||
changed = 1;
|
||||
|
||||
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
|
||||
peep2_insn_data[i].insn = NULL_RTX;
|
||||
peep2_insn_data[peep2_current].insn = PEEP2_EOB;
|
||||
#else
|
||||
/* Back up lifetime information past the end of the
|
||||
newly created sequence. */
|
||||
if (++i >= MAX_INSNS_PER_PEEP2 + 1)
|
||||
i = 0;
|
||||
COPY_REG_SET (live, peep2_insn_data[i].live_before);
|
||||
|
||||
/* Update life information for the new sequence. */
|
||||
do
|
||||
{
|
||||
if (INSN_P (try))
|
||||
{
|
||||
if (--i < 0)
|
||||
i = MAX_INSNS_PER_PEEP2;
|
||||
peep2_insn_data[i].insn = try;
|
||||
propagate_one_insn (pbi, try);
|
||||
COPY_REG_SET (peep2_insn_data[i].live_before, live);
|
||||
}
|
||||
try = PREV_INSN (try);
|
||||
}
|
||||
while (try != prev);
|
||||
|
||||
/* ??? Should verify that LIVE now matches what we
|
||||
had before the new sequence. */
|
||||
|
||||
peep2_current = i;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (insn == bb->head)
|
||||
break;
|
||||
}
|
||||
|
||||
free_propagate_block_info (pbi);
|
||||
}
|
||||
|
||||
free_resource_info ();
|
||||
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
|
||||
FREE_REG_SET (peep2_insn_data[i].live_before);
|
||||
FREE_REG_SET (live);
|
||||
|
||||
compute_bb_for_insn (get_max_uid ());
|
||||
#ifdef HAVE_conditional_execution
|
||||
count_or_remove_death_notes (blocks, 1);
|
||||
update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
|
||||
}
|
||||
sbitmap_free (blocks);
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_peephole2 */
|
||||
|
|
11
gcc/recog.h
11
gcc/recog.h
|
@ -116,9 +116,16 @@ extern void add_clobbers PARAMS ((rtx, int));
|
|||
extern void insn_extract PARAMS ((rtx));
|
||||
extern void extract_insn PARAMS ((rtx));
|
||||
extern void preprocess_constraints PARAMS ((void));
|
||||
extern rtx recog_next_insn PARAMS ((rtx, int));
|
||||
extern rtx peep2_next_insn PARAMS ((int));
|
||||
extern int peep2_regno_dead_p PARAMS ((int, int));
|
||||
extern int peep2_reg_dead_p PARAMS ((int, rtx));
|
||||
#ifdef CLEAR_HARD_REG_SET
|
||||
extern rtx peep2_find_free_register PARAMS ((int, int, const char *,
|
||||
enum machine_mode,
|
||||
HARD_REG_SET *));
|
||||
#endif
|
||||
extern void peephole2_optimize PARAMS ((FILE *));
|
||||
extern rtx peephole2_insns PARAMS ((rtx, rtx, rtx *));
|
||||
extern rtx peephole2_insns PARAMS ((rtx, rtx, int *));
|
||||
|
||||
/* Nonzero means volatile operands are recognized. */
|
||||
extern int volatile_ok;
|
||||
|
|
106
gcc/resource.c
106
gcc/resource.c
|
@ -1268,109 +1268,3 @@ mark_end_of_function_resources (trial, include_delayed_effects)
|
|||
mark_referenced_resources (trial, &end_of_function_needs,
|
||||
include_delayed_effects);
|
||||
}
|
||||
|
||||
/* Try to find a hard register of mode MODE, matching the register class in
|
||||
CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
|
||||
remains available until the end of LAST_INSN. LAST_INSN may be NULL_RTX,
|
||||
in which case the only condition is that the register must be available
|
||||
before CURRENT_INSN.
|
||||
Registers that already have bits set in REG_SET will not be considered.
|
||||
|
||||
If an appropriate register is available, it will be returned and the
|
||||
corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
|
||||
returned. */
|
||||
|
||||
rtx
|
||||
find_free_register (current_insn, last_insn, class_str, mode, reg_set)
|
||||
rtx current_insn, last_insn;
|
||||
const char *class_str;
|
||||
int mode;
|
||||
HARD_REG_SET *reg_set;
|
||||
{
|
||||
int i, j;
|
||||
struct resources used;
|
||||
unsigned char clet = class_str[0];
|
||||
enum reg_class class
|
||||
= (clet == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (clet));
|
||||
|
||||
mark_target_live_regs (get_insns (), current_insn, &used);
|
||||
if (last_insn)
|
||||
while (current_insn != last_insn)
|
||||
{
|
||||
/* Exclude anything set in this insn. */
|
||||
mark_set_resources (PATTERN (current_insn), &used, 0,
|
||||
MARK_SRC_DEST_CALL);
|
||||
current_insn = next_nonnote_insn (current_insn);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
{
|
||||
int regno;
|
||||
int success;
|
||||
|
||||
#ifdef REG_ALLOC_ORDER
|
||||
regno = reg_alloc_order [i];
|
||||
#else
|
||||
regno = i;
|
||||
#endif
|
||||
|
||||
/* Don't allocate fixed registers. */
|
||||
if (fixed_regs[regno])
|
||||
continue;
|
||||
/* Make sure the register is of the right class. */
|
||||
if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
|
||||
continue;
|
||||
/* And can support the mode we need. */
|
||||
if (! HARD_REGNO_MODE_OK (regno, mode))
|
||||
continue;
|
||||
/* And that we don't create an extra save/restore. */
|
||||
if (! call_used_regs[regno] && ! regs_ever_live[regno])
|
||||
continue;
|
||||
/* And we don't clobber traceback for noreturn functions. */
|
||||
if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
|
||||
&& (! reload_completed || frame_pointer_needed))
|
||||
continue;
|
||||
|
||||
success = 1;
|
||||
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
|
||||
{
|
||||
if (TEST_HARD_REG_BIT (*reg_set, regno + j)
|
||||
|| TEST_HARD_REG_BIT (used.regs, regno + j))
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
|
||||
{
|
||||
SET_HARD_REG_BIT (*reg_set, regno + j);
|
||||
}
|
||||
return gen_rtx_REG (mode, regno);
|
||||
}
|
||||
}
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Return true if REG is dead at CURRENT_INSN. */
|
||||
|
||||
int
|
||||
reg_dead_p (current_insn, reg)
|
||||
rtx current_insn, reg;
|
||||
{
|
||||
struct resources used;
|
||||
int regno, j;
|
||||
|
||||
mark_target_live_regs (get_insns (), current_insn, &used);
|
||||
|
||||
regno = REGNO (reg);
|
||||
for (j = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; j >= 0; j--)
|
||||
{
|
||||
if (TEST_HARD_REG_BIT (used.regs, regno + j))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,3 @@ extern void incr_ticks_for_insn PARAMS ((rtx));
|
|||
extern void mark_end_of_function_resources PARAMS ((rtx, int));
|
||||
extern void init_resource_info PARAMS ((rtx));
|
||||
extern void free_resource_info PARAMS ((void));
|
||||
extern rtx find_free_register PARAMS ((rtx, rtx, const char *, int,
|
||||
HARD_REG_SET *));
|
||||
extern int reg_dead_p PARAMS ((rtx, rtx));
|
||||
|
|
|
@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "insn-attr.h"
|
||||
#include "insn-codes.h"
|
||||
#include "insn-config.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "recog.h"
|
||||
#include "defaults.h"
|
||||
#include "output.h"
|
||||
|
@ -54,7 +55,6 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "function.h"
|
||||
#include "toplev.h"
|
||||
#include "expr.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "basic-block.h"
|
||||
#include "intl.h"
|
||||
#include "ggc.h"
|
||||
|
|
Loading…
Add table
Reference in a new issue