This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Function to reliably copy insns (repost)
- To: gcc-patches at gcc dot gnu dot org
- Subject: Function to reliably copy insns (repost)
- From: Bernd Schmidt <bernds at cygnus dot co dot uk>
- Date: Fri, 8 Oct 1999 01:16:17 +0100 (BST)
(This message is a repost; the original one was in May or June)
There doesn't appear to be a function yet that reliably duplicates an
insn. copy_rtx won't do, because ASM_OPERANDS and SCRATCH rtx's have
special sharing rules: parts may be shared within one insn, but not with
other rtl outside the same insn. This patch adds two new functions,
copy_insn and copy_insn_1, which can be used to duplicate insns. It
also converts duplicate_loop_exit_test to use these functions. There may
be other places in the compiler where this could be used.
The code for copy_insn_1 is more or less copy_rtx with some small additions.
The patch assumes that there are no more than MAX_RECOG_OPERANDS different
SCRATCHes in a single insn.
Bernd
* jump.c (duplicate_loop_exit_test): Use copy_insn/copy_insn_1
instead of copy_rtx. Accept sequences that contain asm statements.
* emit_rtl.c (copy_insn_1, copy_insn): New functions.
(copy_insn_scratch_in, copy_insn_scratch_out, copy_insn_n_scratches,
orig_asm_operands_vector, copy_asm_operands_vector,
orig_asm_constraints_vecotr, copy_asm_constraints_vector): New static
variables.
* rtl.h (copy_insn, copy_insn_1): Declare.
--- ./jump.c.orig-1 Sun May 30 11:48:08 1999
+++ ./jump.c Sun May 30 11:59:44 1999
@@ -2603,8 +2603,7 @@ duplicate_loop_exit_test (loop_start)
remove_note (insn, p);
if (++num_insns > 20
|| find_reg_note (insn, REG_RETVAL, NULL_RTX)
- || find_reg_note (insn, REG_LIBCALL, NULL_RTX)
- || asm_noperands (PATTERN (insn)) > 0)
+ || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
return 0;
break;
default:
@@ -2666,7 +2665,7 @@ duplicate_loop_exit_test (loop_start)
break;
case INSN:
- copy = emit_insn_before (copy_rtx (PATTERN (insn)), loop_start);
+ copy = emit_insn_before (copy_insn (PATTERN (insn)), loop_start);
if (reg_map)
replace_regs (PATTERN (copy), reg_map, max_reg, 1);
@@ -2677,7 +2676,7 @@ duplicate_loop_exit_test (loop_start)
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) != REG_LABEL)
REG_NOTES (copy)
- = copy_rtx (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
+ = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
XEXP (link, 0),
REG_NOTES (copy)));
if (reg_map && REG_NOTES (copy))
@@ -2685,13 +2684,13 @@ duplicate_loop_exit_test (loop_start)
break;
case JUMP_INSN:
- copy = emit_jump_insn_before (copy_rtx (PATTERN (insn)), loop_start);
+ copy = emit_jump_insn_before (copy_insn (PATTERN (insn)), loop_start);
if (reg_map)
replace_regs (PATTERN (copy), reg_map, max_reg, 1);
mark_jump_label (PATTERN (copy), copy, 0);
if (REG_NOTES (insn))
{
- REG_NOTES (copy) = copy_rtx (REG_NOTES (insn));
+ REG_NOTES (copy) = copy_insn_1 (REG_NOTES (insn));
if (reg_map)
replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
}
--- ./rtl.h.orig-1 Sun May 30 11:48:16 1999
+++ ./rtl.h Sun May 30 11:48:19 1999
@@ -925,6 +925,8 @@ extern char *oballoc PROTO((int));
extern char *permalloc PROTO((int));
extern rtx rtx_alloc PROTO((RTX_CODE));
extern rtvec rtvec_alloc PROTO((int));
+extern rtx copy_insn_1 PROTO((rtx));
+extern rtx copy_insn PROTO((rtx));
extern rtx copy_rtx PROTO((rtx));
extern rtx copy_rtx_if_shared PROTO((rtx));
extern rtx copy_most_rtx PROTO((rtx, rtx));
--- ./emit-rtl.c.orig-1 Sun May 30 11:59:55 1999
+++ ./emit-rtl.c Sun May 30 12:02:46 1999
@@ -245,6 +245,9 @@ extern int rtx_equal_function_value_matt
extern char *emit_filename;
extern int emit_lineno;
+/* This is where the pointer to the obstack being used for RTL is stored. */
+extern struct obstack *rtl_obstack;
+
static rtx make_jump_insn_raw PROTO((rtx));
static rtx make_call_insn_raw PROTO((rtx));
static rtx find_line_note PROTO((rtx));
@@ -1710,6 +1713,199 @@ restore_emit_status (p)
sequence_result[i] = 0;
free_insn = 0;
+}
+
+/* Used by copy_insn_1 to avoid copying SCRATCHes more than once. */
+static rtx copy_insn_scratch_in[MAX_RECOG_OPERANDS];
+static rtx copy_insn_scratch_out[MAX_RECOG_OPERANDS];
+static int copy_insn_n_scratches;
+
+/* When an insn is being copied by copy_insn_1, this is nonzero if we have
+ copied an ASM_OPERANDS.
+ In that case, it is the original input-operand vector. */
+static rtvec orig_asm_operands_vector;
+
+/* When an insn is being copied by copy_insn_1, this is nonzero if we have
+ copied an ASM_OPERANDS.
+ In that case, it is the copied input-operand vector. */
+static rtvec copy_asm_operands_vector;
+
+/* Likewise for the constraints vector. */
+static rtvec orig_asm_constraints_vector;
+static rtvec copy_asm_constraints_vector;
+
+/* Recursively create a new copy of an rtx for copy_insn.
+ This function differs from copy_rtx in that it handles SCRATCHes and
+ ASM_OPERANDs properly.
+ Normally, this function is not used directly; use copy_insn as front end.
+ However, you could first copy an insn pattern with copy_insn and then use
+ this function afterwards to properly copy any REG_NOTEs containing
+ SCRATCHes. */
+
+rtx
+copy_insn_1 (orig)
+ register rtx orig;
+{
+ register rtx copy;
+ register int i, j;
+ register RTX_CODE code;
+ register char *format_ptr;
+
+ code = GET_CODE (orig);
+
+ switch (code)
+ {
+ case REG:
+ case QUEUED:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case ADDRESSOF:
+ return orig;
+
+ case SCRATCH:
+ for (i = 0; i < copy_insn_n_scratches; i++)
+ if (copy_insn_scratch_in[i] == orig)
+ return copy_insn_scratch_out[i];
+ break;
+
+ case CONST:
+ /* CONST can be shared if it contains a SYMBOL_REF. If it contains
+ a LABEL_REF, it isn't sharable. */
+ if (GET_CODE (XEXP (orig, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+ return orig;
+ break;
+
+ /* A MEM with a constant address is not sharable. The problem is that
+ the constant address may need to be reloaded. If the mem is shared,
+ then reloading one copy of this mem will cause all copies to appear
+ to have been reloaded. */
+
+ default:
+ break;
+ }
+
+ copy = rtx_alloc (code);
+
+ /* Copy the various flags, and other information. We assume that
+ all fields need copying, and then clear the fields that should
+ not be copied. That is the sensible default behavior, and forces
+ us to explicitly document why we are *not* copying a flag. */
+ memcpy (copy, orig, sizeof (struct rtx_def) - sizeof (rtunion));
+
+ /* We do not copy the USED flag, which is used as a mark bit during
+ walks over the RTL. */
+ copy->used = 0;
+
+ /* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs. */
+ if (GET_RTX_CLASS (code) == 'i')
+ {
+ copy->jump = 0;
+ copy->call = 0;
+ copy->frame_related = 0;
+ }
+
+ format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+
+ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ XEXP (copy, i) = XEXP (orig, i);
+ if (XEXP (orig, i) != NULL)
+ XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
+ break;
+
+ case '0':
+ case 'u':
+ XEXP (copy, i) = XEXP (orig, i);
+ break;
+
+ case 'E':
+ case 'V':
+ XVEC (copy, i) = XVEC (orig, i);
+ if (XVEC (orig, i) == orig_asm_constraints_vector)
+ XVEC (copy, i) = copy_asm_constraints_vector;
+ else if (XVEC (orig, i) == orig_asm_operands_vector)
+ XVEC (copy, i) = copy_asm_operands_vector;
+ else if (XVEC (orig, i) != NULL)
+ {
+ XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
+ for (j = 0; j < XVECLEN (copy, i); j++)
+ XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
+ }
+ break;
+
+ case 'b':
+ {
+ bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
+ bitmap_copy (new_bits, XBITMAP (orig, i));
+ XBITMAP (copy, i) = new_bits;
+ break;
+ }
+
+ case 't':
+ XTREE (copy, i) = XTREE (orig, i);
+ break;
+
+ case 'w':
+ XWINT (copy, i) = XWINT (orig, i);
+ break;
+
+ case 'i':
+ XINT (copy, i) = XINT (orig, i);
+ break;
+
+ case 's':
+ case 'S':
+ XSTR (copy, i) = XSTR (orig, i);
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ if (code == SCRATCH)
+ {
+ i = copy_insn_n_scratches++;
+ if (i >= MAX_RECOG_OPERANDS)
+ abort ();
+ copy_insn_scratch_in[i] = orig;
+ copy_insn_scratch_out[i] = copy;
+ }
+ else if (code == ASM_OPERANDS)
+ {
+ orig_asm_operands_vector = XVEC (orig, 3);
+ copy_asm_operands_vector = XVEC (copy, 3);
+ orig_asm_constraints_vector = XVEC (orig, 4);
+ copy_asm_constraints_vector = XVEC (copy, 4);
+ }
+
+ return copy;
+}
+
+/* Create a new copy of an rtx.
+ This function differs from copy_rtx in that it handles SCRATCHes and
+ ASM_OPERANDs properly.
+ INSN doesn't really have to be a full INSN; it could be just the
+ pattern. */
+rtx
+copy_insn (insn)
+ rtx insn;
+{
+ copy_insn_n_scratches = 0;
+ orig_asm_operands_vector = 0;
+ orig_asm_constraints_vector = 0;
+ copy_asm_operands_vector = 0;
+ copy_asm_constraints_vector = 0;
+ return copy_insn_1 (insn);
}
/* Go through all the RTL insn bodies and copy any invalid shared structure.