New function to copy insns

Bernd Schmidt crux@pool.informatik.rwth-aachen.de
Tue Jun 1 11:53:00 GMT 1999


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.



More information about the Gcc-patches mailing list