]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Convert all direct memory references to use LO_SUM and remove machdep hack that used...
authorMichael Hayes <m.hayes@elec.canterbury.ac.nz>
Sun, 24 Jan 1999 01:52:01 +0000 (01:52 +0000)
committerMichael Hayes <m.hayes@gcc.gnu.org>
Sun, 24 Jan 1999 01:52:01 +0000 (01:52 +0000)
Convert all direct memory references to use LO_SUM and remove machdep
hack that used to do this.
Sun Jan 24 21:24:43 1999  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
* config/c4x/c4x.c (c4x_emit_move_sequence, c4x_encode_section_info):
New functions.
(c4x_check_legit_addr): Remove USE and PLUS, allow
LO_SUM, and disable SYMBOL_REF, LABEL_REF, and CONST cases.
(c4x_legitimize_address): Penalise SYMBOL_REF, LABEL_REF, and
CONST cases.  Add LO_SUM.
(c4x_print_operand): Modified 'C' and 'R' cases for calls.
Added 'U' case.  Remove dependence on SYMBOL_REF_FLAG.
(c4x_print_operand_address): Handle LO_SUM.
(c4x_scan_for_ldp): Delete.  Hooray!
(c4x_process_after_reload): Remove call to c4x_scan_for_ldp.
Split all insns.
(c4x_immed_int_constant): Renamed from c4x_int_constant.  All callers
changed.
(c4x_immed_float_constant): Renamed from c4x_float_constant.  All
  callers changed.
(c4x_T_constraint): Allow LO_SUM, disable SYMBOL_REF, LABEL_REF,
and CONST.
(c4x_U_constraint, symbolic_operand): New functions.
(src_operand): Allow 'I' constants in HImode.  Allow LO_SUM,
disable SYMBOL_REF, LABEL_REF, and CONST.
(lsrc_operand, tsrc_operand): Call src_operand instead of
general_operand.
(c4x_operand_subword): Update comments.
* config/c4x/c4x.c (TARGET_LOAD_ADDRESS): New macro.
(LEGITIMATE_CONSTANT_P): Allow SYMBOL_REF, LABEL_REF, CONST,
plus HIGH and LO_SUM for the C40.
(ENCODE_SECTION_INFO): Define macro.
(symbolic_operand, c4x_U_constraint, c4x_emit_move_sequence): New
prototypes.
(PREDICATE_CODES): Add symbolic_operand.
* config/c4x/c4x.md (movqi, movgqf, movhi, movhi): Call
c4x_emit_move_sequence.
(floatunsqiqf2, fixuns_truncqfqi2): Rework emitted RTL
to avoid symbol references.
(all patterns with g constraint): Replace 'g' constraint with 'rIm'.
(set_high): Renamed from set_high_use.
(set_lo_sum): Renamed from set_ior_lo_use.
(all call patterns): Make MEM explicit in call address operands.
Modified output templates to use 'U' modifier.

From-SVN: r24842

gcc/ChangeLog
gcc/config/c4x/c4x.c
gcc/config/c4x/c4x.h
gcc/config/c4x/c4x.md

index 694d804e80a21977265b24a1674642d5bd02ec36..776dcdb0742ac225e9484e299822403692efccc8 100644 (file)
@@ -1,3 +1,48 @@
+Sun Jan 24 21:24:43 1999  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
+
+       * config/c4x/c4x.c (c4x_emit_move_sequence, c4x_encode_section_info):
+       New functions.
+       (c4x_check_legit_addr): Remove USE and PLUS, allow
+       LO_SUM, and disable SYMBOL_REF, LABEL_REF, and CONST cases.
+       (c4x_legitimize_address): Penalise SYMBOL_REF, LABEL_REF, and 
+       CONST cases.  Add LO_SUM.
+       (c4x_print_operand): Modified 'C' and 'R' cases for calls.
+       Added 'U' case.  Remove dependence on SYMBOL_REF_FLAG.
+       (c4x_print_operand_address): Handle LO_SUM.
+       (c4x_scan_for_ldp): Delete.  Hooray!
+       (c4x_process_after_reload): Remove call to c4x_scan_for_ldp.
+       Split all insns.
+       (c4x_immed_int_constant): Renamed from c4x_int_constant.  All callers
+       changed.
+       (c4x_immed_float_constant): Renamed from c4x_float_constant.  All
+       callers changed.
+       (c4x_T_constraint): Allow LO_SUM, disable SYMBOL_REF, LABEL_REF, 
+       and CONST.
+       (c4x_U_constraint, symbolic_operand): New functions.
+       (src_operand): Allow 'I' constants in HImode.  Allow LO_SUM,
+       disable SYMBOL_REF, LABEL_REF, and CONST.
+       (lsrc_operand, tsrc_operand): Call src_operand instead of
+       general_operand.
+       (c4x_operand_subword): Update comments.
+
+       * config/c4x/c4x.c (TARGET_LOAD_ADDRESS): New macro.
+       (LEGITIMATE_CONSTANT_P): Allow SYMBOL_REF, LABEL_REF, CONST,
+       plus HIGH and LO_SUM for the C40.
+       (ENCODE_SECTION_INFO): Define macro.
+       (symbolic_operand, c4x_U_constraint, c4x_emit_move_sequence): New
+       prototypes.
+       (PREDICATE_CODES): Add symbolic_operand.
+
+       * config/c4x/c4x.md (movqi, movgqf, movhi, movhi): Call
+       c4x_emit_move_sequence.
+       (floatunsqiqf2, fixuns_truncqfqi2): Rework emitted RTL
+       to avoid symbol references.
+       (all patterns with g constraint): Replace 'g' constraint with 'rIm'.
+       (set_high): Renamed from set_high_use.
+       (set_lo_sum): Renamed from set_ior_lo_use.
+       (all call patterns): Make MEM explicit in call address operands.
+       Modified output templates to use 'U' modifier.
+       
 Sun Jan 24 01:15:05 PST 1999 Jeff Law  (law@cygnus.com)
 
        * version.c: Bump for snapshot.
index f5c6fc2aad144848f35577a9a4c00a9c6a8b86b5..2e4b941136ebdd89f3c92f13f78699c1e0c7c5e4 100644 (file)
@@ -1016,6 +1016,84 @@ c4x_null_epilogue_p ()
 }
 
 
+int
+c4x_emit_move_sequence (operands, mode)
+     rtx *operands;
+     enum machine_mode mode;     
+{
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+
+  if (! reload_in_progress
+      && ! REG_P (op0) 
+      && ! REG_P (op1)
+      && ! (stik_const_operand (op1, mode) && ! push_operand (op0, mode)))
+    op1 = force_reg (mode, op1);
+
+  if (symbolic_operand (op1, mode))
+    {
+      if (TARGET_LOAD_ADDRESS)
+       {
+         /* Alias analysis seems to do a better job if we force
+            constant addresses to memory after reload.  */
+         emit_insn (gen_load_immed_address (op0, op1));
+         return 1;
+       }
+      else
+       {
+         /* Stick symbol or label address into the constant pool.  */
+         op1 = force_const_mem (Pmode, op1);
+       }
+    }
+  else if (mode == HFmode && CONSTANT_P (op1) && ! LEGITIMATE_CONSTANT_P (op1))
+    {
+      /* We could be a lot smarter about loading some of these
+        constants...  */
+      op1 = force_const_mem (mode, op1);
+    }
+  else if (mode == HImode && CONSTANT_P (op1) && ! LEGITIMATE_CONSTANT_P (op1))
+    {
+      /* We could load all sorts of constants in two goes by pulling all
+        sorts of tricks... The tricky thing is that we cannot clobber CC
+        so that stifles most of the obvious methods.  */
+      op1 = force_const_mem (mode, op1);
+    }
+
+  /* Convert (MEM (SYMREF)) to a (MEM (LO_SUM (REG) (SYMREF)))
+     and emit associated (HIGH (SYMREF)) if large memory model.  
+     c4x_legitimize_address could be used to do this,
+     perhaps by calling validize_address.  */
+  if (! (reload_in_progress || reload_completed)
+      && GET_CODE (op1) == MEM
+      && symbolic_operand (XEXP (op1, 0), Pmode))
+    {
+      rtx dp_reg = gen_rtx_REG (Pmode, DP_REGNO);
+      if (! TARGET_SMALL)
+       emit_insn (gen_set_ldp (dp_reg, XEXP (op1, 0)));
+      op1 = change_address (op1, mode,
+                           gen_rtx_LO_SUM (Pmode, dp_reg, XEXP (op1, 0)));
+    }
+
+  if (! (reload_in_progress || reload_completed)
+      && GET_CODE (op0) == MEM 
+      && symbolic_operand (XEXP (op0, 0), Pmode))
+    {
+      rtx dp_reg = gen_rtx_REG (Pmode, DP_REGNO);
+      if (! TARGET_SMALL)
+       emit_insn (gen_set_ldp (dp_reg, XEXP (op0, 0)));
+      op0 = change_address (op0, mode,
+                           gen_rtx_LO_SUM (Pmode, dp_reg, XEXP (op0, 0)));
+    }
+
+  /* Adjust operands in case we have modified them.  */
+  operands[0] = op0;
+  operands[1] = op1;
+
+  /* Emit normal pattern.  */
+  return 0;
+}
+
+
 void
 c4x_emit_libcall (name, code, dmode, smode, noperands, operands)
      char *name;
@@ -1066,6 +1144,7 @@ c4x_emit_libcall3 (name, code, mode, operands)
   return c4x_emit_libcall (name, code, mode, mode, 3, operands);
 }
 
+
 void
 c4x_emit_libcall_mulhi (name, code, mode, operands)
      char *name;
@@ -1096,7 +1175,7 @@ c4x_emit_libcall_mulhi (name, code, mode, operands)
 
 enum reg_class
 c4x_preferred_reload_class (x, class)
-     rtx x;
+     rtx x ATTRIBUTE_UNUSED;
      enum reg_class class;
 {
   return class;
@@ -1122,6 +1201,22 @@ c4x_secondary_memory_needed (class1, class2, mode)
 }
 
 
+/* Set the SYMBOL_REF_FLAG for a function decl.  However, wo do not
+   yet use this info.  */
+void
+c4x_encode_section_info (decl)
+  tree decl;
+{
+#if 0
+  if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)   
+    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+#else
+  if (TREE_CODE (decl) == FUNCTION_DECL)   
+    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+#endif
+}
+
+
 int
 c4x_check_legit_addr (mode, addr, strict)
      enum machine_mode mode;
@@ -1187,19 +1282,6 @@ c4x_check_legit_addr (mode, addr, strict)
 
        switch (code0)
          {
-         case USE:
-           /* The uses are put in to avoid problems
-              with referenced things disappearing.  */
-           return c4x_check_legit_addr (mode, op1, strict);
-
-         case PLUS:
-           /* This is another reference to keep things
-              from disappearing, but it contains a plus
-              of a use and DP.  */
-           if (GET_CODE (XEXP (op0, 0)) == USE)
-             return c4x_check_legit_addr (mode, op1, strict);
-           return 0;
-
          case REG:
            if (REG_P (op1))
              {
@@ -1224,18 +1306,47 @@ c4x_check_legit_addr (mode, addr, strict)
       }
       break;
 
+      /* Direct addressing with DP register.  */
+    case LO_SUM:
+      {
+       rtx op0 = XEXP (addr, 0);
+       rtx op1 = XEXP (addr, 1);
+
+       /* HImode and HFmode direct memory references aren't truly
+          offsettable (consider case at end of data page).  We
+          probably get better code by loading a pointer and using an
+          indirect memory reference.  */
+       if (mode == HImode || mode == HFmode)
+         return 0;
+
+       if (!REG_P (op0) || REGNO (op0) != DP_REGNO)
+         return 0;
+
+       if ((GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF))
+         return 1;
+
+       if (GET_CODE (op1) == CONST)
+         {
+           addr = XEXP (op1, 0);
+           
+           if (GET_CODE (addr) == PLUS
+               && (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF
+                   || GET_CODE (XEXP (addr, 0)) == LABEL_REF)
+               && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+             return 1;
+         }
+       return 0;
+      }
+      break;
+
       /* Direct addressing with some work for the assembler...  */
     case CONST:
-      if (GET_CODE (XEXP (addr, 0)) == PLUS
-         && (GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF
-             || GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF)
-         && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
-       return 1;
-
       /* Direct addressing.  */
-    case SYMBOL_REF:
     case LABEL_REF:
-      return 1;
+    case SYMBOL_REF:
+      /* These need to be converted to a LO_SUM (...). 
+        c4x_legitimize_address will fix them up.  */
+      return 0;
 
       /* Do not allow direct memory access to absolute addresses.
          This is more pain than its worth, especially for the
@@ -1313,6 +1424,16 @@ c4x_legitimize_address (orig, mode)
      rtx orig ATTRIBUTE_UNUSED;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
+  if (GET_CODE (orig) == SYMBOL_REF)
+    {
+      rtx dp_reg = gen_rtx_REG (Pmode, DP_REGNO);
+
+      if (! TARGET_SMALL)
+       emit_insn (gen_set_ldp (dp_reg, orig));
+      
+      return gen_rtx_LO_SUM (Pmode, dp_reg, orig);
+    }
+
   return NULL_RTX;
 }
 
@@ -1332,32 +1453,46 @@ rtx addr;
     case REG:
       return 1;
 
-    case CONST:
-      {
-       rtx offset = const0_rtx;
-       addr = eliminate_constant_term (addr, &offset);
-       
-       if (GET_CODE (addr) == LABEL_REF)
-         return 3;
-       
-       if (GET_CODE (addr) != SYMBOL_REF)
-         return 4;
-
-       if (INTVAL (offset) == 0)
-         return 3;
-      }
-      
-      /* fall through */
-      
     case POST_INC:
     case POST_DEC:
     case PRE_INC:
     case PRE_DEC:
       return 1;
       
+      /* These shouldn't be directly generated.  */
     case SYMBOL_REF:
     case LABEL_REF:
-      return TARGET_SMALL ? 3 : 4;
+    case CONST:
+      return 10;
+
+    case LO_SUM:
+      {
+       rtx op1 = XEXP (addr, 1);
+
+       if (GET_CODE (op1) == LABEL_REF || GET_CODE (op1) == SYMBOL_REF)
+         return TARGET_SMALL ? 3 : 4;
+       
+       if (GET_CODE (op1) == CONST)
+         {
+           rtx offset = const0_rtx;
+           
+           op1 = eliminate_constant_term (op1, &offset);
+           
+           /* ??? These costs need rethinking... */
+           if (GET_CODE (op1) == LABEL_REF)
+             return 3;
+           
+           if (GET_CODE (op1) != SYMBOL_REF)
+             return 4;
+           
+           if (INTVAL (offset) == 0)
+             return 3;
+
+           return 4;
+         }
+       fatal_insn ("c4x_address_cost: Invalid addressing mode", addr);
+      }
+      break;
       
     case PLUS:
       {
@@ -1479,18 +1614,9 @@ c4x_print_operand (file, op, letter)
        asm_fprintf (file, "@");
       break;
 
-    case 'C':                  /* call */
-      if (code != MEM)
-       fatal_insn ("c4x_print_operand: %%C inconsistency", op);
-      op1 = XEXP (op, 0);
-      SYMBOL_REF_FLAG (op1) = 1;
-      output_addr_const (file, op1);
-      return;
-
     case 'H':                  /* sethi */
-      if (code == SYMBOL_REF)
-       SYMBOL_REF_FLAG (op) = 1;
-      break;
+      output_addr_const (file, op);
+      return;
 
     case 'I':                  /* reversed condition */
       code = reverse_condition (code);
@@ -1511,9 +1637,9 @@ c4x_print_operand (file, op, letter)
     case 'K':                  /* generate ldp(k) if direct address */
       if (! TARGET_SMALL
          && code == MEM
-         && GET_CODE (XEXP (op, 0)) == PLUS
-         && GET_CODE(XEXP (XEXP (op, 0), 0)) == REG
-         && REGNO(XEXP (XEXP (op, 0), 0)) == DP_REGNO)
+         && GET_CODE (XEXP (op, 0)) == LO_SUM
+         && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+         && REGNO (XEXP (XEXP (op, 0), 0)) == DP_REGNO)
        {
          op1 = XEXP (XEXP (op, 0), 1);
           if (GET_CODE(op1) == CONST_INT || GET_CODE(op1) == SYMBOL_REF)
@@ -1548,12 +1674,18 @@ c4x_print_operand (file, op, letter)
        fatal_insn ("c4x_print_operand: %%O inconsistency", op);
       return;
 
-    case 'R':                  /* call register */
-      op1 = XEXP (op, 0);
-      if (code != MEM || GET_CODE (op1) != REG)
-       fatal_insn ("c4x_print_operand: %%R inconsistency", op);
-      else
-       fprintf (file, "%s", reg_names[REGNO (op1)]);
+    case 'C':                  /* call */
+      if (code != MEM)
+       fatal_insn ("c4x_print_operand: %%C inconsistency", op);
+      op = XEXP (op, 0);
+      code = GET_CODE (op);
+      break;
+
+    case 'U':                  /* call/callu */
+      if (code != MEM)
+       fatal_insn ("c4x_print_operand: %%U inconsistency", op);
+      if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
+       asm_fprintf (file, "u");
       return;
 
     default:
@@ -1721,20 +1853,10 @@ c4x_print_operand_address (file, addr)
       {
        rtx op0 = XEXP (addr, 0);
        rtx op1 = XEXP (addr, 1);
-       enum rtx_code code0 = GET_CODE (op0);
 
-       if (code0 == USE || code0 == PLUS)
-         {
-           asm_fprintf (file, "@");
-           output_addr_const (file, op1);
-         }
-       else if (REG_P (op0))
+       if (REG_P (op0))
          {
-           if (REGNO (op0) == DP_REGNO)
-             {
-               c4x_print_operand_address (file, op1);
-             }
-           else if (REG_P (op1))
+           if (REG_P (op1))
              {
                if (IS_INDEX_REGNO (op0))
                  {
@@ -1762,16 +1884,28 @@ c4x_print_operand_address (file, addr)
                         INTVAL (op1));         /* base + displacement */
              }
          }
+       else
+          fatal_insn ("c4x_print_operand_address: Bad operand case", addr);
+      }
+      break;
+
+    case LO_SUM:
+      {
+       rtx op0 = XEXP (addr, 0);
+       rtx op1 = XEXP (addr, 1);
+         
+       if (REG_P (op0) && REGNO (op0) == DP_REGNO)
+         c4x_print_operand_address (file, op1);
+       else
+          fatal_insn ("c4x_print_operand_address: Bad operand case", addr);
       }
       break;
 
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
-      if (! SYMBOL_REF_FLAG (addr))
-       fprintf (file, "@");
+      fprintf (file, "@");
       output_addr_const (file, addr);
-      SYMBOL_REF_FLAG (addr) = 0;
       break;
 
       /* We shouldn't access CONST_INT addresses.  */
@@ -1783,17 +1917,18 @@ c4x_print_operand_address (file, addr)
     }
 }
 
-
+/* Return nonzero if the floating point operand will fit
+   in the immediate field.  */
 static int
-c4x_immed_float_p (operand)
-     rtx operand;
+c4x_immed_float_p (op)
+     rtx op;
 {
   long convval[2];
   int exponent;
   REAL_VALUE_TYPE r;
 
-  REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
-  if (GET_MODE (operand) == HFmode)
+  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+  if (GET_MODE (op) == HFmode)
     REAL_VALUE_TO_TARGET_DOUBLE (r, convval);
   else
     {
@@ -1811,157 +1946,6 @@ c4x_immed_float_p (operand)
     && (exponent >= -7);       /* Negative exp */
 }
 
-
-/* This function checks for an insn operand that requires direct
-   addressing and inserts a load of the DP register prior to the
-   insn if the big memory model is being compiled for.  Immediate
-   operands that do not fit within the opcode field get changed
-   into memory references using direct addressing.  At this point
-   all pseudos have been converted to hard registers.  */
-
-int
-c4x_scan_for_ldp (newop, insn, operand0)
-     rtx *newop;
-     rtx insn;
-     rtx operand0;
-{
-  int i;
-  char *format_ptr;
-  rtx op0, op1, op2, addr;
-  rtx operand = *newop;
-
-  switch (GET_CODE (operand))
-    {
-    case MEM:
-      op0 = XEXP (operand, 0);
-
-      /* We have something we need to emit a load dp insn for.
-         The first operand should hold the rtx for the instruction
-         required.  */
-
-      switch (GET_CODE (op0))
-       {
-       case CONST_INT:
-         fatal_insn ("c4x_scan_for_ldp: Direct memory access to const_int",
-                    op0);
-         break;
-
-       case CONST:
-       case SYMBOL_REF:
-         if (! TARGET_C3X && ! TARGET_SMALL
-             && recog_memoized (insn) == CODE_FOR_movqi_noclobber
-             && ((addr = find_reg_note (insn, REG_EQUAL, NULL_RTX))
-                 || (addr = find_reg_note (insn, REG_EQUIV, NULL_RTX)))
-             && (IS_STD_OR_PSEUDO_REGNO (operand0)))
-           {
-             addr = XEXP (addr, 0);
-             if (GET_CODE (addr) == CONST_INT)
-               {
-                 op1 = GEN_INT (INTVAL (addr) & ~0xffff);
-                 emit_insn_before (gen_movqi (operand0, op1), insn);
-                 op1 = GEN_INT (INTVAL (addr) & 0xffff);
-                 emit_insn_before (gen_iorqi3_noclobber (operand0,
-                                                     operand0, op1), insn);
-                 delete_insn (insn);
-                 return 1;
-               }
-             else if (GET_CODE (addr) == SYMBOL_REF)
-               {
-                 emit_insn_before (gen_set_high_use (operand0, addr, addr),
-                                   insn);
-                 emit_insn_before (gen_set_ior_lo_use (operand0, addr, addr),
-                                   insn);
-                 delete_insn (insn);
-                 return 1;
-               }
-             else if (GET_CODE (addr) == CONST
-                      && GET_CODE (op1 = XEXP (addr, 0)) == PLUS
-                      && GET_CODE (op2 = XEXP (op1, 0)) == SYMBOL_REF
-                      && GET_CODE (XEXP (op1, 1)) == CONST_INT)
-               {
-                 emit_insn_before (gen_set_high_use (operand0, addr, op2),
-                                   insn);
-                 emit_insn_before (gen_set_ior_lo_use (operand0, addr, op2),
-                                   insn);
-                 delete_insn (insn);
-                 return 1;
-               }
-           }
-         if (! TARGET_SMALL)
-           emit_insn_before (gen_set_ldp (gen_rtx_REG (Pmode, DP_REGNO),
-                                          operand), insn);
-
-         /* Replace old memory reference with direct reference.  */
-         *newop = gen_rtx_MEM (GET_MODE (operand),
-                               gen_rtx_PLUS (Pmode,
-                                             gen_rtx_REG (Pmode, DP_REGNO),
-                                             op0));
-
-         /* Use change_address?  */
-         RTX_UNCHANGING_P (*newop) = RTX_UNCHANGING_P (operand);
-         MEM_COPY_ATTRIBUTES (*newop, operand);
-         break;
-
-       default:
-         break;
-       }
-
-      return 0;
-
-    case CONST_INT:
-      if (SMALL_CONST (INTVAL (operand), insn))
-       break;
-      fatal_insn ("Immediate integer too large", insn);
-
-    case CONST_DOUBLE:
-      if (c4x_immed_float_p (operand))
-       break;
-
-      /* We'll come here if a CONST_DOUBLE integer has slipped
-         though the net...  */
-      fatal_insn ("Immediate CONST_DOUBLE integer too large", insn);
-
-    case CONST:
-      fatal_insn ("Immediate integer not known", insn);
-
-      /* Symbol and label immediate addresses cannot be stored
-         within a C[34]x instruction, so we store them in memory
-         and use direct addressing instead.  */
-    case LABEL_REF:
-    case SYMBOL_REF:
-      if (GET_CODE (operand0) != REG)
-       break;
-
-      op0 = XEXP (force_const_mem (Pmode, operand), 0);
-      *newop = gen_rtx_MEM (GET_MODE (operand),
-                           gen_rtx_PLUS (Pmode,
-                                         gen_rtx_PLUS (Pmode,
-                                             gen_rtx_USE (VOIDmode, operand),
-                                             gen_rtx_REG (Pmode, DP_REGNO)),
-                                         op0));
-      
-      if (! TARGET_SMALL)
-       emit_insn_before (gen_set_ldp_use (gen_rtx_REG (Pmode, DP_REGNO),
-                                          *newop, operand), insn);
-      return 0;
-
-    default:
-      break;
-    }
-
-  format_ptr = GET_RTX_FORMAT (GET_CODE (operand));
-
-  /* Recursively hunt for required loads of DP.  */
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
-    {
-      if (*format_ptr++ == 'e')        /* rtx expression */
-       if (c4x_scan_for_ldp (&XEXP (operand, i), insn, operand0))
-         break;
-    }
-  return 0;
-}
-
-
 /* The last instruction in a repeat block cannot be a Bcond, DBcound,
    CALL, CALLCond, TRAPcond, RETIcond, RETScond, IDLE, RPTB or RPTS.
 
@@ -1993,7 +1977,11 @@ c4x_rptb_nop_p (insn)
 
   /* If there is a label at the end of the loop we must insert
      a NOP.  */
-  insn = prev_nonnote_insn (insn);
+  do {
+    insn = previous_insn (insn);
+  } while (GET_CODE (insn) == NOTE
+          || GET_CODE (insn) == USE
+          || GET_CODE (insn) == CLOBBER);
   if (GET_CODE (insn) == CODE_LABEL)
     return 1;
 
@@ -2006,7 +1994,7 @@ c4x_rptb_nop_p (insn)
          if (insn == start_label)
            return i == 0;
 
-         insn = PREV_INSN (insn);
+         insn = previous_insn (insn);
        };
 
       /* If we have a jump instruction we should insert a NOP. If we
@@ -2014,7 +2002,7 @@ c4x_rptb_nop_p (insn)
         is empty. */
       if (GET_CODE (insn) == JUMP_INSN)
        return 1;
-      insn = PREV_INSN (insn);
+      insn = previous_insn (insn);
     }
   return 0;
 }
@@ -2053,20 +2041,16 @@ c4x_rptb_insert (insn)
   emit_insn_before (gen_rptb_top (start_label, end_label), insn);
 }
 
-/* This function is a C4x special. It scans through all the insn
-   operands looking for places where the DP register needs to be
-   reloaded and for large immediate operands that need to be converted
-   to memory references.  The latter should be avoidable with proper
-   definition of patterns in machine description.  We come here right
-   near the end of things, immediately before delayed branch
-   scheduling.  */
+
+/* This function is a C4x special called immediately before delayed
+   branch scheduling.  We fix up RTPB style loops that didn't get RC
+   allocated as the loop counter.  */
 
 void
 c4x_process_after_reload (first)
      rtx first;
 {
   rtx insn;
-  int i;
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
@@ -2086,11 +2070,9 @@ c4x_process_after_reload (first)
            c4x_rptb_insert(insn);
 
          /* We split all insns here if they have a # for the output
-            template if we are using the big memory model since there
-            is a chance that we might be accessing memory across a
-            page boundary.  */
+            template.  */
 
-         if (! TARGET_SMALL)
+         if (1)
            {
              char *template;
 
@@ -2106,30 +2088,9 @@ c4x_process_after_reload (first)
                  PUT_CODE (insn, NOTE);
                  NOTE_SOURCE_FILE (insn) = 0;
                  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-
-                 /* Do we have to update the basic block info here? 
-                    Maybe reorg wants it sorted out... */
-
-                 /* Continue with the first of the new insns generated
-                     by the split. */
                  insn = new;
-
-                 insn_code_number = recog_memoized (insn);
-                 
-                 if (insn_code_number < 0)
-                   continue;
                }
            }
-
-         /* Ignore jumps and calls.  */
-         if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
-             continue; 
-
-         insn_extract (insn);
-         for (i = 0; i < insn_n_operands[insn_code_number]; i++)
-           if (c4x_scan_for_ldp (recog_operand_loc[i], insn, 
-                                 recog_operand[0]))
-             break;
        }
     }
 }
@@ -2152,11 +2113,12 @@ c4x_x_register (op)
 
 
 static int
-c4x_int_constant (op)
+c4x_immed_int_constant (op)
      rtx op;
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
+
   return GET_MODE (op) == VOIDmode
     || GET_MODE_CLASS (op) == MODE_INT
     || GET_MODE_CLASS (op) == MODE_PARTIAL_INT;
@@ -2164,11 +2126,15 @@ c4x_int_constant (op)
 
 
 static int
-c4x_float_constant (op)
+c4x_immed_float_constant (op)
      rtx op;
 {
   if (GET_CODE (op) != CONST_DOUBLE)
     return 0;
+
+  if (GET_CODE (XEXP (op, 0)) == MEM)
+    return 0;
+
   return GET_MODE (op) == QFmode || GET_MODE (op) == HFmode;
 }
 
@@ -2177,7 +2143,7 @@ int
 c4x_H_constant (op)
      rtx op;
 {
-  return c4x_float_constant (op) && c4x_immed_float_p (op);
+  return c4x_immed_float_constant (op) && c4x_immed_float_p (op);
 }
 
 
@@ -2185,7 +2151,7 @@ int
 c4x_I_constant (op)
      rtx op;
 {
-  return c4x_int_constant (op) && IS_INT16_CONST (INTVAL (op));
+  return c4x_immed_int_constant (op) && IS_INT16_CONST (INTVAL (op));
 }
 
 
@@ -2195,7 +2161,7 @@ c4x_J_constant (op)
 {
   if (TARGET_C3X)
     return 0;
-  return c4x_int_constant (op) && IS_INT8_CONST (INTVAL (op));
+  return c4x_immed_int_constant (op) && IS_INT8_CONST (INTVAL (op));
 }
 
 
@@ -2205,7 +2171,7 @@ c4x_K_constant (op)
 {
   if (TARGET_C3X)
     return 0;
-  return c4x_int_constant (op) && IS_INT5_CONST (INTVAL (op));
+  return c4x_immed_int_constant (op) && IS_INT5_CONST (INTVAL (op));
 }
 
 
@@ -2213,7 +2179,7 @@ int
 c4x_L_constant (op)
      rtx op;
 {
-  return c4x_int_constant (op) && IS_UINT16_CONST (INTVAL (op));
+  return c4x_immed_int_constant (op) && IS_UINT16_CONST (INTVAL (op));
 }
 
 
@@ -2221,7 +2187,7 @@ static int
 c4x_N_constant (op)
      rtx op;
 {
-  return c4x_int_constant (op) && IS_NOT_UINT16_CONST (INTVAL (op));
+  return c4x_immed_int_constant (op) && IS_NOT_UINT16_CONST (INTVAL (op));
 }
 
 
@@ -2229,7 +2195,7 @@ static int
 c4x_O_constant (op)
      rtx op;
 {
-  return c4x_int_constant (op) && IS_HIGH_CONST (INTVAL (op));
+  return c4x_immed_int_constant (op) && IS_HIGH_CONST (INTVAL (op));
 }
 
 
@@ -2277,6 +2243,7 @@ c4x_Q_constraint (op)
        return IS_DISP8_CONST (INTVAL (op1));
       }
       break;
+
     default:
       break;
     }
@@ -2508,7 +2475,7 @@ c4x_S_indirect (op)
 }
 
 
-/* Symbol ref.  */
+/* Direct memory operand.  */
 
 int
 c4x_T_constraint (op)
@@ -2518,27 +2485,37 @@ c4x_T_constraint (op)
     return 0;
   op = XEXP (op, 0);
 
-  if ((GET_CODE (op) == PLUS)
-      && (GET_CODE (XEXP (op, 0)) == REG)
-      && (REGNO (XEXP (op, 0)) == DP_REGNO))
+  if (GET_CODE (op) != LO_SUM)
     {
-      op = XEXP (op, 1);
-    }
-  else if ((GET_CODE (op) == PLUS)
-          && (GET_CODE (XEXP (op, 0)) == PLUS)
-          && (GET_CODE (XEXP (XEXP (op, 0), 0)) == USE))
-    {
-      op = XEXP (op, 1);
-    }
-  else if ((GET_CODE (op) == PLUS) && (GET_CODE (XEXP (op, 0)) == USE))
-    {
-      op = XEXP (op, 1);
+      /* Allow call operands.  */
+      return GET_CODE (op) == SYMBOL_REF
+       && GET_MODE (op) == Pmode
+       && SYMBOL_REF_FLAG (op);
     }
 
+  /* HImode and HFmode are not offsettable.  */
+  if (GET_MODE (op) == HImode || GET_CODE (op) == HFmode)
+    return 0;
+
+  if ((GET_CODE (XEXP (op, 0)) == REG)
+      && (REGNO (XEXP (op, 0)) == DP_REGNO))
+    return c4x_U_constraint (XEXP (op, 1));
+  
+  return 0;
+}
+
+
+/* Symbolic operand.  */
+
+int
+c4x_U_constraint (op)
+     rtx op;
+{
   /* Don't allow direct addressing to an arbitrary constant.  */
   if (GET_CODE (op) == CONST
       && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
+      && (GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
+         || GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF)
       && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
     return 1;
 
@@ -2657,6 +2634,7 @@ reg_operand (op, mode)
   return register_operand (op, mode);
 }
 
+
 int
 reg_imm_operand (op, mode)
      rtx op;
@@ -2667,6 +2645,7 @@ reg_imm_operand (op, mode)
   return 0;
 }
 
+
 int
 not_modify_reg (op, mode)
      rtx op;
@@ -2693,6 +2672,16 @@ not_modify_reg (op, mode)
        if (REG_P (op1) || GET_CODE (op1) == CONST_INT)
          return 1;
       }
+
+    case LO_SUM:
+      {
+       rtx op0 = XEXP (op, 0);
+         
+       if (REG_P (op0) && REGNO (op0) == DP_REGNO)
+         return 1;
+      }
+      break;
+     
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -2703,6 +2692,7 @@ not_modify_reg (op, mode)
   return 0;
 }
 
+
 int
 not_rc_reg (op, mode)
      rtx op;
@@ -2713,6 +2703,7 @@ not_rc_reg (op, mode)
   return 1;
 }
 
+
 /* Extended precision register R0-R1.  */
 
 int
@@ -2867,8 +2858,6 @@ call_operand (op, mode)
      rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  if (GET_CODE (op) != MEM)
-    return 0;
   op = XEXP (op, 0);
   switch (GET_CODE (op))
     {
@@ -2881,6 +2870,29 @@ call_operand (op, mode)
 }
 
 
+/* Symbolic operand.  */
+
+int
+symbolic_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  switch (GET_CODE (op))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+    case CONST:
+      op = XEXP (op, 0);
+      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+             && GET_CODE (XEXP (op, 1)) == CONST_INT);
+    default:
+      return 0;
+    }
+}
+
+
 /* Check src operand of two operand arithmetic instructions.  */
 
 int
@@ -2894,14 +2906,29 @@ src_operand (op, mode)
   if (mode == VOIDmode)
     mode = GET_MODE (op);
 
-  /* We could allow certain CONST_INT values for HImode...  */
   if (GET_CODE (op) == CONST_INT)
-    return (mode == QImode || mode == Pmode) && c4x_I_constant (op);
+    return (mode == QImode || mode == Pmode || mode == HImode)
+      && c4x_I_constant (op);
 
   /* We don't like CONST_DOUBLE integers.  */
   if (GET_CODE (op) == CONST_DOUBLE)
     return c4x_H_constant (op);
 
+  /* Disallow symbolic addresses.  */
+  if (GET_CODE (op) == SYMBOL_REF
+      || GET_CODE (op) == LABEL_REF
+      || GET_CODE (op) == CONST)
+    return 0;
+
+  /* Disallow direct memory access symbolic addresses. 
+     These are usually caught by the movqi expander and
+     converted to a LO_SUM.  */
+  if (GET_CODE (op) == MEM
+      && ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+          || GET_CODE (XEXP (op, 0)) == LABEL_REF
+          || GET_CODE (XEXP (op, 0)) == CONST)))
+    return 0;
+
   return general_operand (op, mode);
 }
 
@@ -2930,13 +2957,10 @@ lsrc_operand (op, mode)
   if (mode != QImode && mode != Pmode)
     fatal_insn ("Mode not QImode", op);
 
-  if (REG_P (op))
-    return reg_operand (op, mode);
-
   if (GET_CODE (op) == CONST_INT)
     return c4x_L_constant (op) || c4x_J_constant (op);
 
-  return general_operand (op, mode);
+  return src_operand (op, mode);
 }
 
 
@@ -2953,13 +2977,10 @@ tsrc_operand (op, mode)
   if (mode != QImode && mode != Pmode)
     fatal_insn ("Mode not QImode", op);
 
-  if (REG_P (op))
-    return reg_operand (op, mode);
-
   if (GET_CODE (op) == CONST_INT)
     return c4x_L_constant (op) || c4x_N_constant (op) || c4x_J_constant (op);
 
-  return general_operand (op, mode);
+  return src_operand (op, mode);
 }
 
 
@@ -3441,7 +3462,7 @@ c4x_valid_operands (code, operands, mode, force)
          break;
          
        default:
-         fatal ("c4x_valid_operands: Internal error");
+         fatal_insn ("c4x_valid_operands: Internal error", op2);
          break;
        }
       
@@ -3922,16 +3943,19 @@ c4x_operand_subword (op, i, validate_address, mode)
     {
       enum rtx_code code = GET_CODE (XEXP (op, 0));
       enum machine_mode mode = GET_MODE (XEXP (op, 0));
+      enum machine_mode submode;
+
+      submode = mode;
+      if (mode == HImode)
+       submode = QImode;
+      else if (mode == HFmode)
+       submode = QFmode;
 
       switch (code)
        {
        case POST_INC:
        case PRE_INC:
-         if (mode == HImode)
-           mode = QImode;
-         else if (mode == HFmode)
-           mode = QFmode;
-         return gen_rtx_MEM (mode, XEXP (op, 0));
+         return gen_rtx_MEM (submode, XEXP (op, 0));
          
        case POST_DEC:
        case PRE_DEC:
@@ -3941,6 +3965,23 @@ c4x_operand_subword (op, i, validate_address, mode)
             e.g., *p-- => *(p-=2); *(p+1).  */
          fatal_insn ("c4x_operand_subword: invalid autoincrement", op);
 
+       case SYMBOL_REF:
+       case LABEL_REF:
+       case CONST:
+       case CONST_INT:
+         fatal_insn ("c4x_operand_subword: invalid address", op);
+
+         /* Even though offsettable_address_p considers (MEM
+            (LO_SUM)) to be offsettable, it is not safe if the
+            address is at the end of the data page since we also have
+            to fix up the associated high PART.  In this case where
+            we are trying to split a HImode or HFmode memory
+            reference, we would have to emit another insn to reload a
+            new HIGH value.  It's easier to disable LO_SUM memory references
+            in HImode or HFmode and we probably get better code.  */
+       case LO_SUM:
+         fatal_insn ("c4x_operand_subword: address not offsettable", op);
+  
        default:
          break;
        }
@@ -4233,7 +4274,6 @@ c4x_adjust_cost (insn, link, dep_insn, cost)
 
       /* Data dependency; DEP_INSN writes a register that INSN reads some
         cycles later.  */
-
       if (TARGET_C3X)
        {
          if (get_attr_setgroup1 (dep_insn) && get_attr_usegroup1 (insn))
@@ -4248,7 +4288,6 @@ c4x_adjust_cost (insn, link, dep_insn, cost)
             insn uses ar0-ar7.  We then test if the same register
             is used.  The tricky bit is that some operands will
             use several registers...  */
-
          if (get_attr_setar0 (dep_insn) && get_attr_usear0 (insn))
            max = SET_USE_COST > max ? SET_USE_COST : max;
          if (get_attr_setlda_ar0 (dep_insn) && get_attr_usear0 (insn))
@@ -4342,3 +4381,4 @@ c4x_adjust_cost (insn, link, dep_insn, cost)
   else
     abort ();
 }
+
index 2a0a7c045d480b4fb24dacd8bae2c4dbc51afef2..c001712c89446f8d0e943626e1ee8a51ee7921d8 100644 (file)
@@ -258,12 +258,16 @@ extern int target_flags;
 #define TARGET_C40             (target_flags & C40_FLAG)
 #define TARGET_C44             (target_flags & C44_FLAG)
 
+#define TARGET_LOAD_ADDRESS    (1 || (! TARGET_C3X && ! TARGET_SMALL))
+
 /* -mrpts            allows the use of the RPTS instruction irregardless.
    -mrpts=max-cycles will use RPTS if the number of cycles is constant
    and less than max-cycles. */
 
 #define TARGET_RPTS_CYCLES(CYCLES) (TARGET_RPTS || (CYCLES) < c4x_rpts_cycles)
 
+#define        BCT_CHECK_LOOP_ITERATIONS  !(TARGET_LOOP_UNSIGNED)
+
 /* -mcpu=XX    with XX = target DSP version number */
 
 /* This macro is similar to `TARGET_SWITCHES' but defines names of
@@ -836,16 +840,17 @@ c4x_secondary_memory_needed(CLASS1, CLASS2, MODE)
        : ((C) == 'O') ? (IS_HIGH_CONST (VAL))                          \
         : 0 )  
 
-#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL, C)                           \
-        ( ((C) == 'G') ? (fp_zero_operand (VAL))                       \
-       : ((C) == 'H') ? (c4x_H_constant (VAL))                         \
+#define CONST_DOUBLE_OK_FOR_LETTER_P(OP, C)                            \
+        ( ((C) == 'G') ? (fp_zero_operand (OP))                                \
+       : ((C) == 'H') ? (c4x_H_constant (OP))                          \
        : 0 )
 
-#define EXTRA_CONSTRAINT(VAL, C) \
-        ( ((C) == 'Q') ? (c4x_Q_constraint (VAL))                      \
-       : ((C) == 'R') ? (c4x_R_constraint (VAL))                       \
-       : ((C) == 'S') ? (c4x_S_constraint (VAL))                       \
-       : ((C) == 'T') ? (c4x_T_constraint (VAL))                       \
+#define EXTRA_CONSTRAINT(OP, C) \
+        ( ((C) == 'Q') ? (c4x_Q_constraint (OP))                       \
+       : ((C) == 'R') ? (c4x_R_constraint (OP))                        \
+       : ((C) == 'S') ? (c4x_S_constraint (OP))                        \
+       : ((C) == 'T') ? (c4x_T_constraint (OP))                        \
+       : ((C) == 'U') ? (c4x_U_constraint (OP))                        \
        : 0 )
 
 #define SMALL_CONST(VAL, insn)                                         \
@@ -1613,17 +1618,44 @@ extern struct rtx_def *c4x_legitimize_address ();
 /* Nonzero if the constant value X is a legitimate general operand.
    It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. 
 
-   The C4x can only load 16-bit immediate values, so we only allow
-   a restricted subset of CONST_INT and CONST_DOUBLE and reject
-   LABEL_REF, SYMBOL_REF, CONST, and HIGH codes.  */
+   The C4x can only load 16-bit immediate values, so we only allow a
+   restricted subset of CONST_INT and CONST_DOUBLE.  Disallow
+   LABEL_REF and SYMBOL_REF (except on the C40 with the big memory
+   model) so that the symbols will be forced into the constant pool.
+   On second thoughts, lets do this with the move expanders.
+*/
 
 #define LEGITIMATE_CONSTANT_P(X)                               \
   ((GET_CODE (X) == CONST_DOUBLE && c4x_H_constant (X))                \
-  || (GET_CODE (X) == CONST_INT && c4x_I_constant (X)))
-
+  || (GET_CODE (X) == CONST_INT && c4x_I_constant (X))         \
+  || (GET_CODE (X) == SYMBOL_REF)                              \
+  || (GET_CODE (X) == LABEL_REF)                               \
+  || (GET_CODE (X) == CONST)                                   \
+  || (GET_CODE (X) == HIGH && ! TARGET_C3X)                    \
+  || (GET_CODE (X) == LO_SUM && ! TARGET_C3X))
 
 #define LEGITIMATE_DISPLACEMENT_P(X) IS_DISP8_CONST (INTVAL (X))
 
+/* Define this macro if references to a symbol must be treated
+   differently depending on something about the variable or
+   function named by the symbol (such as what section it is in).
+
+   The macro definition, if any, is executed immediately after the
+   rtl for DECL or other node is created.
+   The value of the rtl will be a `mem' whose address is a
+   `symbol_ref'.
+
+   The usual thing for this macro to do is to a flag in the
+   `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified
+   name string in the `symbol_ref' (if one bit is not enough
+   information).
+
+   On the C4x we use this to indicate if a symbol is in text or
+   data space.  */
+
+extern void c4x_encode_section_info ();
+#define ENCODE_SECTION_INFO(DECL) c4x_encode_section_info (DECL);
+
 /* Descripting Relative Cost of Operations  */
 
 /* Provide the costs of a rtl expression.  This is in the body of a
@@ -1912,7 +1944,7 @@ dtors_section ()                                                  \
          || ! TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL)         \
          || ! DECL_INITIAL (DECL)                                      \
          || (DECL_INITIAL (DECL) != error_mark_node                    \
-             && ! TREE_CONSTANT (DECL_INITIAL (DECL))))                        \
+             && ! TREE_CONSTANT (DECL_INITIAL (DECL))))                \
        data_section ();                                                \
       else                                                             \
        const_section ();                                               \
@@ -2440,8 +2472,6 @@ do { fprintf (asm_out_file, "\t.sdef\t");         \
 
 #define MACHINE_DEPENDENT_REORG(INSNS) c4x_process_after_reload(INSNS)
 
-#define MACHINE_DEPENDENT_COMBINE(INSNS) c4x_combine_parallel(INSNS)
-
 #define DBR_OUTPUT_SEQEND(FILE)                \
 if (final_sequence != NULL_RTX)                \
 {                                      \
@@ -2492,7 +2522,8 @@ if (final_sequence != NULL_RTX)           \
   {"any_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE}}, \
   {"par_ind_operand", {MEM}},                                  \
   {"parallel_operand", {SUBREG, REG, MEM}},                    \
-  {"mem_operand", {MEM}},                                      \
+  {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}},                \
+  {"mem_operand", {MEM}},                                      
 
 
 /* Variables in c4x.c */
@@ -2582,6 +2613,8 @@ extern int rc_reg_operand ();
 
 extern int st_reg_operand ();
 
+extern int symbolic_operand ();
+
 extern int ar0_reg_operand ();
 
 extern int ar0_mem_operand ();
@@ -2652,12 +2685,16 @@ extern int c4x_S_constraint ();
 
 extern int c4x_T_constraint ();
 
+extern int c4x_U_constraint ();
+
 extern void c4x_emit_libcall ();
 
 extern void c4x_emit_libcall3 ();
 
 extern void c4x_emit_libcall_mulhi ();
 
+extern int c4x_emit_move_sequence ();
+
 extern int legitimize_operands ();
 
 extern int valid_operands ();
index 7d858547a790871252086f5745b07da1891dd6ad..60bc43fd99f1f014f850731defcd0882bfec7a5b 100644 (file)
@@ -23,7 +23,6 @@
 
 ;
 ; TODO :
-;        Set up addressing macros to handle direct memory references properly.
 ;        Try using PQImode again for addresses since C30 only uses
 ;        24-bit addresses.   Ideally GCC would emit different insns
 ;        for QImode and Pmode, whether Pmode was QImode or PQImode.
@@ -66,7 +65,7 @@
 ; st_reg_operand        ST                                         [y]
 ; dp_reg_operand        DP                                         [z]
 ; stik_const_operand    5-bit const                                [K]
-; src_operand           general operand                            [rfmHI]
+; src_operand           general operand                            [rfHmI]
 ; par_ind_operand       indirect S mode (ARx + 0, 1, IRx)          [S<>]
 ; parallel_operand      par_ind_operand or ext_low_reg_operand
 
 ; Q   ARx + 9-bit signed disp
 ; R   ARx + 5-bit unsigned disp  (C4x only)
 ; S   ARx + 0, 1, IRx disp
-; T   symbol ref (direct)
+; T   direct memory operand
 ; V   non offsettable memory
 ; X   any operand
 ; <   memory operand with autodecrement addressing
 ; {   memory operand with pre-modify addressing
 ; }   memory operand with post-modify addressing
 
-;  Note that the d, f, and h constraints are equivalent.
-;  The m constraint is equivalent to QT<>{}
+;  Note that the 'd', 'f', and 'h' constraints are equivalent.
+;  The m constraint is equivalent to 'QT<>{}'
+
+;  Note we cannot use the 'g' constraint with Pmode (i.e, QImode)
+;  operations since LEGITIMATE_CONSTANT_P accepts SYMBOL_REF.
+;  So instead we use 'rIm' for signed operands or 'rLm' for unsigned operands.
 
 ;  Note that the constraints are used to select the operands
 ;  for a chosen pattern.  The constraint that requires the fewest
   "* return (TARGET_C3X) ? \"ldp\\t%A1\" : \"ldpk\\t%A1\";"
   [(set_attr "type" "ldp")])
 
-
-; Used when moving a constant label reference to an external
-; location, this will make sure the original label is still
-; used so the optimizer will not optimize it away.
-;
-(define_insn "set_ldp_use"
-  [(parallel [(set (match_operand:QI 0 "dp_reg_operand" "=z")
-                   (high:QI (match_operand:QI 1 "" "")))
-              (use (match_operand 2 "" ""))])]
-  "! TARGET_SMALL"
-  "* return (TARGET_C3X) ? \"ldp\\t%A1\" : \"ldpk\\t%A1\";"
-  [(set_attr "type" "ldp")])
-
-(define_insn "set_high_use"
-  [(parallel [(set (match_operand:QI 0 "std_reg_operand" "=c")
-                   (high:QI (match_operand:QI 1 "" "")))
-              (use (match_operand 2 "" ""))])]
-  "! TARGET_C3X && ! TARGET_SMALL"
+(define_insn "set_high"
+  [(set (match_operand:QI 0 "std_reg_operand" "=c")
+        (high:QI (match_operand:QI 1 "symbolic_operand" "")))]
+  "! TARGET_C3X "
   "ldhi\\t^%H1,%0"
   [(set_attr "type" "unary")])
 
-(define_insn "set_ior_lo_use"
-  [(parallel [(set (match_operand:QI 0 "std_reg_operand" "=c")
-                   (ior:QI (match_dup 0)
-                           (and:QI (match_operand:QI 1 "" "")
-                                   (const_int 65535))))
-              (use (match_operand 2 "" ""))])]
-  "! TARGET_C3X && ! TARGET_SMALL"
+(define_insn "set_lo_sum"
+  [(set (match_operand:QI 0 "std_reg_operand" "=c")
+        (lo_sum:QI (match_dup 0)
+                   (match_operand:QI 1 "symbolic_operand" "")))]
+  ""
   "or\\t#%H1,%0"
   [(set_attr "type" "unary")])
 
+(define_split
+  [(set (match_operand:QI 0 "std_reg_operand" "")
+        (match_operand:QI 1 "symbolic_operand" ""))]
+  "! TARGET_C3X"
+  [(set (match_dup 0) (high:QI (match_dup 1)))
+   (set (match_dup 0) (lo_sum:QI (match_dup 0) (match_dup 1)))]
+  "")
+
+; This pattern is required to handle the case where a register that clobbers
+; CC has been selected to load a symbolic address.  We force the address
+; into memory and then generate LDP and LDIU insns.
+; This is also required for the C30 if we pretend that we can 
+; easily load symbolic addresses into a register.
+(define_split
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (match_operand:QI 1 "symbolic_operand" ""))]
+  "! TARGET_SMALL 
+   && (TARGET_C3X || (reload_completed
+                      && ! std_reg_operand (operands[0], QImode)))"
+  [(set (match_dup 2) (high:QI (match_dup 3)))
+   (set (match_dup 0) (match_dup 4))
+   (use (match_dup 1))]
+  "
+{
+   rtx dp_reg = gen_rtx_REG (Pmode, DP_REGNO);
+   operands[2] = dp_reg;
+   operands[3] = force_const_mem (Pmode, operands[1]);
+   operands[4] = change_address (operands[3], QImode,
+                                gen_rtx_LO_SUM (Pmode, dp_reg,
+                                                 XEXP (operands[3], 0)));
+   operands[3] = XEXP (operands[3], 0);
+}")
+
+; This pattern is similar to the above but does not emit a LDP
+; for the small memory model.
+(define_split
+  [(set (match_operand:QI 0 "reg_operand" "")
+        (match_operand:QI 1 "symbolic_operand" ""))]
+  "TARGET_SMALL
+   && (TARGET_C3X || (reload_completed
+                      && ! std_reg_operand (operands[0], QImode)))"
+  [(set (match_dup 0) (match_dup 1))]
+  "
+{  
+   rtx dp_reg = gen_rtx_REG (Pmode, DP_REGNO);
+   operands[1] = force_const_mem (Pmode, operands[1]);
+   operands[1] = change_address (operands[1], QImode,
+                                gen_rtx_LO_SUM (Pmode, dp_reg,
+                                                 XEXP (operands[1], 0)));
+}")
+
+(define_insn "load_immed_address"
+  [(set (match_operand:QI 0 "reg_operand" "=a?x?c*r")
+        (match_operand:QI 1 "symbolic_operand" ""))]
+   "TARGET_LOAD_ADDRESS"
+  "#"
+  [(set_attr "type" "multi")])
+
 ;
 ; LDIU/LDA/STI/STIK
 ;
 ; spill a register.
 (define_insn "movqi_noclobber"
   [(set (match_operand:QI 0 "src_operand" "=d,*c,m,r")
-        (match_operand:QI 1 "src_hi_operand" "rmI,rmI,r,O"))]
-  "reg_operand (operands[0], QImode)
-   || reg_operand (operands[1], QImode)"
+        (match_operand:QI 1 "src_hi_operand" "rIm,rIm,r,O"))]
+  "(REG_P (operands[0]) || REG_P (operands[1])
+    || GET_CODE (operands[0]) == SUBREG
+    || GET_CODE (operands[1]) == SUBREG)
+    && ! symbolic_operand (operands[1], QImode)"
   "*
    if (which_alternative == 2)
      return \"sti\\t%1,%0\";
 ; We shouldn't need these peepholes, but the combiner seems to miss them...
 (define_peephole
   [(set (match_operand:QI 0 "ext_reg_operand" "=d")
-        (match_operand:QI 1 "src_operand" "g"))
+        (match_operand:QI 1 "src_operand" "rIm"))
    (set (reg:CC 21)
         (compare:CC (match_dup 0) (const_int 0)))]
   ""
 
 (define_insn "*movqi_set"
   [(set (reg:CC 21)
-        (compare:CC (match_operand:QI 1 "src_operand" "g") 
+        (compare:CC (match_operand:QI 1 "src_operand" "rIm") 
                     (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d")
         (match_dup 1))]
 ; when a simple compare with zero will suffice.
 ;(define_insn "*movqi_test"
 ; [(set (reg:CC 21)
-;       (compare:CC (match_operand:QI 1 "src_operand" "g") 
+;       (compare:CC (match_operand:QI 1 "src_operand" "rIm") 
 ;                   (const_int 0)))
 ;  (clobber (match_scratch:QI 0 "=d"))]
 ; ""
 ;  the compiler, have memoized the insn number already.
 
 (define_expand "movqi"
-  [(set (match_operand:QI 0 "src_operand" "")
-        (match_operand:QI 1 "src_operand" ""))]
+  [(set (match_operand:QI 0 "general_operand" "")
+        (match_operand:QI 1 "general_operand" ""))]
   ""
   "
-   /* We shouldn't have to do this, since reload is supposed to
-      be able to do this if we have a memory constraint.  */
-   if (CONSTANT_P (operands[1])
-       && ! const_operand (operands[1], QImode))
-     {
-        operands[1] = force_const_mem (QImode, operands[1]);
-        if (! memory_address_p (QImode, XEXP (operands[1], 0))
-            && ! reload_in_progress)
-          operands[1] = change_address (operands[1], QImode,
-                                        XEXP (operands[1], 0));
-     }
-
-   if (! reload_in_progress
-       && ! reg_operand (operands[0], QImode) 
-       && ! reg_operand (operands[1], QImode)
-       && ! (stik_const_operand (operands[1], QImode) 
-            && ! push_operand (operands[0], QImode)))
-     operands[1] = force_reg (QImode, operands[1]);")
+{
+  if (c4x_emit_move_sequence (operands, QImode))
+    DONE;
+}")
 
 (define_insn "*movqi_update"
   [(set (match_operand:QI 0 "reg_operand" "=r") 
 
 (define_insn "*absqi2_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,c")
-        (abs:QI (match_operand:QI 1 "src_operand" "g,g")))
+        (abs:QI (match_operand:QI 1 "src_operand" "rIm,rIm")))
    (clobber (reg:CC_NOOV 21))]
   ""
   "absi\\t%1,%0"
 
 (define_insn "*absqi2_test"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "g"))
+        (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "rIm"))
                          (const_int 0)))
    (clobber (match_scratch:QI 0 "=d"))]
   ""
 
 (define_insn "*absqi2_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "g"))
+        (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "rIm"))
                          (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d")
         (abs:QI (match_dup 1)))]
 
 (define_insn "*negqi2_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,c")
-        (neg:QI (match_operand:QI 1 "src_operand" "g,g")))
+        (neg:QI (match_operand:QI 1 "src_operand" "rIm,rIm")))
    (clobber (reg:CC_NOOV 21))]
   ""
   "negi\\t%1,%0"
 
 (define_insn "*negqi2_test"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "g"))
+        (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "rIm"))
                          (const_int 0)))
    (clobber (match_scratch:QI 0 "=d"))]
   ""
 
 (define_insn "*negqi2_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "g"))
+        (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "rIm"))
                          (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d")
         (neg:QI (match_dup 1)))]
 
 (define_insn "*negbqi2_clobber"
   [(set (match_operand:QI 0 "ext_reg_operand" "=d")
-        (neg:QI (match_operand:QI 1 "src_operand" "g")))
+        (neg:QI (match_operand:QI 1 "src_operand" "rIm")))
    (use (reg:CC_NOOV 21))
    (clobber (reg:CC_NOOV 21))]
   ""
 
 (define_insn "*one_cmplqi2_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,c")
-        (not:QI (match_operand:QI 1 "lsrc_operand" "g,g")))
+        (not:QI (match_operand:QI 1 "lsrc_operand" "rLm,rLm")))
    (clobber (reg:CC 21))]
   ""
   "not\\t%1,%0"
 
 (define_insn "*one_cmplqi2_test"
   [(set (reg:CC 21)
-        (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "g"))
+        (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "rLm"))
                     (const_int 0)))
    (clobber (match_scratch:QI 0 "=d"))]
   ""
 
 (define_insn "*one_cmplqi2_set"
   [(set (reg:CC 21)
-        (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "g"))
+        (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "rLm"))
                     (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d")        
         (not:QI (match_dup 1)))]
 (define_insn "*addqi3_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
         (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
-                 (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (PLUS, operands, QImode)"
   "@
 (define_insn "*addqi3_test"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
-                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,rIm"))
                          (const_int 0)))
    (clobber (match_scratch:QI 0 "=d,?d,d"))]
   "valid_operands (PLUS, operands, QImode)"
 (define_insn "*addqi3_set"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
-                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,rIm"))
                          (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
         (plus:QI (match_dup 1) (match_dup 2)))]
 (define_insn "addqi3_noclobber"
   [(set (match_operand:QI 0 "std_reg_operand" "=c,?c,c")
         (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
-                 (match_operand:QI 2 "src_operand" "JR,rS<>,g")))]
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,rIm")))]
   "valid_operands (PLUS, operands, QImode)"
   "@
    addi3\\t%2,%1,%0
 (define_insn "*addqi3_noclobber_reload"
   [(set (match_operand:QI 0 "general_operand" "=c,?c,c")
         (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
-                 (match_operand:QI 2 "src_operand" "JR,rS<>,g")))]
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,rIm")))]
   "reload_in_progress"
   "@
    addi3\\t%2,%1,%0
 (define_insn "*addqi3_carry_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
         (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
-                 (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")))
    (use (reg:CC_NOOV 21))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (PLUS, operands, QImode)"
 
 (define_insn "*subqi3_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c")
-        (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g,rR,rS<>,0,g")
-                  (match_operand:QI 2 "src_operand" "JR,rS<>,g,0,JR,rS<>,g,0")))
+        (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rIm,rR,rS<>,0,rIm")
+                  (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,0,JR,rS<>,rIm,0")))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (MINUS, operands, QImode)"
   "@
 
 (define_insn "*subqi3_test"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
-                                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))
+        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rIm")
+                                   (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,0"))
                          (const_int 0)))
    (clobber (match_scratch:QI 0 "=d,?d,d,d"))]
   "valid_operands (MINUS, operands, QImode)"
 
 (define_peephole
   [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
-                   (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
-                             (match_operand:QI 2 "src_operand" "JR,rS<>,g,0")))
+                   (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rIm")
+                             (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,0")))
               (clobber (reg:CC_NOOV 21))])
    (set (reg:CC_NOOV 21)
         (compare:CC_NOOV (match_dup 0) (const_int 0)))]
   
 (define_insn "*subqi3_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
-                                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))
+        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rIm")
+                                   (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,0"))
                          (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
         (minus:QI (match_dup 1)
 
 (define_insn "*subqi3_carry_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c")
-        (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g,rR,rS<>,0,g")
-                  (match_operand:QI 2 "src_operand" "JR,rS<>,g,0,JR,rS<>,g,0")))
+        (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rIm,rR,rS<>,0,rIm")
+                  (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,0,JR,rS<>,rIm,0")))
    (use (reg:CC_NOOV 21))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (MINUS, operands, QImode)"
 
 (define_insn "*subqi3_carry_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g")
-                                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))
+        (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rIm")
+                                   (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,0"))
                          (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d")
         (minus:QI (match_dup 1)
 (define_insn "*mulqi3_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
         (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
-                 (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+                 (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (MULT, operands, QImode)"
   "*
 (define_insn "*mulqi3_test"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
-                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,rIm"))
                          (const_int 0)))
    (clobber (match_scratch:QI 0 "=d,?d,d"))]
   "valid_operands (MULT, operands, QImode)"
 (define_insn "*mulqi3_set"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0")
-                                  (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                                  (match_operand:QI 2 "src_operand" "JR,rS<>,rIm"))
                          (const_int 0)))
    (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d")
         (mult:QI (match_dup 1)
           (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")
                   (const_int 16777215)))
          (sign_extend:QI
-          (and:QI (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")
+          (and:QI (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")
                   (const_int 16777215)))))
    (clobber (reg:CC_NOOV 21))]
   "TARGET_C3X && valid_operands (MULT, operands, QImode)"
          (lshiftrt:HI
           (mult:HI
            (sign_extend:HI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0"))
-           (sign_extend:HI (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+           (sign_extend:HI (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")))
       (const_int 32))))
    (clobber (reg:CC_NOOV 21))]
   "! TARGET_C3X && valid_operands (MULT, operands, QImode)"
          (lshiftrt:HI
           (mult:HI 
            (zero_extend:HI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0"))
-           (zero_extend:HI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,g,JR,rS<>,g")))
+           (zero_extend:HI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm")))
           (const_int 32))))
    (clobber (reg:CC_NOOV 21))]
   "! TARGET_C3X && valid_operands (MULT, operands, QImode)"
 (define_insn "*ashlqi3_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
         (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
-                   (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")))
+                   (match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")))
    (clobber (reg:CC 21))]
   "valid_operands (ASHIFT, operands, QImode)"
   "@
   [(set (reg:CC 21)
         (compare:CC
           (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0")
-                     (match_operand:QI 2 "src_operand" "JR,rS<>,g"))
+                     (match_operand:QI 2 "src_operand" "JR,rS<>,rIm"))
           (const_int 0)))
    (set (match_operand:QI 0 "reg_operand" "=d,?d,d")
         (ashift:QI (match_dup 1)
 (define_insn "*lshlqi3_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c")
         (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0")
-                   (unspec [(match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")] 3)))
+                   (unspec [(match_operand:QI 2 "src_operand" "JR,rS<>,rIm,JR,rS<>,rIm")] 3)))
    (clobber (reg:CC 21))]
   "valid_operands (ASHIFT, operands, QImode)"
   "@
 (define_insn "*cmpqi_test"
   [(set (reg:CC 21)
         (compare:CC (match_operand:QI 0 "src_operand" "rR,?rS<>,r")
-                    (match_operand:QI 1 "src_operand" "JR,rS<>,g")))]
+                    (match_operand:QI 1 "src_operand" "JR,rS<>,rIm")))]
   "valid_operands (COMPARE, operands, QImode)"
   "@
    cmpi3\\t%1,%0
 (define_insn "*cmpqi_test_noov"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (match_operand:QI 0 "src_operand" "rR,?rS<>,r")
-                         (match_operand:QI 1 "src_operand" "JR,rS<>,g")))]
+                         (match_operand:QI 1 "src_operand" "JR,rS<>,rIm")))]
   "valid_operands (COMPARE, operands, QImode)"
   "@
    cmpi3\\t%1,%0
 
 (define_insn "*extv_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,c")
-        (sign_extract:QI (match_operand:QI 1 "src_operand" "g,g")
+        (sign_extract:QI (match_operand:QI 1 "src_operand" "rLm,rLm")
                          (match_operand:QI 2 "const_int_operand" "n,n")
                          (match_operand:QI 3 "const_int_operand" "n,n")))
    (clobber (reg:CC 21))]
 
 (define_insn "*extv_clobber_test"
   [(set (reg:CC 21)
-        (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "g")
+        (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "rLm")
                                      (match_operand:QI 2 "const_int_operand" "n")
                                      (match_operand:QI 3 "const_int_operand" "n"))
                    (const_int 0)))
 
 (define_insn "*extv_clobber_set"
   [(set (reg:CC 21)
-        (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "g")
+        (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "rLm")
                                      (match_operand:QI 2 "const_int_operand" "n")
                                      (match_operand:QI 3 "const_int_operand" "n"))
                    (const_int 0)))
 
 (define_insn "*extzv_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,c")
-        (zero_extract:QI (match_operand:QI 1 "src_operand" "g,g")
+        (zero_extract:QI (match_operand:QI 1 "src_operand" "rLm,rLm")
                          (match_operand:QI 2 "const_int_operand" "n,n")
                          (match_operand:QI 3 "const_int_operand" "n,n")))
    (clobber (reg:CC 21))]
 
 (define_insn "*extzv_test"
   [(set (reg:CC 21)
-        (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "g")
+        (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "rLm")
                                      (match_operand:QI 2 "const_int_operand" "n")
                                      (match_operand:QI 3 "const_int_operand" "n"))
                    (const_int 0)))
 
 (define_insn "*extzv_set"
   [(set (reg:CC 21)
-        (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "g")
+        (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "rLm")
                                      (match_operand:QI 2 "const_int_operand" "n")
                                      (match_operand:QI 3 "const_int_operand" "n"))
                    (const_int 0)))
-   (set (match_operand:QI 0 "reg_operand" "=d")
+   (set (match_operand:QI 0 "ext_reg_operand" "=d")
         (zero_extract:QI (match_dup 1)
                          (match_dup 2)
                          (match_dup 3)))]
   [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "=d,c")
                          (match_operand:QI 1 "const_int_operand" "n,n")
                          (match_operand:QI 2 "const_int_operand" "n,n"))
-        (match_operand:QI 3 "src_operand" "g,g"))
+        (match_operand:QI 3 "src_operand" "rLm,rLm"))
    (clobber (reg:CC 21))]
   "! TARGET_C3X
    && (((INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
    (set_attr "data" "uint16,uint16")])
 
 (define_peephole
-  [(parallel [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "=d")
+  [(parallel [(set (zero_extract:QI (match_operand:QI 0 "ext_reg_operand" "=d")
                                     (match_operand:QI 1 "const_int_operand" "n")
                                     (match_operand:QI 2 "const_int_operand" "n"))
-                   (match_operand:QI 3 "src_operand" "g"))
+                   (match_operand:QI 3 "src_operand" "rLm"))
              (clobber (reg:CC 21))])
    (set (reg:CC 21)
         (compare:CC (match_dup 0) (const_int 0)))]
         (match_operand:QF 1 "src_operand" ""))]
  ""
  "
-  if (CONSTANT_P (operands[1]) && ! const_operand (operands[1], QFmode))
-    {
-      operands[1] = force_const_mem (QFmode, operands[1]);
-      if (! memory_address_p (QFmode, XEXP (operands[1], 0))
-          && ! reload_in_progress)
-        operands[1] = change_address (operands[1], QFmode,
-                                      XEXP (operands[1], 0));
-    }
-
-  if (! reload_in_progress
-      && ! reg_operand (operands[0], QFmode)
-      && ! reg_operand (operands[1], QFmode))
-    operands[1] = force_reg (QFmode, operands[1]);
- ")
+{
+  if (c4x_emit_move_sequence (operands, QFmode))
+    DONE;
+}")
 
 ; We must provide an alternative to store to memory in case we have to
 ; spill a register.
-(define_insn "*movqf_noclobber"
+(define_insn "movqf_noclobber"
  [(set (match_operand:QF 0 "src_operand" "=f,m")
-       (match_operand:QF 1 "src_operand" "fmH,f"))]
- "reg_operand (operands[0], QFmode)
-  || reg_operand (operands[1], QFmode)"
+       (match_operand:QF 1 "src_operand" "fHm,f"))]
+ "REG_P (operands[0]) || REG_P (operands[1])"
  "@
   ldfu\\t%1,%0
   stf\\t%1,%0"
 
 ;(define_insn "*movqf_clobber"
 ;  [(set (match_operand:QF 0 "reg_operand" "=f")
-;        (match_operand:QF 1 "src_operand" "fmH"))
+;        (match_operand:QF 1 "src_operand" "fHm"))
 ;   (clobber (reg:CC 21))]
 ; "0"
 ; "ldf\\t%1,%0"
 
 (define_insn "*movqf_test"
   [(set (reg:CC 21)
-        (compare:CC (match_operand:QF 1 "src_operand" "fmH")
+        (compare:CC (match_operand:QF 1 "src_operand" "fHm")
                     (const_int 0)))
    (clobber (match_scratch:QF 0 "=f"))]
  ""
 
 (define_insn "*movqf_set"
   [(set (reg:CC 21)
-        (compare:CC (match_operand:QF 1 "src_operand" "fmH")
+        (compare:CC (match_operand:QF 1 "src_operand" "fHm")
                     (match_operand:QF 2 "fp_zero_operand" "G")))
     (set (match_operand:QF 0 "reg_operand" "=f")
          (match_dup 1))]
 
 (define_insn "*absqf2_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f")
-        (abs:QF (match_operand:QF 1 "src_operand" "fmH")))
+        (abs:QF (match_operand:QF 1 "src_operand" "fHm")))
    (clobber (reg:CC_NOOV 21))]
   ""
   "absf\\t%1,%0"
 
 (define_insn "*absqf2_test"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fmH"))
+        (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fHm"))
                          (match_operand:QF 2 "fp_zero_operand" "G")))
    (clobber (match_scratch:QF 0 "=f"))]
   ""
 
 (define_insn "*absqf2_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fmH"))
+        (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fHm"))
                          (match_operand:QF 2 "fp_zero_operand" "G")))
    (set (match_operand:QF 0 "reg_operand" "=f")
         (abs:QF (match_dup 1)))]
 
 (define_insn "*negqf2_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f")
-        (neg:QF (match_operand:QF 1 "src_operand" "fmH")))
+        (neg:QF (match_operand:QF 1 "src_operand" "fHm")))
    (clobber (reg:CC_NOOV 21))]
   ""
   "negf\\t%1,%0"
 
 (define_insn "*negqf2_test"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fmH"))
+        (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fHm"))
                          (match_operand:QF 2 "fp_zero_operand" "G")))
    (clobber (match_scratch:QF 0 "=f"))]
   ""
 
 (define_insn "*negqf2_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fmH"))
+        (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fHm"))
                          (match_operand:QF 2 "fp_zero_operand" "G")))
    (set (match_operand:QF 0 "reg_operand" "=f")
         (neg:QF (match_dup 1)))]
 ;
 (define_insn "floatqiqf2"
   [(set (match_operand:QF 0 "reg_operand" "=f")
-        (float:QF (match_operand:QI 1 "src_operand" "g")))
+        (float:QF (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
  ""
  "float\\t%1,%0"
 
 (define_insn "*floatqiqf2_set"
   [(set (reg:CC 21)
-        (compare:CC (float:QF (match_operand:QI 1 "src_operand" "g"))
+        (compare:CC (float:QF (match_operand:QI 1 "src_operand" "rIm"))
                     (match_operand:QF 2 "fp_zero_operand" "G")))
    (set (match_operand:QF 0 "reg_operand" "=f")
         (float:QF (match_dup 1)))]
-
  ""
  "float\\t%1,%0"
   [(set_attr "type" "unarycc")])
 
 ; Unsigned conversions are a little tricky because we need to
 ; add the value for the high bit if necessary.
+; 
 ;
 (define_expand "floatunsqiqf2"
  [(set (match_dup 2) (match_dup 3))
                               (match_dup 3)))
              (set (match_dup 4)
                   (float:QF (match_dup 1)))])
-  (set (match_dup 2)
+  (set (match_dup 6)
        (if_then_else:QF (lt (reg:CC 21) (const_int 0))
-                        (mem:QF (symbol_ref:QF "*___unsfltconst"))
+                        (match_dup 5)
                         (match_dup 2)))
   (parallel [(set (match_operand:QF 0 "reg_operand" "")
-                  (plus:QF (match_dup 2) (match_dup 4)))
+                  (plus:QF (match_dup 6) (match_dup 4)))
              (clobber (reg:CC_NOOV 21))])]
  ""
  "operands[2] = gen_reg_rtx (QFmode);
   operands[3] = CONST0_RTX (QFmode); 
   operands[4] = gen_reg_rtx (QFmode);
- ")
+  operands[5] = gen_reg_rtx (QFmode);
+  operands[6] = gen_reg_rtx (QFmode);
+  emit_move_insn (operands[5], 
+   immed_real_const_1 (REAL_VALUE_ATOF (\"4294967296.0\", QFmode), QFmode));")
 
 (define_insn "floatqihf2"
   [(set (match_operand:HF 0 "reg_operand" "=h")
-        (float:HF (match_operand:QI 1 "src_operand" "g")))
+        (float:HF (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
  ""
  "float\\t%1,%0"
 ;
 (define_insn "fixqfqi_clobber"
   [(set (match_operand:QI 0 "reg_operand" "=d,c")
-        (fix:QI (match_operand:QF 1 "src_operand" "fmH,fmH")))
+        (fix:QI (match_operand:QF 1 "src_operand" "fHm,fHm")))
    (clobber (reg:CC 21))]
  ""
  "fix\\t%1,%0"
 
 (define_insn "*fixqfqi_set"
   [(set (reg:CC 21)
-        (compare:CC (fix:QI (match_operand:QF 1 "src_operand" "fmH"))
+        (compare:CC (fix:QI (match_operand:QF 1 "src_operand" "fHm"))
                     (const_int 0)))
-   (set (match_operand:QI 0 "reg_operand" "=d")
+   (set (match_operand:QI 0 "ext_reg_operand" "=d")
         (fix:QI (match_dup 1)))]
  ""
  "fix\\t%1,%0"
   "c4x_emit_libcall (FIX_TRUNCQFHI2_LIBCALL, FIX, HImode, QFmode, 2, operands);
    DONE;")
 
+; Is this allowed to be implementation dependent?  If so, we can
+; omit the conditional load.  Otherwise we should emit a split.
 (define_expand "fixuns_truncqfqi2"
- [(set (match_dup 2) (match_dup 4))
-  (set (reg:CC 21)
-       (compare:CC (match_operand:QF 1 "reg_operand" "")
-                   (mem:QF (symbol_ref "*___unsfltcompare"))))
-  (set (match_dup 2)
-       (if_then_else:QF (ge (reg:CC 21) (const_int 0))
-                        (mem:QF (symbol_ref "*___unsfltconst"))
-                        (match_dup 2)))
-  (parallel [(set (match_dup 3)
-                  (minus:QF (match_dup 1) (match_dup 2)))
-             (clobber (reg:CC_NOOV 21))])
-  (parallel [(set (match_operand:QI 0 "reg_operand" "")
-                  (fix:QI (match_dup 3)))
-             (clobber (reg:CC 21))])]
+ [(parallel [(set (reg:CC 21)
+                  (compare:CC (fix:QI (match_operand:QF 1 "src_operand" "fHm"))
+                              (const_int 0)))
+             (set (match_dup 2)
+                  (fix:QI (match_dup 1)))])
+  (set (match_operand:QI 0 "reg_operand" "=r")
+       (if_then_else:QI (lt (reg:CC 21) (const_int 0))
+                        (const_int 0)
+                        (match_dup 2)))]
  ""
- "operands[2] = gen_reg_rtx (QFmode);
-  operands[3] = gen_reg_rtx (QFmode);
-  operands[4] = CONST0_RTX (QFmode);
- ")
+ "operands[2] = gen_reg_rtx (QImode);")
 
 (define_expand "fixuns_truncqfhi2"
   [(parallel [(set (match_operand:HI 0 "reg_operand" "")
 ;
 (define_insn "*rcpfqf_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f")
-        (unspec [(match_operand:QF 1 "src_operand" "fmH")] 5))
+        (unspec [(match_operand:QF 1 "src_operand" "fHm")] 5))
    (clobber (reg:CC_NOOV 21))]
   "! TARGET_C3X"
   "rcpf\\t%1,%0"
 ;
 (define_insn "*rsqrfqf_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f")
-        (unspec [(match_operand:QF 1 "src_operand" "fmH")] 10))
+        (unspec [(match_operand:QF 1 "src_operand" "fHm")] 10))
    (clobber (reg:CC_NOOV 21))]
   "! TARGET_C3X"
   "rsqrf\\t%1,%0"
 ;
 (define_insn "*rndqf_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f")
-        (unspec [(match_operand:QF 1 "src_operand" "fmH")] 6))
+        (unspec [(match_operand:QF 1 "src_operand" "fHm")] 6))
    (clobber (reg:CC_NOOV 21))]
   "! TARGET_C3X"
   "rnd\\t%1,%0"
 (define_insn "*addqf3_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f,?f,f")
         (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
-                 (match_operand:QF 2 "src_operand" "R,fS<>,fmH")))
+                 (match_operand:QF 2 "src_operand" "R,fS<>,fHm")))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (PLUS, operands, QFmode)"
   "@
 (define_insn "*addqf3_test"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
-                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fHm"))
                          (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
    (clobber (match_scratch:QF 0 "=f,?f,f"))]
   "valid_operands (PLUS, operands, QFmode)"
 (define_insn "*addqf3_set"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
-                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fHm"))
                          (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
    (set (match_operand:QF 0 "reg_operand" "=f,?f,f")
         (plus:QF (match_dup 1)
 
 (define_insn "*subqf3_clobber"
    [(set (match_operand:QF 0 "reg_operand" "=f,?f,f,f")
-         (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH")
-                   (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0")))
+         (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fHm")
+                   (match_operand:QF 2 "src_operand" "R,fS<>,fHm,0")))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (MINUS, operands, QFmode)"
   "@
 
 (define_insn "*subqf3_test"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH")
-                                   (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0"))
+        (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fHm")
+                                   (match_operand:QF 2 "src_operand" "R,fS<>,fHm,0"))
                          (match_operand:QF 3 "fp_zero_operand" "G,G,G,G")))
    (clobber (match_scratch:QF 0 "=f,?f,f,f"))]
   "valid_operands (MINUS, operands, QFmode)"
 
 (define_insn "*subqf3_set"
   [(set (reg:CC_NOOV 21)
-        (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH")
-                                   (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0"))
+        (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fHm")
+                                   (match_operand:QF 2 "src_operand" "R,fS<>,fHm,0"))
                          (match_operand:QF 3 "fp_zero_operand" "G,G,G,G")))
    (set (match_operand:QF 0 "reg_operand" "=f,?f,f,f")
         (minus:QF (match_dup 1)
 (define_insn "*mulqf3_clobber"
   [(set (match_operand:QF 0 "reg_operand" "=f,?f,f")
         (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
-                 (match_operand:QF 2 "src_operand" "R,fS<>,fmH")))
+                 (match_operand:QF 2 "src_operand" "R,fS<>,fHm")))
    (clobber (reg:CC_NOOV 21))]
   "valid_operands (MULT, operands, QFmode)"
   "@
 (define_insn "*mulqf3_test"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
-                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fHm"))
                          (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
    (clobber (match_scratch:QF 0 "=f,?f,f"))]
   "valid_operands (MULT, operands, QFmode)"
 (define_insn "*mulqf3_set"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0")
-                                  (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))
+                                  (match_operand:QF 2 "src_operand" "R,fS<>,fHm"))
                          (match_operand:QF 3 "fp_zero_operand" "G,G,G")))
    (set (match_operand:QF 0 "reg_operand" "=f,?f,f")
         (mult:QF (match_dup 1)
 (define_insn "*cmpqf"
   [(set (reg:CC 21)
         (compare:CC (match_operand:QF 0 "src_operand" "fR,?fS<>,f")
-                    (match_operand:QF 1 "src_operand" "R,fS<>,fmH")))]
+                    (match_operand:QF 1 "src_operand" "R,fS<>,fHm")))]
   "valid_operands (COMPARE, operands, QFmode)"
   "@
    cmpf3\\t%1,%0
 (define_insn "*cmpqf_noov"
   [(set (reg:CC_NOOV 21)
         (compare:CC_NOOV (match_operand:QF 0 "src_operand" "fR,?fS<>,f")
-                         (match_operand:QF 1 "src_operand" "R,fS<>,fmH")))]
+                         (match_operand:QF 1 "src_operand" "R,fS<>,fHm")))]
   "valid_operands (COMPARE, operands, QFmode)"
   "@
    cmpf3\\t%1,%0
   [(set (match_operand:QI 0 "reg_operand" "=r,r")
         (if_then_else:QI (match_operator 1 "comparison_operator"
                           [(reg:CC 21) (const_int 0)])
-                         (match_operand:QI 2 "src_operand" "g,0")
-                         (match_operand:QI 3 "src_operand" "0,g")))]
+                         (match_operand:QI 2 "src_operand" "rIm,0")
+                         (match_operand:QI 3 "src_operand" "0,rIm")))]
  ""
  "@
   ldi%1\\t%2,%0
   [(set (match_operand:QI 0 "reg_operand" "=r,r")
         (if_then_else:QI (match_operator 1 "comparison_operator"
                           [(reg:CC_NOOV 21) (const_int 0)])
-                         (match_operand:QI 2 "src_operand" "g,0")
-                         (match_operand:QI 3 "src_operand" "0,g")))]
+                         (match_operand:QI 2 "src_operand" "rIm,0")
+                         (match_operand:QI 3 "src_operand" "0,rIm")))]
  "GET_CODE (operands[1]) != LE
   && GET_CODE (operands[1]) != GE
   && GET_CODE (operands[1]) != LT
   [(set (match_operand:QF 0 "reg_operand" "=f,f")
         (if_then_else:QF (match_operator 1 "comparison_operator"
                           [(reg:CC 21) (const_int 0)])
-                         (match_operand:QF 2 "src_operand" "fmH,0")
-                         (match_operand:QF 3 "src_operand" "0,fmH")))]
+                         (match_operand:QF 2 "src_operand" "fHm,0")
+                         (match_operand:QF 3 "src_operand" "0,fHm")))]
  ""
  "@
   ldf%1\\t%2,%0
   [(set (match_operand:QF 0 "reg_operand" "=f,f")
         (if_then_else:QF (match_operator 1 "comparison_operator"
                           [(reg:CC_NOOV 21) (const_int 0)])
-                         (match_operand:QF 2 "src_operand" "fmH,0")
-                         (match_operand:QF 3 "src_operand" "0,fmH")))]
+                         (match_operand:QF 2 "src_operand" "fHm,0")
+                         (match_operand:QF 3 "src_operand" "0,fHm")))]
  "GET_CODE (operands[1]) != LE
   && GET_CODE (operands[1]) != GE
   && GET_CODE (operands[1]) != LT
 ; CALL
 ;
 (define_insn "*call_c3x"
- [(call (match_operand:QI 0 "call_operand" "T,!o")
+ [(call (mem:QI (match_operand:QI 0 "call_operand" ""))
         (match_operand:QI 1 "general_operand" ""))
   (clobber (reg:QI 31))]
   ;; Operand 1 not really used on the C4x.  The C30 doesn't have reg 31.
 
   "TARGET_C3X"
-  "@
-   call\\t%C0
-   callu\\t%R0"
-  [(set_attr "type" "call,call")])
+  "call%U0\\t%C0"
+  [(set_attr "type" "call")])
 
 ; LAJ requires R11 (31) for the return address
 (define_insn "*laj"
- [(call (match_operand:QI 0 "call_operand" "T,!o")
+ [(call (mem:QI (match_operand:QI 0 "call_operand" ""))
         (match_operand:QI 1 "general_operand" ""))
   (clobber (reg:QI 31))]
   ;; Operand 1 not really used on the C4x.
 
   "! TARGET_C3X"
   "*
-   if (which_alternative == 0)
-     {
-       if (final_sequence)
-         return \"laj\\t%C0\";
-       else
-         return \"call\\t%C0\";
-     }
+   if (final_sequence)
+     return \"laj%U0\\t%C0\";
    else
-     {
-       if (final_sequence)
-         return \"laju\\t%R0\";
-       else
-         return \"callu\\t%R0\";
-     }"
-  [(set_attr "type" "laj,laj")])
+     return \"call%U0\\t%C0\";"
+  [(set_attr "type" "laj")])
 
 (define_expand "call"
- [(parallel [(call (match_operand:QI 0 "call_operand" "")
+ [(parallel [(call (mem:QI (match_operand:QI 0 "call_operand" ""))
                    (match_operand:QI 1 "general_operand" ""))
              (clobber (reg:QI 31))])]
  ""
  "")
 
 (define_insn "*callv_c3x"
- [(set (match_operand 0 "" "=r,r")
-       (call (match_operand:QI 1 "call_operand" "T,!o")
+ [(set (match_operand 0 "" "=r")
+       (call (mem:QI (match_operand:QI 1 "call_operand" ""))
              (match_operand:QI 2 "general_operand" "")))
   (clobber (reg:QI 31))]
   ;; Operand 0 and 2 not really used for the C4x. 
   ;; The C30 doesn't have reg 31.
 
   "TARGET_C3X"
-  "@
-   call\\t%C1
-   callu\\t%R1"
-  [(set_attr "type" "call,call")])
+  "call%U1\\t%C1"
+  [(set_attr "type" "call")])
 
 ; LAJ requires R11 (31) for the return address
 (define_insn "*lajv"
- [(set (match_operand 0 "" "=r,r")
-       (call (match_operand:QI 1 "call_operand" "T,!o")
+ [(set (match_operand 0 "" "=r")
+       (call (mem:QI (match_operand:QI 1 "call_operand" ""))
              (match_operand:QI 2 "general_operand" "")))
   (clobber (reg:QI 31))]
   ;; Operand 0 and 2 not really used in the C30 instruction.
 
   "! TARGET_C3X"
   "*
-   if (which_alternative == 0)
-     {
-       if (final_sequence)
-         return \"laj\\t%C1\";
-       else
-         return \"call\\t%C1\";
-     }
+   if (final_sequence)
+     return \"laj%U1\\t%C1\";
    else
-     {
-       if (final_sequence)
-         return \"laju\\t%R1\";
-       else
-         return \"callu\\t%R1\";
-     }"
-  [(set_attr "type" "laj,laj")])
+     return \"call%U1\\t%C1\";"
+  [(set_attr "type" "laj")])
 
 (define_expand "call_value"
  [(parallel [(set (match_operand 0 "" "")
-                  (call (match_operand:QI 1 "call_operand" "")
+                  (call (mem:QI (match_operand:QI 1 "call_operand" ""))
                         (match_operand:QI 2 "general_operand" "")))
              (clobber (reg:QI 31))])]
  ""
 
 
 (define_insn "*cmpstrqi"
-  [(set (match_operand:QI 0 "reg_operand" "=d")
+  [(set (match_operand:QI 0 "ext_reg_operand" "=d")
         (compare:QI (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a"))
                     (mem:BLK (match_operand:QI 2 "addr_reg_operand" "a"))))
    (use (match_operand:QI 3 "immediate_operand" "i"))
   [(set (match_operand:HF 0 "src_operand" "")
         (match_operand:HF 1 "src_operand" ""))]
  ""
- "if (CONSTANT_P (operands[1]))
-    {
-      operands[1] = force_const_mem (HFmode, operands[1]); 
-      if (! memory_address_p (HFmode, XEXP (operands[1], 0))
-          && ! reload_in_progress)
-        operands[1] = change_address (operands[1], HFmode,
-                                      XEXP (operands[1], 0));
-     }
-
-  /* Memory to memory copies must go through a register.  */
-  if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[0]) == MEM
-      && ! reload_in_progress)
-    operands[1] = force_reg (HFmode, operands[1]); 
-")
+ "if (c4x_emit_move_sequence (operands, HFmode))
+    DONE;")
 
 (define_insn "*movhf_noclobber_reg"
   [(set (match_operand:HF 0 "reg_operand" "=h")
-        (match_operand:HF 1 "reg_operand" "h"))]
- ""
+        (match_operand:HF 1 "src_operand" "Hh"))]
+ "GET_CODE (operands[1]) != MEM"
  "ldfu\\t%1,%0"
   [(set_attr "type" "unary")])
 
 ; The predicates could be tightened to disallow constants
 (define_insn "*movhf_noclobber"
  [(set (match_operand:HF 0 "src_operand" "=h,m")
-       (match_operand:HF 1 "src_operand" "m,h"))]
+       (match_operand:HF 1 "src_operand" "HQT>,h"))]
  "reg_operand (operands[0], HFmode) ^ reg_operand (operands[1], HFmode)"
  "#"
  [(set_attr "type" "multi,multi")])
 
 (define_insn "*loadhf_float"
  [(set (match_operand:HF 0 "reg_operand" "=h")
-       (float_extend:HF (match_operand:QF 1 "src_operand" "fmH")))]
+       (float_extend:HF (match_operand:QF 1 "src_operand" "fHm")))]
  ""
  "@
   ldfu\\t%1,%0"
 (define_insn "*loadhf_int"
  [(set (match_operand:HF 0 "reg_operand" "=h")
        (unspec[(subreg:QI (match_dup 0) 0)
-               (match_operand:QI 1 "src_operand" "g")] 8))]
+               (match_operand:QI 1 "src_operand" "rIm")] 8))]
  ""
  "@
   ldiu\\t%1,%0"
   [(set (match_operand:HI 0 "src_operand" "")
         (match_operand:HI 1 "src_operand" ""))]
  ""
- "if (CONSTANT_P (operands[1]))
-    {
-      /* We don't need to force all constants into memory.
-         This could be improved.... */
-      operands[1] = force_const_mem (HImode, operands[1]); 
-      if (! memory_address_p (HImode, XEXP (operands[1], 0))
-          && ! reload_in_progress)
-        operands[1] = change_address (operands[1], HImode,
-                                      XEXP (operands[1], 0));
-     }
-
-  /* Memory to memory copies must go through a register.  */
-  if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[0]) == MEM
-      && ! reload_in_progress)
-    operands[1] = force_reg (HImode, operands[1]); 
-")
+ "if (c4x_emit_move_sequence (operands, HImode))
+    DONE;")
 
 ; The constraints for movhi must include 'r' if we don't
 ; restrict HImode regnos to start on an even number, since
 ; votes for FP_REGS so we use dr as the constraints.
 (define_insn "*movhi_noclobber"
   [(set (match_operand:HI 0 "src_operand" "=dr,m")
-        (match_operand:HI 1 "src_operand" "drm,r"))]
+        (match_operand:HI 1 "src_operand" "drIQT>,r"))]
   "reg_operand (operands[0], HImode)
    || reg_operand (operands[1], HImode)"
   "#"
 
 (define_insn "extendqihi2"
   [(set (match_operand:HI 0 "reg_operand" "=dc")
-        (sign_extend:HI (match_operand:QI 1 "src_operand" "g")))
+        (sign_extend:HI (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
   ""
   "#"
 
 (define_split
   [(set (match_operand:HI 0 "reg_operand" "=?dc")
-        (sign_extend:HI (match_operand:QI 1 "src_operand" "g")))
+        (sign_extend:HI (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
   "reload_completed && TARGET_C3X"
   [(set (match_dup 2) (match_dup 1))
 
 (define_split
   [(set (match_operand:HI 0 "reg_operand" "=?dc")
-        (sign_extend:HI (match_operand:QI 1 "src_operand" "g")))
+        (sign_extend:HI (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
   "reload_completed && ! TARGET_C3X"
   [(set (match_dup 2) (match_dup 1))
 
 (define_insn "zero_extendqihi2"
   [(set (match_operand:HI 0 "reg_operand" "=?dc")
-        (zero_extend:HI (match_operand:QI 1 "src_operand" "g")))
+        (zero_extend:HI (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
   ""
   "#"
 ; the first set.
 (define_split
   [(set (match_operand:HI 0 "reg_operand" "=?dc")
-        (zero_extend:HI (match_operand:QI 1 "src_operand" "g")))
+        (zero_extend:HI (match_operand:QI 1 "src_operand" "rIm")))
    (clobber (reg:CC 21))]
   "reload_completed"
   [(set (match_dup 2) (match_dup 1))
    (parallel
     [(set (pc)
           (if_then_else
-            (ge (plus:QI (match_operand:QI 4 "addr_reg_operand" "0")
+            (ge (plus:QI (match_operand:QI 0 "addr_reg_operand" "+a")
                          (const_int -1))
                 (const_int 0))
             (label_ref (match_operand 1 "" ""))
             (pc)))
-     (set (match_operand:QI 0 "addr_reg_operand" "+a")
+     (set (match_dup 0)
           (plus:QI (match_dup 0)
                    (const_int -1)))
      (clobber (reg:CC_NOOV 21))])]
    (parallel
     [(set (pc)
           (if_then_else
-            (ne (match_operand:QI 4 "addr_reg_operand" "0")
+            (ne (match_operand:QI 0 "addr_reg_operand" "+a")
                 (const_int 0))
             (label_ref (match_operand 1 "" ""))
             (pc)))
-     (set (match_operand:QI 0 "addr_reg_operand" "+a")
+     (set (match_dup 0)
           (plus:QI (match_dup 0)
                    (const_int -1)))
      (clobber (reg:CC_NOOV 21))])]
 ; Peepholes to convert 'call label; rets' into jump label
 ;
 (define_peephole
-  [(parallel [(call (match_operand:QI 0 "call_operand" "T,!o")
+  [(parallel [(call (mem:QI (match_operand:QI 0 "call_operand" ""))
                     (match_operand:QI 1 "general_operand" ""))
               (clobber (reg:QI 31))])
    (return)]
   "c4x_null_epilogue_p ()"
-  "@
-   br%#\\t%C0
-   bu%#\\t%R0"
-  [(set_attr "type" "jump,jump")])
+  "*
+   if (GET_CODE (XEXP (operands[0], 0)) == REG)
+     return \"bu%#\\t%C0\";
+   else
+     return \"br%#\\t%C0\";"
+  [(set_attr "type" "jump")])
 
 (define_peephole
   [(parallel [(set (match_operand 0 "" "")
-                   (call (match_operand:QI 1 "call_operand" "T,!o")
+                   (call (mem:QI (match_operand:QI 1 "call_operand" ""))
                          (match_operand:QI 2 "general_operand" "")))
               (clobber (reg:QI 31))])
    (return)]
   "c4x_null_epilogue_p ()"
-  "@
-   br%#\\t%C1
-   bu%#\\t%R1"
-  [(set_attr "type" "jump,jump")])
+  "*
+   if (GET_CODE (XEXP (operands[1], 0)) == REG)
+     return \"bu%#\\t%C1\";
+   else
+     return \"br%#\\t%C1\";"
+  [(set_attr "type" "jump")])
 
 ;
 ; Peepholes for parallel instructions