public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix _Unwind_Context backward compatibility issues
@ 2006-12-28 20:46 Jakub Jelinek
  2006-12-29  6:54 ` [PATCH]: for Score backend liqin
  2007-01-03 18:07 ` [PATCH] Fix _Unwind_Context backward compatibility issues Richard Henderson
  0 siblings, 2 replies; 5+ messages in thread
From: Jakub Jelinek @ 2006-12-28 20:46 UTC (permalink / raw)
  To: gcc-patches

Hi!

The
http://gcc.gnu.org/ml/gcc-patches/2006-02/msg01986.html
http://gcc.gnu.org/ml/gcc-patches/2006-03/msg00208.html
patches added 2 new fields at the end of struct _Unwind_Context.
While that structure is only defined inside unwind-dw2.c, unfortunately
it seems to be part of the ABI.  That's because if some application
or library has its own copy of some older version of GCC unwinder
linked into it, the two unwinders don't play together nicely.
It is arguably a bug to provide its own unwinder (except for statically
linked apps), but unfortunately it seems quite a common bug.
With older GCCs (before --as-needed was used in specs), all that
was needed was link some C++ program or shared library with
gcc -o foo *.o -lstdc++
rather than
g++ -o foo *.o
and with very old GCCs the libgcc_eh.a routines weren't even hidden
in the executable.  With contemporary GCCs one has to try harder,
either use -static-libgcc switch or link with explicit -lgcc_eh (one
example of the latter is e.g. libwvstreams).
The scenarios in which things break:
1) unwinder in the executable, exported from it (i.e. before it was
made .hidden in libgcc_eh.a), links against shared libstdc++.so and
that links against shared libgcc_s.so.  If something calls say
_Unwind_RaiseException, it will be resolved to the copy in the executable,
because it comes earlier in the search path.  The old _Unwind_RaiseException
sets up 2 struct _Unwind_Context variables, with the old layout (i.e.
args_size as the last member).  During unwinding __gxx_personality_v0
in the shared libstdc++.so is called and that calls _Unwind_GetIPInfo.
A pointer to the small old struct _Unwind_Context in old
_Unwind_RaiseException's stack frame is passed through.
As this is a new function in GCC 4.2, it won't be in the unwinder in
the executable, so the call jumps to _Unwind_GetIPInfo in GCC 4.2+
libgcc_s.so.  But, this routine looks at context->signal_frame,
i.e. depends on some uninitialized byte on the stack.
2) unwinder in the executable, not exported from it (slightly newer
version, already .hidden), links against shared libstdc++.so which
links against shared libgcc_s.so.  When an exception is thrown
(__cxa_throw), first the libgcc_s.so unwinder is used, but if there
is some destructor within the executable, we can then call _Unwind_Resume
hidden in the executable.  This again sets up a small _Unwind_Context,
then during unwinding calls __gxx_personality_v0.  This can call
_Unwind_SetGR to set the unwind arguments, in all cases passing around
pointer to the small _Unwind_Context.  But, as _Unwind_SetGR from the
executable's unwinder is hidden in the executable, it calls _Unwind_SetGR
in libgcc_s.so.  This looks at context->by_value, thus again depends
on uninitialized stack values.  If non-zero happens to be there,
it can set context->regs[i] directly to the value rather than
store the value to *context->regs[i].  When in uw_install_context_1
of the executable's unwinder the program will likely crash though,
because it expects context->regs[i] to be a valid pointer.

Unfortunately, the old _Unwind_Context did not contain any zero initialized
pad values nor any version field which would allow subsequent field
additions.
The following patch tries to stay backwards compatible with 99.999%
of old programs out there.  It will not work with functions on 32-bit
arches which push 1GB or more of arguments to one function, use
DW_CFA_GNU_args_size for that function and at least one other unwinder
is used in the application in addition to libgcc_s.so.1's unwinder.
I guess that is extremely rare to non-existent.
args_size field is always used only within the same unwinder
(set up in uw_frame_state_for and/or static functions it calls,
read in uw_install_context_1, again static function called from within
the same _Unwind_{RaiseException,ForcedUnwind,Resume}.

The reason I'm not just using the topmost args_size bit for
EXTENDED_CONTEXT_BIT is that we (Red Hat) unfortunately used the
topmost bit in RHEL 4.4 and RHEL 3.8 when we found the signal_frame
new field didn't fly.  I'm terribly sorry about that.
At that time we thought GCC 4.2+ doesn't need to worry about this,
after all apps that have their own unwinder in addition to libgcc_s's
are broken (e.g. when libc or some other library starts using new
DW_CFA_* opcodes, the old statically linked unwinders are out of luck),
but we didn't know about scenario 2) at that point and we didn't know
how many buggy apps are out there.

Perhaps to be even more compatible even with older GCC 4.2 (plus
all the 4.1 branches where this has been backported) unwinders,
_Unwind_Context could be:

struct _Unwind_Context
{
  void *reg[DWARF_FRAME_REGISTERS+1];
  void *cfa;
  void *ra;
  void *lsda;
  struct dwarf_eh_bases bases;
  /* Signal frame context.  */
#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
  /* Context which has version/args_size/by_value fields.  */
#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
  _Unwind_Word flags;
  char old_signal_frame; /* Unused now, always 0.  */
  char by_value[DWARF_FRAME_REGISTERS+1];
  /* 0 for now, can be increased when further fields are added to
     struct _Unwind_Context.  */
  _Unwind_Word version;
  _Unwind_Word args_size;
};

and keep the rest of the patch the same, or alternatively
drop SIGNAL_FRAME_BIT (but keep EXTENDED_CONTEXT_BIT the 2nd MSB)
and use signal_frame only if _Unwind_IsExtendedContext (context).

As args_size (see above) is only used within the same unwinder,
we can IMHO move it to a different field, therefore support even
extremely huge function arguments when only the new under is used.

The struct now includes also a version field which can be used
for further extensions of struct _Unwind_Context, so that we don't
have to fight this bit battle again.

Bootstrapped/regtested on 7 linux arches.

Thoughts?

2006-12-28  Jakub Jelinek  <jakub@redhat.com>

	* unwind-dw2.c (SIGNAL_FRAME_BIT, EXTENDED_CONTEXT_BIT): Define.
	(struct _Unwind_Context): Rename args_size to flags, remove
	signal_frame field, add a new args_size field and version field.
	(_Unwind_IsSignalFrame, _Unwind_SetSignalFrame,
	_Unwind_IsExtendedContext): New inline functions.
	(_Unwind_GetGR, _Unwind_SetGR, _Unwind_GetGRPtr, _Unwind_SetGRPtr):
	Assume by_value array is only present if _Unwind_IsExtendedContext.
	(_Unwind_GetIPInfo, execute_cfa_program, uw_frame_state_for): Use
	_Unwind_IsSignalFrame.
	(__frame_state_for): Initialize context.flags to EXTENDED_CONTEXT_BIT.
	(uw_update_context_1): Use _Unwind_SetSignalFrame.
	(uw_init_context_1): Initialize context->flags to
	EXTENDED_CONTEXT_BIT.
	* config/rs6000/linux-unwind.h (frob_update_context): Use
	_Unwind_SetSignalFrame.

--- gcc/unwind-dw2.c.jj	2006-12-08 15:57:44.000000000 +0100
+++ gcc/unwind-dw2.c	2006-12-27 17:16:12.000000000 +0100
@@ -70,8 +70,15 @@ struct _Unwind_Context
   void *ra;
   void *lsda;
   struct dwarf_eh_bases bases;
+  /* Signal frame context.  */
+#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
+  /* Context which has version/args_size/by_value fields.  */
+#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
+  _Unwind_Word flags;
+  /* 0 for now, can be increased when further fields are added to
+     struct _Unwind_Context.  */
+  _Unwind_Word version;
   _Unwind_Word args_size;
-  char signal_frame;
   char by_value[DWARF_FRAME_REGISTERS+1];
 };
 
@@ -123,6 +130,27 @@ read_8u (const void *p) { const union un
 static inline unsigned long
 read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
 \f
+static inline _Unwind_Word
+_Unwind_IsSignalFrame (struct _Unwind_Context *context)
+{
+  return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0;
+}
+
+static inline void
+_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val)
+{
+  if (val)
+    context->flags |= SIGNAL_FRAME_BIT;
+  else
+    context->flags &= ~SIGNAL_FRAME_BIT;
+}
+
+static inline _Unwind_Word
+_Unwind_IsExtendedContext (struct _Unwind_Context *context)
+{
+  return context->flags & EXTENDED_CONTEXT_BIT;
+}
+\f
 /* Get the value of register INDEX as saved in CONTEXT.  */
 
 inline _Unwind_Word
@@ -141,7 +169,7 @@ _Unwind_GetGR (struct _Unwind_Context *c
   size = dwarf_reg_size_table[index];
   ptr = context->reg[index];
 
-  if (context->by_value[index])
+  if (_Unwind_IsExtendedContext (context) && context->by_value[index])
     return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr;
 
   /* This will segfault if the register hasn't been saved.  */
@@ -180,7 +208,7 @@ _Unwind_SetGR (struct _Unwind_Context *c
   gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
   size = dwarf_reg_size_table[index];
 
-  if (context->by_value[index])
+  if (_Unwind_IsExtendedContext (context) && context->by_value[index])
     {
       context->reg[index] = (void *) (_Unwind_Internal_Ptr) val;
       return;
@@ -203,7 +231,7 @@ static inline void *
 _Unwind_GetGRPtr (struct _Unwind_Context *context, int index)
 {
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
-  if (context->by_value[index])
+  if (_Unwind_IsExtendedContext (context) && context->by_value[index])
     return &context->reg[index];
   return context->reg[index];
 }
@@ -214,7 +242,8 @@ static inline void
 _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
 {
   index = DWARF_REG_TO_UNWIND_COLUMN (index);
-  context->by_value[index] = 0;
+  if (_Unwind_IsExtendedContext (context))
+    context->by_value[index] = 0;
   context->reg[index] = p;
 }
 
@@ -256,7 +285,7 @@ _Unwind_GetIP (struct _Unwind_Context *c
 inline _Unwind_Ptr
 _Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
 {
-  *ip_before_insn = context->signal_frame != 0;
+  *ip_before_insn = _Unwind_IsSignalFrame (context);
   return (_Unwind_Ptr) context->ra;
 }
 
@@ -824,7 +853,8 @@ execute_cfa_program (const unsigned char
      reflected at the point immediately before the call insn.
      In signal frames, return address is after last completed instruction,
      so we add 1 to return address to make the comparison <=.  */
-  while (insn_ptr < insn_end && fs->pc < context->ra + context->signal_frame)
+  while (insn_ptr < insn_end
+	 && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
     {
       unsigned char insn = *insn_ptr++;
       _Unwind_Word reg, utmp;
@@ -1063,7 +1093,7 @@ uw_frame_state_for (struct _Unwind_Conte
   if (context->ra == 0)
     return _URC_END_OF_STACK;
 
-  fde = _Unwind_Find_FDE (context->ra + context->signal_frame - 1,
+  fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
 			  &context->bases);
   if (fde == NULL)
     {
@@ -1142,6 +1172,7 @@ __frame_state_for (void *pc_target, stru
   int reg;
 
   memset (&context, 0, sizeof (struct _Unwind_Context));
+  context.flags = EXTENDED_CONTEXT_BIT;
   context.ra = pc_target + 1;
 
   if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON)
@@ -1306,7 +1337,7 @@ uw_update_context_1 (struct _Unwind_Cont
 	break;
       }
 
-  context->signal_frame = fs->signal_frame;
+  _Unwind_SetSignalFrame (context, fs->signal_frame);
 
 #ifdef MD_FROB_UPDATE_CONTEXT
   MD_FROB_UPDATE_CONTEXT (context, fs);
@@ -1366,6 +1397,7 @@ uw_init_context_1 (struct _Unwind_Contex
 
   memset (context, 0, sizeof (struct _Unwind_Context));
   context->ra = ra;
+  context->flags = EXTENDED_CONTEXT_BIT;
 
   code = uw_frame_state_for (context, &fs);
   gcc_assert (code == _URC_NO_REASON);
--- gcc/config/rs6000/linux-unwind.h.jj	2006-10-29 21:49:21.000000000 +0100
+++ gcc/config/rs6000/linux-unwind.h	2006-12-28 10:40:19.000000000 +0100
@@ -319,7 +319,7 @@ frob_update_context (struct _Unwind_Cont
   if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
       && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
       && pc[2] == 0x44000002)
-    context->signal_frame = 1;
+    _Unwind_SetSignalFrame (context, 1);
 #else
   /* li r0, 0x7777; sc  (sigreturn old)  */
   /* li r0, 0x0077; sc  (sigreturn new)  */
@@ -328,7 +328,7 @@ frob_update_context (struct _Unwind_Cont
   if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
        || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
       && pc[1] == 0x44000002)
-    context->signal_frame = 1;
+    _Unwind_SetSignalFrame (context, 1);
 #endif
 
 #ifdef __powerpc64__

	Jakub

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH]: for Score backend
  2006-12-28 20:46 [PATCH] Fix _Unwind_Context backward compatibility issues Jakub Jelinek
@ 2006-12-29  6:54 ` liqin
  2007-01-04  1:30   ` liqin
  2007-01-03 18:07 ` [PATCH] Fix _Unwind_Context backward compatibility issues Richard Henderson
  1 sibling, 1 reply; 5+ messages in thread
From: liqin @ 2006-12-29  6:54 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1325 bytes --]

Hi,
this patch did many changes for Score backend.

Changelog:
        * config/score/predicates.md (const_uimm5, sr0_operand, 
const_simm12,
        const_simm15, const_pow2, const_npow2): Added.
        * config/score/misc.md (insv, extv, extzv, movmemsi, 
        move_lbu_a/b, mov_lhu_a/b etc): Added and fix some bug.
        * config/score/score.c (score_address_cost, score_select_cc_mode): 

        Added.
        Change CONST_OK_FOR_LETTER_P/EXTRA_CONSTRAINT define.
        Update score_rtx_costs for MACRO TARGET_RTX_COSTS.
       Update score_print_operand.
        * config/score/score.h (DATA_ALIGNMENT, SELECT_CC_MODE): Added.
        Adjust register allocate order and update some macro define.
        * config/score/score-mdaux.c (mdx_unaligned_load, 
mdx_unsigned_store,
        mdx_block_move_straight, mdx_block_move_loop_head, 
mdx_block_move_loop_body,
        mdx_block_move_loop_foot, mdx_block_move_loop  mdx_block_move):
        Added.
        (mdx_movsicc, mdp_select_add_imm, mdp_select, 
mds_zero_extract_andi, mdp_limm):
        Updated and fix some bug and typo.
        * config/score/score.md (movqi/hi/si, add/sub/zero/ext): Updated.
        (movsf, movdf, doloop_end): Added.
        * config/score/t-score-elf (MULTILIB_OPTIONS): Change.

Rgds
Liqin



[-- Attachment #2: score-20061229.patch --]
[-- Type: application/octet-stream, Size: 99711 bytes --]

Index: gcc/config/score/t-score-elf
===================================================================
--- gcc/config/score/t-score-elf	(revision 120252)
+++ gcc/config/score/t-score-elf	(working copy)
@@ -35,7 +35,7 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
 # without the $gp register.
 TARGET_LIBGCC2_CFLAGS = -G 0
 
-MULTILIB_OPTIONS = fPIC mel mscore7
+MULTILIB_OPTIONS = mmac mel fPIC
 MULTILIB_MATCHES = fPIC=fpic
 
 EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
@@ -43,4 +43,3 @@ EXTRA_MULTILIB_PARTS = crtbegin.o crtend
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
 
-
Index: gcc/config/score/crti.asm
===================================================================
--- gcc/config/score/crti.asm	(revision 120252)
+++ gcc/config/score/crti.asm	(working copy)
@@ -43,8 +43,8 @@
         .mask   0x00000000, 0
 _start:
         la      r28, _gp
-        la      r8, __bss_start
-        la      r9, __bss_end__
+        la      r8, _bss_start
+        la      r9, _bss_end__
         sub!    r9, r8
         srli!   r9, 2
         addi    r9, -1
@@ -91,8 +91,8 @@ _fini:
         .mask   0x00000000,0
 _start:
         la      r28, _gp
-        la      r8, __bss_start
-        la      r9, __bss_end__
+        la      r8, _bss_start
+        la      r9, _bss_end__
         sub!    r9, r8
         srli!   r9, 2
         addi    r9, -1
@@ -102,15 +102,10 @@ _start:
         sw      r9, [r8]+, 4
         bcnz    1b
         la      r0, _stack
-#       jl      _init
-#       la      r4, _end
-#       jl      _init_argv
         ldiu!   r4, 0
         ldiu!   r5, 0
-#       jl      main
         la      r29, main
         brl     r29
-#       jl      exit
         la      r29, exit
         brl     r29
         .end    _start
Index: gcc/config/score/predicates.md
===================================================================
--- gcc/config/score/predicates.md	(revision 120252)
+++ gcc/config/score/predicates.md	(working copy)
@@ -35,13 +35,11 @@
   (ior (match_operand 0 "const_call_insn_operand")
        (match_operand 0 "register_operand")))
 
-(define_predicate "const_bi_operand"
-  (and (match_code "const_int")
-       (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'J')")))
-
-(define_predicate "pindex_off_operand"
-  (and (match_code "const_int")
-       (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'P')")))
+(define_predicate "const_uimm5"
+  (match_code "const_int")
+{
+  return IMM_IN_RANGE (INTVAL (op), 5, 0);
+})
 
 (define_predicate "hireg_operand"
   (and (match_code "reg")
@@ -51,6 +49,10 @@
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
 
+(define_predicate "sr0_operand"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == CN_REGNUM")))
+
 (define_predicate "g32reg_operand"
   (and (match_code "reg")
        (match_test "GP_REG_P (REGNO (op))")))
@@ -61,3 +63,26 @@
 (define_predicate "branch_nz_operator"
   (match_code "eq,ne,lt,ge"))
 
+(define_predicate "const_simm12"
+  (match_code "const_int")
+{
+  return IMM_IN_RANGE (INTVAL (op), 12, 1);
+})
+
+(define_predicate "const_simm15"
+  (match_code "const_int")
+{
+  return IMM_IN_RANGE (INTVAL (op), 15, 1);
+})
+
+(define_predicate "const_pow2"
+  (match_code "const_int")
+{
+  return IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) INTVAL (op), 0, 31);
+})
+
+(define_predicate "const_npow2"
+  (match_code "const_int")
+{
+  return IMM_IS_POW_OF_2 (~(unsigned HOST_WIDE_INT) INTVAL (op), 0, 31);
+})
Index: gcc/config/score/score-version.h
===================================================================
--- gcc/config/score/score-version.h	(revision 120252)
+++ gcc/config/score/score-version.h	(working copy)
@@ -18,4 +18,4 @@
    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.  */
 
-#define SCORE_GCC_VERSION "1.1"
+#define SCORE_GCC_VERSION "1.2"
Index: gcc/config/score/crtn.asm
===================================================================
--- gcc/config/score/crtn.asm	(revision 120252)
+++ gcc/config/score/crtn.asm	(working copy)
@@ -59,4 +59,3 @@
         br      r3
 #endif
 
-
Index: gcc/config/score/score-protos.h
===================================================================
--- gcc/config/score/score-protos.h	(revision 120252)
+++ gcc/config/score/score-protos.h	(working copy)
@@ -36,7 +36,7 @@ enum reg_class score_preferred_reload_cl
 enum reg_class score_secondary_reload_class (enum reg_class class,
                                              enum machine_mode mode, rtx x);
 
-int score_const_ok_for_letter_p (int value, char c);
+int score_const_ok_for_letter_p (HOST_WIDE_INT value, char c);
 
 int score_extra_constraint (rtx op, char c);
 
Index: gcc/config/score/misc.md
===================================================================
--- gcc/config/score/misc.md	(revision 120252)
+++ gcc/config/score/misc.md	(working copy)
@@ -84,8 +84,8 @@
   [(set (match_operand:SI 0 "register_operand" "=d")
         (if_then_else:SI (match_operator 1 "comparison_operator"
                           [(reg:CC CC_REGNUM) (const_int 0)])
-                         (match_operand:SI 2 "register_operand" "d")
-                         (match_operand:SI 3 "register_operand" "0")))]
+                         (match_operand:SI 2 "arith_operand" "d")
+                         (match_operand:SI 3 "arith_operand" "0")))]
   ""
   "mv%C1   %0, %2"
   [(set_attr "type" "cndmv")
@@ -95,7 +95,7 @@
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (unspec:SI
                         [(match_operand:SI 0 "register_operand" "*e,d")
-                         (match_operand:SI 1 "const_bi_operand" "")]
+                         (match_operand:SI 1 "const_uimm5" "")]
                         BITTST)
                        (const_int 0)))]
   ""
@@ -106,3 +106,312 @@
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
+(define_expand "extzv"
+  [(set (match_operand:SI 0 "register_operand" "")
+        (zero_extract (match_operand:SI 1 "memory_operand" "")
+                      (match_operand:SI 2 "immediate_operand" "")
+                      (match_operand:SI 3 "immediate_operand" "")))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+{
+  if (mdx_unaligned_load (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_expand "insv"
+  [(set (zero_extract (match_operand:SI 0 "memory_operand" "")
+                      (match_operand:SI 1 "immediate_operand" "")
+                      (match_operand:SI 2 "immediate_operand" ""))
+        (match_operand:SI 3 "register_operand" ""))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+{
+  if (mdx_unaligned_store (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_expand "extv"
+  [(set (match_operand:SI 0 "register_operand" "")
+        (sign_extract (match_operand:SI 1 "memory_operand" "")
+                      (match_operand:SI 2 "immediate_operand" "")
+                      (match_operand:SI 3 "immediate_operand" "")))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+{
+  if (mdx_unaligned_load (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_expand "movmemsi"
+  [(parallel [(set (match_operand:BLK 0 "general_operand")
+                   (match_operand:BLK 1 "general_operand"))
+              (use (match_operand:SI 2 ""))
+              (use (match_operand:SI 3 "const_int_operand"))])]
+  "!TARGET_SCORE5U"
+{
+  if (mdx_block_move (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_insn "move_lbu_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:QI 3 "register_operand" "=d")
+        (mem:QI (match_dup 1)))]
+  "!TARGET_SCORE5U"
+  "lbu     %3, [%1]+, %2"
+  [(set_attr "type" "load")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_lhu_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:HI 3 "register_operand" "=d")
+        (mem:HI (match_dup 1)))]
+  "!TARGET_SCORE5U"
+  "lhu     %3, [%1]+, %2"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_lw_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:SI 3 "register_operand" "=d")
+        (mem:SI (match_dup 1)))]
+  "!TARGET_SCORE5U"
+  "lw      %3, [%1]+, %2"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_sb_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:QI (match_dup 1))
+        (match_operand:QI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sb      %3, [%1]+, %2"
+  [(set_attr "type" "store")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_sh_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:HI (match_dup 1))
+        (match_operand:HI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sh      %3, [%1]+, %2"
+  [(set_attr "type" "store")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_sw_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:SI (match_dup 1))
+        (match_operand:SI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sw      %3, [%1]+, %2"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lbu_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:QI 3 "register_operand" "=d")
+        (mem:QI (plus:SI (match_dup 1)
+                         (match_dup 2))))]
+  "!TARGET_SCORE5U"
+  "lbu     %3, [%1, %2]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_lhu_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:HI 3 "register_operand" "=d")
+        (mem:HI (plus:SI (match_dup 1)
+                         (match_dup 2))))]
+  "!TARGET_SCORE5U"
+  "lhu     %3, [%1, %2]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_lw_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:SI 3 "register_operand" "=d")
+        (mem:SI (plus:SI (match_dup 1)
+                         (match_dup 2))))]
+  "!TARGET_SCORE5U"
+  "lw      %3, [%1, %2]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_sb_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:QI (plus:SI (match_dup 1)
+                         (match_dup 2)))
+        (match_operand:QI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sb      %3, [%1, %2]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_sh_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:HI (plus:SI (match_dup 1)
+                         (match_dup 2)))
+        (match_operand:HI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sh      %3, [%1, %2]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_sw_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:SI (plus:SI (match_dup 1)
+                         (match_dup 2)))
+        (match_operand:SI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sw      %3, [%1, %2]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lcb"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (reg:SI LC_REGNUM)
+        (unspec:SI [(mem:BLK (match_dup 1))] LCB))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "lcb     [%1]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lcw"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (match_operand:SI 2 "register_operand" "=d")
+        (unspec:SI [(mem:BLK (match_dup 1))
+                    (reg:SI LC_REGNUM)] LCW))
+   (set (reg:SI LC_REGNUM)
+        (unspec:SI [(mem:BLK (match_dup 1))] LCB))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "lcw     %2, [%1]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lce"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (match_operand:SI 2 "register_operand" "=d")
+        (unspec:SI [(mem:BLK (match_dup 1))
+                    (reg:SI LC_REGNUM)] LCE))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "lce     %2, [%1]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_scb"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (mem:BLK (match_dup 1))
+        (unspec:BLK [(match_operand:SI 2 "register_operand" "d")] SCB))
+   (set (reg:SI SC_REGNUM)
+        (unspec:SI [(match_dup 2)] SCLC))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "scb     %2, [%1]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_scw"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (mem:BLK (match_dup 1))
+        (unspec:BLK [(match_operand:SI 2 "register_operand" "d")
+                     (reg:SI SC_REGNUM)] SCW))
+   (set (reg:SI SC_REGNUM)
+        (unspec:SI [(match_dup 2)] SCLC))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "scw     %2, [%1]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_sce"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (mem:BLK (match_dup 1))
+        (unspec:BLK [(reg:SI SC_REGNUM)] SCE))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "sce     [%1]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "andsi3_extzh"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (and:SI (match_operand:SI 1 "register_operand" "d")
+                (const_int 65535)))]
+  ""
+  "extzh   %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "bitclr_c"
+  [(set (match_operand:SI 0 "register_operand" "=e,d")
+        (and:SI (match_operand:SI 1 "register_operand" "0,d")
+                (match_operand:SI 2 "const_npow2")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "@
+   bitclr!    %0, %F2
+   bitclr.c   %0, %1, %F2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "bitset_c"
+  [(set (match_operand:SI 0 "register_operand" "=e,d")
+        (ior:SI (match_operand:SI 1 "register_operand" "0,d")
+                (match_operand:SI 2 "const_pow2")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "@
+   bitset!    %0, %E2
+   bitset.c   %0, %1, %E2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "bittgl_c"
+  [(set (match_operand:SI 0 "register_operand" "=e,d")
+        (xor:SI (match_operand:SI 1 "register_operand" "0,d")
+                (match_operand:SI 2 "const_pow2")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "@
+   bittgl!    %0, %E2
+   bittgl.c   %0, %1, %E2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
Index: gcc/config/score/score.c
===================================================================
--- gcc/config/score/score.c	(revision 120252)
+++ gcc/config/score/score.c	(working copy)
@@ -67,7 +67,9 @@ static int score_symbol_insns (enum scor
 
 static int score_address_insns (rtx, enum machine_mode);
 
-static bool score_rtx_costs (rtx, int, int, int *);
+static bool score_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *);
+
+static int score_address_cost (rtx);
 
 #undef  TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START           th_asm_file_start
@@ -126,6 +128,9 @@ static bool score_rtx_costs (rtx, int, i
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS                score_rtx_costs
 
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST             score_address_cost
+
 #undef TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS     TARGET_DEFAULT
 
@@ -154,7 +159,7 @@ score_pass_by_reference (CUMULATIVE_ARGS
 static rtx
 score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
 {
-  if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
+  if (!IMM_IN_RANGE (offset, 15, 1))
     {
       reg = expand_simple_binop (GET_MODE (reg), PLUS,
                                  gen_int_mode (offset & 0xffffc000,
@@ -499,12 +504,13 @@ enum reg_class score_char_to_class[256];
 void
 score_override_options (void)
 {
+  flag_pic = false;
   if (!flag_pic)
     sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
   else
     {
       sdata_max = 0;
-      if (g_switch_set)
+      if (g_switch_set && (g_switch_value != 0))
         warning (0, "-fPIC and -G are incompatible");
     }
 
@@ -540,7 +546,7 @@ score_reg_class (int regno)
       || regno == ARG_POINTER_REGNUM)
     return ALL_REGS;
 
-  for (c = 0 ; c < N_REG_CLASSES ; c++)
+  for (c = 0; c < N_REG_CLASSES; c++)
     if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
       return c;
 
@@ -551,10 +557,10 @@ score_reg_class (int regno)
 enum reg_class
 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
 {
-  if (reg_class_subset_p (G32_REGS, class))
-    class = G32_REGS;
   if (reg_class_subset_p (G16_REGS, class))
-    class = G16_REGS;
+    return G16_REGS;
+  if (reg_class_subset_p (G32_REGS, class))
+    return G32_REGS;
   return class;
 }
 
@@ -576,41 +582,34 @@ score_secondary_reload_class (enum reg_c
 
 /* Implement CONST_OK_FOR_LETTER_P macro.  */
 /* imm constraints
-   I        IMM8        (i15-2-form)
-   J        IMM5        (i15_1-form)
-   K        IMM16       (i-form)
-   L        IMM16s      (i-form)
-   M        IMM14       (ri-form)
-   N        IMM14s      (ri-form)
-   O        IMM15s      (ri-form)
-   P        IMM12s      (rix-form) / IMM10s(cop-form) << 2  */
+   I        imm16 << 16
+   J        uimm5
+   K        uimm16
+   L        simm16
+   M        uimm14
+   N        simm14  */
 int
-score_const_ok_for_letter_p (int value, char c)
+score_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
 {
   switch (c)
     {
-    case 'I': return IMM_IN_RANGE (value, 8, 0);
+    case 'I': return ((value & 0xffff) == 0);
     case 'J': return IMM_IN_RANGE (value, 5, 0);
     case 'K': return IMM_IN_RANGE (value, 16, 0);
     case 'L': return IMM_IN_RANGE (value, 16, 1);
     case 'M': return IMM_IN_RANGE (value, 14, 0);
     case 'N': return IMM_IN_RANGE (value, 14, 1);
-    case 'O': return IMM_IN_RANGE (value, 15, 1);
-    case 'P': return IMM_IN_RANGE (value, 12, 1);
     default : return 0;
     }
 }
 
 /* Implement EXTRA_CONSTRAINT macro.  */
-/* Q        const_hi    imm
-   Z        symbol_ref  */
+/* Z        symbol_ref  */
 int
 score_extra_constraint (rtx op, char c)
 {
   switch (c)
     {
-    case 'Q':
-      return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
     case 'Z':
       return GET_CODE (op) == SYMBOL_REF;
     default:
@@ -917,10 +916,8 @@ score_address_insns (rtx x, enum machine
   int factor;
 
   if (mode == BLKmode)
-    /* BLKmode is used for single unaligned loads and stores.  */
     factor = 1;
   else
-    /* Each word of a multi-word value will be accessed individually.  */
     factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
   if (mda_classify_address (&addr, mode, x, false))
@@ -938,24 +935,53 @@ score_address_insns (rtx x, enum machine
 
 /* Implement TARGET_RTX_COSTS macro.  */
 static bool
-score_rtx_costs (rtx x, int code, int outer_code, int *total)
+score_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
+                 int *total)
 {
   enum machine_mode mode = GET_MODE (x);
 
   switch (code)
     {
     case CONST_INT:
-      /* These can be used anywhere. */
-      *total = 0;
+      if (outer_code == SET)
+        {
+          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+              || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
+            *total = COSTS_N_INSNS (1);
+          else
+            *total = COSTS_N_INSNS (2);
+        }
+      else if (outer_code == PLUS || outer_code == MINUS)
+        {
+          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
+            *total = 0;
+          else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
+            *total = 1;
+          else
+            *total = COSTS_N_INSNS (2);
+        }
+      else if (outer_code == AND || outer_code == IOR)
+        {
+          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
+            *total = 0;
+          else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
+            *total = 1;
+          else
+            *total = COSTS_N_INSNS (2);
+        }
+      else
+        {
+          *total = 0;
+        }
       return true;
 
-      /* Otherwise fall through to the handling below because
-         we'll need to construct the constant.  */
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_DOUBLE:
-      *total = COSTS_N_INSNS (1);
+      *total = COSTS_N_INSNS (2);
       return true;
 
     case MEM:
@@ -1011,7 +1037,8 @@ score_rtx_costs (rtx x, int code, int ou
           *total = COSTS_N_INSNS (4);
           return true;
         }
-      return false;
+      *total = COSTS_N_INSNS (1);
+      return true;
 
     case NEG:
       if (mode == DImode)
@@ -1022,22 +1049,38 @@ score_rtx_costs (rtx x, int code, int ou
       return false;
 
     case MULT:
-      *total = COSTS_N_INSNS (12);
+      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
       return true;
 
     case DIV:
     case MOD:
     case UDIV:
     case UMOD:
-      *total = COSTS_N_INSNS (33);
+      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
       return true;
 
     case SIGN_EXTEND:
-      *total = COSTS_N_INSNS (2);
-      return true;
-
     case ZERO_EXTEND:
-      *total = COSTS_N_INSNS (1);
+      switch (GET_MODE (XEXP (x, 0)))
+        {
+        case QImode:
+        case HImode:
+          if (GET_CODE (XEXP (x, 0)) == MEM)
+            {
+              *total = COSTS_N_INSNS (2);
+
+              if (!TARGET_LITTLE_ENDIAN &&
+                  side_effects_p (XEXP (XEXP (x, 0), 0)))
+                *total = 100;
+            }
+          else
+            *total = COSTS_N_INSNS (1);
+          break;
+
+        default:
+          *total = COSTS_N_INSNS (1);
+          break;
+        }
       return true;
 
     default:
@@ -1045,6 +1088,13 @@ score_rtx_costs (rtx x, int code, int ou
     }
 }
 
+/* Implement TARGET_ADDRESS_COST macro.  */
+int
+score_address_cost (rtx addr)
+{
+  return score_address_insns (addr, SImode);
+}
+
 /* Implement ASM_OUTPUT_EXTERNAL macro.  */
 int
 score_output_external (FILE *file ATTRIBUTE_UNUSED,
@@ -1089,18 +1139,16 @@ score_return_addr (int count, rtx frame 
 /* Implement PRINT_OPERAND macro.  */
 /* Score-specific operand codes:
    '['        print .set nor1 directive
-   ']'        print .set r1        directive
-
+   ']'        print .set r1 directive
    'U'        print hi part of a CONST_INT rtx
-   'D'        print first part of const double
-   'S'        selectively print '!' if operand is 15bit instruction accessible
-   'V'        print "v!" if operand is 15bit instruction accessible, or
-   "lfh!"
-
+   'E'        print log2(v)
+   'F'        print log2(~v)
+   'D'        print SFmode const double
+   'S'        selectively print "!" if operand is 15bit instruction accessible
+   'V'        print "v!" if operand is 15bit instruction accessible, or "lfh!"
    'L'        low  part of DImode reg operand
    'H'        high part of DImode reg operand
-
-   'C'  print part of opcode for a branch condition.  */
+   'C'        print part of opcode for a branch condition.  */
 void
 score_print_operand (FILE *file, rtx op, int c)
 {
@@ -1125,9 +1173,11 @@ score_print_operand (FILE *file, rtx op,
   else if (c == 'D')
     {
       if (GET_CODE (op) == CONST_DOUBLE)
-        fprintf (file, HOST_WIDE_INT_PRINT_HEX,
-                 TARGET_LITTLE_ENDIAN
-                 ? CONST_DOUBLE_LOW (op) : CONST_DOUBLE_HIGH (op));
+        {
+          rtx temp = gen_lowpart (SImode, op);
+          gcc_assert (GET_MODE (op) == SFmode);
+          fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp));
+        }
       else
         output_addr_const (file, op);
     }
@@ -1142,23 +1192,17 @@ score_print_operand (FILE *file, rtx op,
       gcc_assert (code == REG);
       fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
     }
-  else if (code == REG)
-    {
-      int regnum = REGNO (op);
-      if ((c == 'H' && !WORDS_BIG_ENDIAN)
-          || (c == 'L' && WORDS_BIG_ENDIAN))
-        regnum ++;
-      fprintf (file, "%s", reg_names[regnum]);
-    }
   else if (c == 'C')
     {
+      enum machine_mode mode = GET_MODE (XEXP (op, 0));
+
       switch (code)
         {
         case EQ: fputs ("eq", file); break;
         case NE: fputs ("ne", file); break;
         case GT: fputs ("gt", file); break;
-        case GE: fputs ("ge", file); break;
-        case LT: fputs ("lt", file); break;
+        case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
+        case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
         case LE: fputs ("le", file); break;
         case GTU: fputs ("gtu", file); break;
         case GEU: fputs ("cs", file); break;
@@ -1168,6 +1212,46 @@ score_print_operand (FILE *file, rtx op,
           output_operand_lossage ("invalid operand for code: '%c'", code);
         }
     }
+  else if (c == 'E')
+    {
+      unsigned HOST_WIDE_INT i;
+      unsigned HOST_WIDE_INT pow2mask = 1;
+      unsigned HOST_WIDE_INT val;
+
+      val = INTVAL (op);
+      for (i = 0; i < 32; i++)
+        {
+          if (val == pow2mask)
+            break;
+          pow2mask <<= 1;
+        }
+      gcc_assert (i < 32);
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
+    }
+  else if (c == 'F')
+    {
+      unsigned HOST_WIDE_INT i;
+      unsigned HOST_WIDE_INT pow2mask = 1;
+      unsigned HOST_WIDE_INT val;
+
+      val = ~INTVAL (op);
+      for (i = 0; i < 32; i++)
+        {
+          if (val == pow2mask)
+            break;
+          pow2mask <<= 1;
+        }
+      gcc_assert (i < 32);
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
+    }
+  else if (code == REG)
+    {
+      int regnum = REGNO (op);
+      if ((c == 'H' && !WORDS_BIG_ENDIAN)
+          || (c == 'L' && WORDS_BIG_ENDIAN))
+        regnum ++;
+      fprintf (file, "%s", reg_names[regnum]);
+    }
   else
     {
       switch (code)
@@ -1233,4 +1317,48 @@ score_print_operand_address (FILE *file,
   gcc_unreachable ();
 }
 
+/* Implement SELECT_CC_MODE macro.  */
+enum machine_mode
+score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
+{
+  if ((op == EQ || op == NE || op == LT || op == GE)
+      && y == const0_rtx
+      && GET_MODE (x) == SImode)
+    {
+      switch (GET_CODE (x))
+        {
+        case PLUS:
+        case MINUS:
+        case NEG:
+        case AND:
+        case IOR:
+        case XOR:
+        case NOT:
+        case ASHIFT:
+        case LSHIFTRT:
+        case ASHIFTRT:
+          return CC_NZmode;
+
+        case SIGN_EXTEND:
+        case ZERO_EXTEND:
+        case ROTATE:
+        case ROTATERT:
+          return (op == LT || op == GE) ? CC_Nmode : CCmode;
+
+        default:
+          return CCmode;
+        }
+    }
+
+  if ((op == EQ || op == NE)
+      && (GET_CODE (y) == NEG)
+      && register_operand (XEXP (y, 0), SImode)
+      && register_operand (x, SImode))
+    {
+      return CC_NZmode;
+    }
+
+  return CCmode;
+}
+
 struct gcc_target targetm = TARGET_INITIALIZER;
Index: gcc/config/score/score.h
===================================================================
--- gcc/config/score/score.h	(revision 120252)
+++ gcc/config/score/score.h	(working copy)
@@ -28,19 +28,20 @@ extern GTY(()) rtx cmp_op0;
 extern GTY(()) rtx cmp_op1;
 
 /* Controlling the Compilation Driver.  */
+#undef SWITCH_TAKES_ARG
 #define SWITCH_TAKES_ARG(CHAR) \
   (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
 
 /* CC1_SPEC is the set of arguments to pass to the compiler proper.  */
 #undef CC1_SPEC
-#define CC1_SPEC                 "%{!mel:-meb}"
+#define CC1_SPEC                 "%{G*} %{!mel:-meb}"
 
 #undef ASM_SPEC
 #define ASM_SPEC \
   "%{!mel:-EB} %{mel:-EL} %{mscore5u:-SCORE5U} %{mscore7:-SCORE7} %{G*}"
 
 #undef LINK_SPEC
-#define LINK_SPEC                 "%{!mel:-EB} %{mel:-EL} %{G*}"
+#define LINK_SPEC                "%{!mel:-EB} %{mel:-EL} %{G*}"
 
 /* Run-time Target Specification.  */
 #define TARGET_CPU_CPP_BUILTINS()               \
@@ -96,7 +97,7 @@ extern GTY(()) rtx cmp_op1;
 
 /* Allocation boundary (in *bits*) for storing arguments in argument list.  */
 #define PARM_BOUNDARY                  BITS_PER_WORD
-#define STACK_BOUNDARY                 64
+#define STACK_BOUNDARY                 BITS_PER_WORD
 
 /* Allocation boundary (in *bits*) for the code of a function.  */
 #define FUNCTION_BOUNDARY              BITS_PER_WORD
@@ -115,12 +116,41 @@ extern GTY(()) rtx cmp_op1;
    data to make it all fit in fewer cache lines.  Another is to
    cause character arrays to be word-aligned so that `strcpy' calls
    that copy constants to character arrays can be done inline.  */
-#define DATA_ALIGNMENT(TYPE, ALIGN)                                     \
-  ((((ALIGN) < BITS_PER_WORD)                                           \
-    && (TREE_CODE (TYPE) == ARRAY_TYPE                                  \
-        || TREE_CODE (TYPE) == UNION_TYPE                               \
+#define DATA_ALIGNMENT(TYPE, ALIGN)                                      \
+  ((((ALIGN) < BITS_PER_WORD)                                            \
+    && (TREE_CODE (TYPE) == ARRAY_TYPE                                   \
+        || TREE_CODE (TYPE) == UNION_TYPE                                \
         || TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
 
+/* If defined, a C expression to compute the alignment given to a
+   constant that is being placed in memory.  EXP is the constant
+   and ALIGN is the alignment that the object would ordinarily have.
+   The value of this macro is used instead of that alignment to align
+   the object.
+
+   If this macro is not defined, then ALIGN is used.
+
+   The typical use of this macro is to increase alignment for string
+   constants to be word aligned so that `strcpy' calls that copy
+   constants can be done inline.  */
+#define CONSTANT_ALIGNMENT(EXP, ALIGN)                                  \
+  ((TREE_CODE (EXP) == STRING_CST  || TREE_CODE (EXP) == CONSTRUCTOR)   \
+   && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* If defined, a C expression to compute the alignment for a local
+   variable.  TYPE is the data type, and ALIGN is the alignment that
+   the object would ordinarily have.  The value of this macro is used
+   instead of that alignment to align the object.
+
+   If this macro is not defined, then ALIGN is used.
+
+   One use of this macro is to increase alignment of medium-size
+   data to make it all fit in fewer cache lines.  */
+#define LOCAL_ALIGNMENT(TYPE, ALIGN)                                    \
+  ((TREE_CODE (TYPE) == ARRAY_TYPE                                      \
+    && TYPE_MODE (TREE_TYPE (TYPE)) == QImode                           \
+    && (ALIGN) < BITS_PER_WORD) ? BITS_PER_WORD : (ALIGN))
+
 /* Alignment of field after `int : 0' in a structure.  */
 #define EMPTY_FIELD_BOUNDARY           32
 
@@ -209,7 +239,7 @@ extern GTY(()) rtx cmp_op1;
 {                                                        \
   /* General Purpose Registers  */                       \
   1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        \
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,        \
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,        \
   /* Control Registers  */                               \
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,        \
   /* CEH/ CEL/ CNT/ LCR/ SCR / ARG_POINTER_REGNUM/ FRAME_POINTER_REGNUM */\
@@ -245,8 +275,8 @@ extern GTY(()) rtx cmp_op1;
 }
 
 #define REG_ALLOC_ORDER                                                   \
-{   0,  1,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,        \
-   18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  2,  3,        \
+{   0,  1,  6,  7,  8,  9, 10, 11,  4,  5, 22, 23, 24, 25, 26, 27,        \
+   12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 28, 29, 30, 31,  2,  3,        \
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,        \
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,        \
    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,        \
@@ -386,18 +416,18 @@ enum reg_class
   score_preferred_reload_class (X, CLASS)
 
 /* If we need to load shorts byte-at-a-time, then we need a scratch.  */
-#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X)        \
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
   score_secondary_reload_class (CLASS, MODE, X)
 
 /* Return the register class of a scratch register needed to copy IN into
    or out of a register in CLASS in MODE.  If it can be done directly,
    NO_REGS is returned.  */
-#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X)       \
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \
   score_secondary_reload_class (CLASS, MODE, X)
 
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS.  */
-#define CLASS_MAX_NREGS(CLASS, MODE)    \
+#define CLASS_MAX_NREGS(CLASS, MODE) \
   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 
 #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)    \
@@ -607,8 +637,8 @@ typedef struct score_args
 #define HAVE_PRE_DECREMENT              1
 #define HAVE_POST_INCREMENT             1
 #define HAVE_POST_DECREMENT             1
-#define HAVE_PRE_MODIFY_DISP            0
-#define HAVE_POST_MODIFY_DISP           0
+#define HAVE_PRE_MODIFY_DISP            1
+#define HAVE_POST_MODIFY_DISP           1
 #define HAVE_PRE_MODIFY_REG             0
 #define HAVE_POST_MODIFY_REG            0
 
@@ -660,6 +690,13 @@ typedef struct score_args
 
 #define LEGITIMATE_CONSTANT_P(X)        1
 
+/* Condition Code Status.  */
+#define SELECT_CC_MODE(OP, X, Y)        score_select_cc_mode (OP, X, Y)
+
+/* Return nonzero if SELECT_CC_MODE will never return MODE for a
+   floating point inequality comparison.  */
+#define REVERSIBLE_CC_MODE(MODE)        1
+
 /* Describing Relative Costs of Operations  */
 /* Compute extra cost of moving data between one register class and another.  */
 #define REGISTER_MOVE_COST(MODE, FROM, TO) \
@@ -753,32 +790,32 @@ typedef struct score_args
   sprintf ((LABEL), "*%s%s%ld", (LOCAL_LABEL_PREFIX), (PREFIX), (long) (NUM))
 
 /* Output of Assembler Instructions.  */
-#define REGISTER_NAMES                                                   \
-{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",                        \
-  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",                  \
-  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",                \
-  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",                \
-                                                                         \
-  "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",                \
-  "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",          \
-                                                                         \
-  "ceh", "cel", "sr0", "sr1", "sr2", "_arg", "_frame", "",               \
-  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",        \
-                                                                         \
-  "c1r0", "c1r1", "c1r2", "c1r3", "c1r4", "c1r5", "c1r6", "c1r7",        \
-  "c1r8", "c1r9", "c1r10", "c1r11", "c1r12", "c1r13", "c1r14", "c1r15",  \
-  "c1r16", "c1r17", "c1r18", "c1r19", "c1r20", "c1r21", "c1r22", "c1r23",\
-  "c1r24", "c1r25", "c1r26", "c1r27", "c1r28", "c1r29", "c1r30", "c1r31",\
-                                                                         \
-  "c2r0", "c2r1", "c2r2", "c2r3", "c2r4", "c2r5", "c2r6", "c2r7",        \
-  "c2r8", "c2r9", "c2r10", "c2r11", "c2r12", "c2r13", "c2r14", "c2r15",  \
-  "c2r16", "c2r17", "c2r18", "c2r19", "c2r20", "c2r21", "c2r22", "c2r23",\
-  "c2r24", "c2r25", "c2r26", "c2r27", "c2r28", "c2r29", "c2r30", "c2r31",\
-                                                                         \
-  "c3r0", "c3r1", "c3r2", "c3r3", "c3r4", "c3r5", "c3r6", "c3r7",        \
-  "c3r8", "c3r9", "c3r10", "c3r11", "c3r12", "c3r13", "c3r14", "c3r15",  \
-  "c3r16", "c3r17", "c3r18", "c3r19", "c3r20", "c3r21", "c3r22", "c3r23",\
-  "c3r24", "c3r25", "c3r26", "c3r27", "c3r28", "c3r29", "c3r30", "c3r31",\
+#define REGISTER_NAMES                                                    \
+{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",                         \
+  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",                   \
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",                 \
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",                 \
+                                                                          \
+  "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",                 \
+  "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",           \
+                                                                          \
+  "ceh", "cel", "sr0", "sr1", "sr2", "_arg", "_frame", "",                \
+  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",         \
+                                                                          \
+  "c1r0", "c1r1", "c1r2", "c1r3", "c1r4", "c1r5", "c1r6", "c1r7",         \
+  "c1r8", "c1r9", "c1r10", "c1r11", "c1r12", "c1r13", "c1r14", "c1r15",   \
+  "c1r16", "c1r17", "c1r18", "c1r19", "c1r20", "c1r21", "c1r22", "c1r23", \
+  "c1r24", "c1r25", "c1r26", "c1r27", "c1r28", "c1r29", "c1r30", "c1r31", \
+                                                                          \
+  "c2r0", "c2r1", "c2r2", "c2r3", "c2r4", "c2r5", "c2r6", "c2r7",         \
+  "c2r8", "c2r9", "c2r10", "c2r11", "c2r12", "c2r13", "c2r14", "c2r15",   \
+  "c2r16", "c2r17", "c2r18", "c2r19", "c2r20", "c2r21", "c2r22", "c2r23", \
+  "c2r24", "c2r25", "c2r26", "c2r27", "c2r28", "c2r29", "c2r30", "c2r31", \
+                                                                          \
+  "c3r0", "c3r1", "c3r2", "c3r3", "c3r4", "c3r5", "c3r6", "c3r7",         \
+  "c3r8", "c3r9", "c3r10", "c3r11", "c3r12", "c3r13", "c3r14", "c3r15",   \
+  "c3r16", "c3r17", "c3r18", "c3r19", "c3r20", "c3r21", "c3r22", "c3r23", \
+  "c3r24", "c3r25", "c3r26", "c3r27", "c3r28", "c3r29", "c3r30", "c3r31", \
 }
 
 /* Print operand X (an rtx) in assembler syntax to file FILE.  */
@@ -907,4 +944,4 @@ struct extern_list GTY ((chain_next ("%h
   int size;                             /* size in bytes  */
 };
 
-extern GTY (()) struct extern_list      *extern_head ;
+extern GTY (()) struct extern_list      *extern_head;
Index: gcc/config/score/score-conv.h
===================================================================
--- gcc/config/score/score-conv.h	(revision 120252)
+++ gcc/config/score/score-conv.h	(working copy)
@@ -45,7 +45,7 @@ extern int target_flags;
 
 #define CE_REG_P(REGNO)        REG_CONTAIN (REGNO, CE_REG_FIRST, CE_REG_NUM)
 
-#define UIMM_IN_RANGE(V, W)  ((V) >= 0 && (V) < ((HOST_WIDE_INT)1 << (W)))
+#define UIMM_IN_RANGE(V, W)  ((V) >= 0 && (V) < ((HOST_WIDE_INT) 1 << (W)))
 
 #define SIMM_IN_RANGE(V, W)                            \
   ((V) >= (-1 * ((HOST_WIDE_INT) 1 << ((W) - 1)))      \
@@ -54,6 +54,11 @@ extern int target_flags;
 #define IMM_IN_RANGE(V, W, S) \
   ((S) ? SIMM_IN_RANGE (V, W) : UIMM_IN_RANGE (V, W))
 
+#define IMM_IS_POW_OF_2(V, E1, E2)                \
+  ((V) >= ((unsigned HOST_WIDE_INT) 1 << (E1))     \
+   && (V) <= ((unsigned HOST_WIDE_INT) 1 << (E2))  \
+   && ((V) & ((V) - 1)) == 0)
+
 #define SCORE_STACK_ALIGN(LOC)          (((LOC) + 3) & ~3)
 
 #define SCORE_MAX_FIRST_STACK_STEP      (0x3ff0)
Index: gcc/config/score/score-mdaux.c
===================================================================
--- gcc/config/score/score-mdaux.c	(revision 120252)
+++ gcc/config/score/score-mdaux.c	(working copy)
@@ -108,10 +108,9 @@ score_symbol_type score_classify_symbol 
   if (GET_CODE (x) == LABEL_REF)
     return SYMBOL_GENERAL;
 
-  if (GET_CODE (x) != SYMBOL_REF)
-    gcc_unreachable ();
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
-  if (CONSTANT_POOL_ADDRESS_P(x))
+  if (CONSTANT_POOL_ADDRESS_P (x))
     {
       if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
         return SYMBOL_SMALL_DATA;
@@ -185,14 +184,14 @@ mda_compute_frame_size (HOST_WIDE_INT si
   f->mask = 0;
   f->var_size = SCORE_STACK_ALIGN (size);
   f->args_size = current_function_outgoing_args_size;
-  f->cprestore_size = SCORE_STACK_ALIGN (STARTING_FRAME_OFFSET) - f->args_size;
+  f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
   if (f->var_size == 0 && current_function_is_leaf)
     f->args_size = f->cprestore_size = 0;
 
   if (f->args_size == 0 && current_function_calls_alloca)
     f->args_size = UNITS_PER_WORD;
 
-  f->total_size = f->var_size + f->args_size;
+  f->total_size = f->var_size + f->args_size + f->cprestore_size;
   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
     {
       if (score_save_reg_p (regno))
@@ -205,7 +204,7 @@ mda_compute_frame_size (HOST_WIDE_INT si
   if (current_function_calls_eh_return)
     {
       unsigned int i;
-      for (i = 0; ; ++i)
+      for (i = 0;; ++i)
         {
           regno = EH_RETURN_DATA_REGNO (i);
           if (regno == INVALID_REGNUM)
@@ -215,7 +214,7 @@ mda_compute_frame_size (HOST_WIDE_INT si
         }
     }
 
-  f->total_size += SCORE_STACK_ALIGN (f->gp_reg_size);
+  f->total_size += f->gp_reg_size;
   f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
 
   if (f->mask)
@@ -226,12 +225,7 @@ mda_compute_frame_size (HOST_WIDE_INT si
       f->gp_sp_offset = offset;
     }
   else
-    {
-      f->gp_sp_offset = 0;
-    }
-
-  if ((f->total_size == f->gp_reg_size) && flag_pic)
-    f->total_size += 8;
+    f->gp_sp_offset = 0;
 
   return f;
 }
@@ -294,8 +288,13 @@ mdx_prologue (void)
   if (frame_pointer_needed)
     EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
 
-  if (flag_pic)
-    emit_insn (gen_cprestore (GEN_INT (size + 4)));
+  if (flag_pic && f->cprestore_size)
+    {
+      if (frame_pointer_needed)
+        emit_insn (gen_cprestore_use_fp (GEN_INT (size - f->cprestore_size)));
+      else
+        emit_insn (gen_cprestore_use_sp (GEN_INT (size - f->cprestore_size)));
+    }
 
 #undef EMIT_PL
 }
@@ -392,7 +391,7 @@ mda_classify_address (struct score_addre
       info->offset = XEXP (x, 1);
       return (mda_valid_base_register_p (info->reg, strict)
               && GET_CODE (info->offset) == CONST_INT
-              && CONST_OK_FOR_LETTER_P (INTVAL (info->offset), 'O'));
+              && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
     case PRE_DEC:
     case POST_DEC:
     case PRE_INC:
@@ -405,7 +404,7 @@ mda_classify_address (struct score_addre
       return mda_valid_base_register_p (info->reg, strict);
     case CONST_INT:
       info->type = ADD_CONST_INT;
-      return CONST_OK_FOR_LETTER_P (INTVAL (x), 'O');
+      return IMM_IN_RANGE (INTVAL (x), 15, 1);
     case CONST:
     case LABEL_REF:
     case SYMBOL_REF:
@@ -443,7 +442,7 @@ mda_symbolic_constant_p (rtx x, enum sco
     return 1;
 
   /* if offset > 15bit, must reload  */
-  if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
+  if (!IMM_IN_RANGE (offset, 15, 1))
     return 0;
 
   switch (*symbol_type)
@@ -459,11 +458,9 @@ mda_symbolic_constant_p (rtx x, enum sco
 void
 mdx_movsicc (rtx *ops)
 {
-  enum machine_mode mode = CCmode;
-
-  if (GET_CODE (ops[1]) == EQ || GET_CODE (ops[1]) == NE)
-    mode = CC_NZmode;
+  enum machine_mode mode;
 
+  mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
                           gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
 }
@@ -533,14 +530,15 @@ mds_movdi (rtx *ops)
 void
 mds_zero_extract_andi (rtx *ops)
 {
-  if (INTVAL (ops[1]) == 1 && const_bi_operand (ops[2], SImode))
+  if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
     emit_insn (gen_zero_extract_bittst (ops[0], ops[2]));
   else
     {
       unsigned HOST_WIDE_INT mask;
       mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
       mask = mask << INTVAL (ops[2]);
-      emit_insn (gen_andsi3_cmp (ops[0], gen_int_mode (mask, SImode)));
+      emit_insn (gen_andsi3_cmp (ops[3], ops[0],
+                                 gen_int_mode (mask, SImode)));
     }
 }
 
@@ -637,17 +635,20 @@ mdp_sinsn (rtx *ops, enum mda_mem_unit u
 const char *
 mdp_limm (rtx *ops)
 {
+  HOST_WIDE_INT v;
+
   gcc_assert (GET_CODE (ops[0]) == REG);
+  gcc_assert (GET_CODE (ops[1]) == CONST_INT);
 
-  if (G16_REG_P (REGNO (ops[0]))
-      && CONST_OK_FOR_LETTER_P (INTVAL (ops[1]), 'I'))
+  v = INTVAL (ops[1]);
+  if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
     return "ldiu!   %0, %c1";
-  else if (CONST_OK_FOR_LETTER_P (INTVAL (ops[1]), 'L'))
+  else if (IMM_IN_RANGE (v, 16, 1))
     return "ldi     %0, %c1";
-  else if (EXTRA_CONSTRAINT (ops[1], 'Q'))
+  else if ((v & 0xffff) == 0)
     return "ldis    %0, %U1";
   else
-    return "li      %0, %D1";
+    return "li      %0, %c1";
 }
 
 /* Output asm insn for move.  */
@@ -670,69 +671,389 @@ mdp_move (rtx *ops)
     return "mv      %0, %1";
 }
 
-/* Score support add/sub with exponent immediate insn,
-   use to judge imm condition.  */
-static unsigned int
-num_bits1 (unsigned HOST_WIDE_INT v)
+/* Emit lcb/lce insns.  */
+bool
+mdx_unaligned_load (rtx *ops)
+{
+  rtx dst = ops[0];
+  rtx src = ops[1];
+  rtx len = ops[2];
+  rtx off = ops[3];
+  rtx addr_reg;
+
+  if (INTVAL (len) != BITS_PER_WORD
+      || (INTVAL (off) % BITS_PER_UNIT) != 0)
+    return false;
+
+  gcc_assert (GET_MODE_SIZE (GET_MODE (dst)) == GET_MODE_SIZE (SImode));
+
+  addr_reg = copy_addr_to_reg (XEXP (src, 0));
+  emit_insn (gen_move_lcb (addr_reg, addr_reg));
+  emit_insn (gen_move_lce (addr_reg, addr_reg, dst));
+
+  return true;
+}
+
+/* Emit scb/sce insns.  */
+bool
+mdx_unaligned_store (rtx *ops)
+{
+  rtx dst = ops[0];
+  rtx len = ops[1];
+  rtx off = ops[2];
+  rtx src = ops[3];
+  rtx addr_reg;
+
+  if (INTVAL(len) != BITS_PER_WORD
+      || (INTVAL(off) % BITS_PER_UNIT) != 0)
+    return false;
+
+  gcc_assert (GET_MODE_SIZE (GET_MODE (src)) == GET_MODE_SIZE (SImode));
+
+  addr_reg = copy_addr_to_reg (XEXP (dst, 0));
+  emit_insn (gen_move_scb (addr_reg, addr_reg, src));
+  emit_insn (gen_move_sce (addr_reg, addr_reg));
+
+  return true;
+}
+
+/* If length is short, generate move insns straight.  */
+static void
+mdx_block_move_straight (rtx dst, rtx src, HOST_WIDE_INT length)
+{
+  HOST_WIDE_INT leftover;
+  int i, reg_count;
+  rtx *regs;
+
+  leftover = length % UNITS_PER_WORD;
+  length -= leftover;
+  reg_count = length / UNITS_PER_WORD;
+
+  regs = alloca (sizeof (rtx) * reg_count);
+  for (i = 0; i < reg_count; i++)
+    regs[i] = gen_reg_rtx (SImode);
+
+  /* Load from src to regs.  */
+  if (MEM_ALIGN (src) >= BITS_PER_WORD)
+    {
+      HOST_WIDE_INT offset = 0;
+      for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
+        emit_move_insn (regs[i], adjust_address (src, SImode, offset));
+    }
+  else if (reg_count >= 1)
+    {
+      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
+
+      emit_insn (gen_move_lcb (src_reg, src_reg));
+      for (i = 0; i < (reg_count - 1); i++)
+        emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
+      emit_insn (gen_move_lce (src_reg, src_reg, regs[i]));
+    }
+
+  /* Store regs to dest.  */
+  if (MEM_ALIGN (dst) >= BITS_PER_WORD)
+    {
+      HOST_WIDE_INT offset = 0;
+      for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
+        emit_move_insn (adjust_address (dst, SImode, offset), regs[i]);
+    }
+  else if (reg_count >= 1)
+    {
+      rtx dst_reg = copy_addr_to_reg (XEXP (dst, 0));
+
+      emit_insn (gen_move_scb (dst_reg, dst_reg, regs[0]));
+      for (i = 1; i < reg_count; i++)
+        emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
+      emit_insn (gen_move_sce (dst_reg, dst_reg));
+    }
+
+  /* Mop up any left-over bytes.  */
+  if (leftover > 0)
+    {
+      src = adjust_address (src, BLKmode, length);
+      dst = adjust_address (dst, BLKmode, length);
+      move_by_pieces (dst, src, leftover,
+                      MIN (MEM_ALIGN (src), MEM_ALIGN (dst)), 0);
+    }
+}
+
+/* Generate loop head when dst or src is unaligned.  */
+static void
+mdx_block_move_loop_head (rtx dst_reg, HOST_WIDE_INT dst_align,
+                          rtx src_reg, HOST_WIDE_INT src_align,
+                          HOST_WIDE_INT length)
 {
-  int i, n = 0;
+  bool src_unaligned = (src_align < BITS_PER_WORD);
+  bool dst_unaligned = (dst_align < BITS_PER_WORD);
+
+  rtx temp = gen_reg_rtx (SImode);
 
-  for (i = 0; i < BITS_PER_WORD; i++)
-    n += BITSET_P (v, i) ? 1 : 0;
-  return n;
+  gcc_assert (length == UNITS_PER_WORD);
+
+  if (src_unaligned)
+    {
+      emit_insn (gen_move_lcb (src_reg, src_reg));
+      emit_insn (gen_move_lcw (src_reg, src_reg, temp));
+    }
+  else
+    emit_insn (gen_move_lw_a (src_reg,
+                              src_reg, gen_int_mode (4, SImode), temp));
+
+  if (dst_unaligned)
+    emit_insn (gen_move_scb (dst_reg, dst_reg, temp));
+  else
+    emit_insn (gen_move_sw_a (dst_reg,
+                              dst_reg, gen_int_mode (4, SImode), temp));
 }
 
-/* Generate add insn, insn will affect condition flag. Optimize used.  */
+/* Generate loop body, copy length bytes per iteration.  */
+static void
+mdx_block_move_loop_body (rtx dst_reg, HOST_WIDE_INT dst_align,
+                          rtx src_reg, HOST_WIDE_INT src_align,
+                          HOST_WIDE_INT length)
+{
+  int reg_count = length / UNITS_PER_WORD;
+  rtx *regs = alloca (sizeof (rtx) * reg_count);
+  int i;
+  bool src_unaligned = (src_align < BITS_PER_WORD);
+  bool dst_unaligned = (dst_align < BITS_PER_WORD);
+
+  for (i = 0; i < reg_count; i++)
+    regs[i] = gen_reg_rtx (SImode);
+
+  if (src_unaligned)
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
+    }
+  else
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_lw_a (src_reg,
+                                  src_reg, gen_int_mode (4, SImode), regs[i]));
+    }
+
+  if (dst_unaligned)
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
+    }
+  else
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_sw_a (dst_reg,
+                                  dst_reg, gen_int_mode (4, SImode), regs[i]));
+    }
+}
+
+/* Generate loop foot, copy the leftover bytes.  */
+static void
+mdx_block_move_loop_foot (rtx dst_reg, HOST_WIDE_INT dst_align,
+                          rtx src_reg, HOST_WIDE_INT src_align,
+                          HOST_WIDE_INT length)
+{
+  bool src_unaligned = (src_align < BITS_PER_WORD);
+  bool dst_unaligned = (dst_align < BITS_PER_WORD);
+
+  HOST_WIDE_INT leftover;
+
+  leftover = length % UNITS_PER_WORD;
+  length -= leftover;
+
+  if (length > 0)
+    mdx_block_move_loop_body (dst_reg, dst_align,
+                              src_reg, src_align, length);
+
+  if (dst_unaligned)
+    emit_insn (gen_move_sce (dst_reg, dst_reg));
+
+  if (leftover > 0)
+    {
+      HOST_WIDE_INT src_adj = src_unaligned ? -4 : 0;
+      HOST_WIDE_INT dst_adj = dst_unaligned ? -4 : 0;
+      rtx temp;
+
+      gcc_assert (leftover < UNITS_PER_WORD);
+
+      if (leftover >= UNITS_PER_WORD / 2
+          && src_align >= BITS_PER_WORD / 2
+          && dst_align >= BITS_PER_WORD / 2)
+        {
+          temp = gen_reg_rtx (HImode);
+          emit_insn (gen_move_lhu_b (src_reg, src_reg,
+                                     gen_int_mode (src_adj, SImode), temp));
+          emit_insn (gen_move_sh_b (dst_reg, dst_reg,
+                                    gen_int_mode (dst_adj, SImode), temp));
+          leftover -= UNITS_PER_WORD / 2;
+          src_adj = UNITS_PER_WORD / 2;
+          dst_adj = UNITS_PER_WORD / 2;
+        }
+
+      while (leftover > 0)
+        {
+          temp = gen_reg_rtx (QImode);
+          emit_insn (gen_move_lbu_b (src_reg, src_reg,
+                                     gen_int_mode (src_adj, SImode), temp));
+          emit_insn (gen_move_sb_b (dst_reg, dst_reg,
+                                    gen_int_mode (dst_adj, SImode), temp));
+          leftover--;
+          src_adj = 1;
+          dst_adj = 1;
+        }
+    }
+}
+
+#define MIN_MOVE_REGS 3
+#define MIN_MOVE_BYTES (MIN_MOVE_REGS * UNITS_PER_WORD)
+#define MAX_MOVE_REGS 4
+#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
+
+/* The length is large, generate a loop if necessary.
+   The loop is consisted by loop head/body/foot.  */
+static void
+mdx_block_move_loop (rtx dst, rtx src, HOST_WIDE_INT length)
+{
+  HOST_WIDE_INT src_align = MEM_ALIGN (src);
+  HOST_WIDE_INT dst_align = MEM_ALIGN (dst);
+  HOST_WIDE_INT loop_mov_bytes;
+  HOST_WIDE_INT iteration = 0;
+  HOST_WIDE_INT head_length = 0, leftover;
+  rtx label, src_reg, dst_reg, final_dst;
+
+  bool gen_loop_head = (src_align < BITS_PER_WORD
+                        || dst_align < BITS_PER_WORD);
+
+  if (gen_loop_head)
+    head_length += UNITS_PER_WORD;
+
+  for (loop_mov_bytes = MAX_MOVE_BYTES;
+       loop_mov_bytes >= MIN_MOVE_BYTES;
+       loop_mov_bytes -= UNITS_PER_WORD)
+    {
+      iteration = (length - head_length) / loop_mov_bytes;
+      if (iteration > 1)
+        break;
+    }
+  if (iteration <= 1)
+    {
+      mdx_block_move_straight (dst, src, length);
+      return;
+    }
+
+  leftover = (length - head_length) % loop_mov_bytes;
+  length -= leftover;
+
+  src_reg = copy_addr_to_reg (XEXP (src, 0));
+  dst_reg = copy_addr_to_reg (XEXP (dst, 0));
+  final_dst = expand_simple_binop (Pmode, PLUS, dst_reg, GEN_INT (length),
+                                   0, 0, OPTAB_WIDEN);
+
+  if (gen_loop_head)
+    mdx_block_move_loop_head (dst_reg, dst_align,
+                              src_reg, src_align, head_length);
+
+  label = gen_label_rtx ();
+  emit_label (label);
+
+  mdx_block_move_loop_body (dst_reg, dst_align,
+                            src_reg, src_align, loop_mov_bytes);
+
+  emit_insn (gen_cmpsi (dst_reg, final_dst));
+  emit_jump_insn (gen_bne (label));
+
+  mdx_block_move_loop_foot (dst_reg, dst_align,
+                            src_reg, src_align, leftover);
+}
+
+/* Generate block move, for misc.md: "movmemsi".  */
+bool
+mdx_block_move (rtx *ops)
+{
+  rtx dst = ops[0];
+  rtx src = ops[1];
+  rtx length = ops[2];
+
+  if (TARGET_LITTLE_ENDIAN
+      && (MEM_ALIGN (src) < BITS_PER_WORD || MEM_ALIGN (dst) < BITS_PER_WORD)
+      && INTVAL (length) >= UNITS_PER_WORD)
+    return false;
+
+  if (GET_CODE (length) == CONST_INT)
+    {
+      if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
+        {
+           mdx_block_move_straight (dst, src, INTVAL (length));
+           return true;
+        }
+      else if (optimize &&
+               !(flag_unroll_loops || flag_unroll_all_loops))
+        {
+          mdx_block_move_loop (dst, src, INTVAL (length));
+          return true;
+        }
+    }
+  return false;
+}
+
+/* Generate add insn.  */
 const char *
-mdp_add_imm_ucc (rtx *ops)
+mdp_select_add_imm (rtx *ops, bool set_cc)
 {
   HOST_WIDE_INT v = INTVAL (ops[2]);
 
   gcc_assert (GET_CODE (ops[2]) == CONST_INT);
   gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
 
-  if (G16_REG_P (REGNO (ops[0])))
+  if (set_cc && G16_REG_P (REGNO (ops[0])))
     {
-      if (v > 0 && num_bits1 (v) == 1 && IMM_IN_RANGE (ffs (v) - 1, 4, 0))
+      if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
         {
           ops[2] = GEN_INT (ffs (v) - 1);
           return "addei!  %0, %c2";
         }
 
-      if (v < 0 && num_bits1 (-v) == 1 && IMM_IN_RANGE (ffs (-v) - 1, 4, 0))
+      if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
         {
           ops[2] = GEN_INT (ffs (-v) - 1);
           return "subei!  %0, %c2";
         }
     }
+
+  if (set_cc)
     return "addi.c  %0, %c2";
+  else
+    return "addi    %0, %c2";
 }
 
-/* Output arith insn, insn will update condition flag.  */
+/* Output arith insn.  */
 const char *
-mdp_select (rtx *ops, const char *inst_pre, bool commu, const char *let)
+mdp_select (rtx *ops, const char *inst_pre,
+            bool commu, const char *letter, bool set_cc)
 {
   gcc_assert (GET_CODE (ops[0]) == REG);
   gcc_assert (GET_CODE (ops[1]) == REG);
 
-  if (G16_REG_P (REGNO (ops[0]))
+  if (set_cc && G16_REG_P (REGNO (ops[0]))
       && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
       && REGNO (ops[0]) == REGNO (ops[1]))
     {
-      snprintf (ins, INS_BUF_SZ, "%s!        %%0, %%%s2", inst_pre, let);
+      snprintf (ins, INS_BUF_SZ, "%s!  %%0, %%%s2", inst_pre, letter);
       return ins;
     }
 
-  if (commu && G16_REG_P (REGNO (ops[0]))
+  if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
       && G16_REG_P (REGNO (ops[1]))
       && REGNO (ops[0]) == REGNO (ops[2]))
     {
       gcc_assert (GET_CODE (ops[2]) == REG);
-      snprintf (ins, INS_BUF_SZ, "%s!        %%0, %%%s1", inst_pre, let);
+      snprintf (ins, INS_BUF_SZ, "%s!  %%0, %%%s1", inst_pre, letter);
       return ins;
     }
 
-  snprintf (ins, INS_BUF_SZ, "%s.c        %%0, %%1, %%%s2", inst_pre, let);
+  if (set_cc)
+    snprintf (ins, INS_BUF_SZ, "%s.c  %%0, %%1, %%%s2", inst_pre, letter);
+  else
+    snprintf (ins, INS_BUF_SZ, "%s    %%0, %%1, %%%s2", inst_pre, letter);
   return ins;
 }
 
Index: gcc/config/score/score.md
===================================================================
--- gcc/config/score/score.md	(revision 120252)
+++ gcc/config/score/score.md	(working copy)
@@ -59,8 +59,8 @@
 
 (define_constants
    [(BITTST         0)
-    (LOAD_ADD       1)
-    (STORE_ADD      2)
+    (CPLOAD         1)
+    (CPRESTORE      2)
 
     (SCB            3)
     (SCW            4)
@@ -88,10 +88,22 @@
 (include "misc.md")
 (include "mac.md")
 
-(define_insn "movqi"
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand")
+        (match_operand:QI 1 "general_operand"))]
+  ""
+{
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], QImode))
+    {
+      operands[1] = force_reg (QImode, operands[1]);
+    }
+})
+
+(define_insn "*movqi_insns"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a")
         (match_operand:QI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))]
-  ""
+  "!MEM_P (operands[0]) || register_operand (operands[1], QImode)"
 {
   switch (which_alternative)
     {
@@ -109,10 +121,22 @@
   [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr")
    (set_attr "mode" "QI")])
 
-(define_insn "movhi"
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand")
+        (match_operand:HI 1 "general_operand"))]
+  ""
+{
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], HImode))
+    {
+      operands[1] = force_reg (HImode, operands[1]);
+    }
+})
+
+(define_insn "*movhi_insns"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a")
         (match_operand:HI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))]
-  ""
+  "!MEM_P (operands[0]) || register_operand (operands[1], HImode)"
 {
   switch (which_alternative)
     {
@@ -130,11 +154,23 @@
   [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr")
    (set_attr "mode" "HI")])
 
-(define_insn "movsi"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a,d,c")
-        (match_operand:SI 1 "general_operand" "i,d,m,d,*x,d,*a,d,c,d"))]
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand")
+        (match_operand:SI 1 "general_operand"))]
   ""
 {
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], SImode))
+    {
+      operands[1] = force_reg (SImode, operands[1]);
+    }
+})
+
+(define_insn "*movsi_insns"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a,d,*c")
+        (match_operand:SI 1 "general_operand" "i,d,m,d,*x,d,*a,d,*c,d"))]
+  "!MEM_P (operands[0]) || register_operand (operands[1], SImode)"
+{
   switch (which_alternative)
     {
     case 0:
@@ -169,46 +205,103 @@
   DONE;
 })
 
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand")
+        (match_operand:SF 1 "general_operand"))]
+  ""
+{
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], SFmode))
+    {
+      operands[1] = force_reg (SFmode, operands[1]);
+    }
+})
+
+(define_insn "*movsf_insns"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,m")
+        (match_operand:SF 1 "general_operand" "i,d,m,d"))]
+  "!MEM_P (operands[0]) || register_operand (operands[1], SFmode)"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"li      %0, %D1\";;
+    case 1: return mdp_move (operands);
+    case 2: return mdp_linsn (operands, MDA_WORD, false);
+    case 3: return mdp_sinsn (operands, MDA_WORD);
+    default: gcc_unreachable ();
+    }
+}
+  [(set_attr "type" "arith,move,load,store")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "movdf"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,m")
+        (match_operand:DF 1 "general_operand" "i,d,m,d"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  mds_movdi (operands);
+  DONE;
+})
+
 (define_insn "addsi3"
-  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
-        (plus:SI (match_operand:SI 1 "register_operand" "0,d,%d")
-                 (match_operand:SI 2 "arith_operand" "L,N,d")))]
+  [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
+                 (match_operand:SI 2 "arith_operand" "I,L,N,d")))]
   ""
-  "@
-   addi    %0, %c2
-   addri   %0, %1, %c2
-   add     %0, %1, %2"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"addis %0, %U2\";
+    case 1: return mdp_select_add_imm (operands, false);
+    case 2: return \"addri %0, %1, %c2\";
+    case 3: return mdp_select (operands, "add", true, "", false);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "*addsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (plus:SI (match_operand:SI 0 "register_operand" "d,d,d")
-                                (match_operand:SI 1 "arith_operand" "N,L,d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (plus:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,L,N,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d,d,d"))]
   ""
-  "@
-   %[       addri.c r1, %0, %c1       %]
-   %[       m%V0    r1, %0\;addi.c  r1, %2        %]
-   %[       add.c   r1, %0, %1        %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"addis.c %0, %U2\";
+    case 1: return mdp_select_add_imm (operands, true);
+    case 2: return \"addri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "add", true, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "addsi3_ucc"
+(define_insn "*addsi3_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
-                                (match_operand:SI 2 "arith_operand" "L,N,d"))
+        (compare:CC_NZ (plus:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,L,N,d"))
                        (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d,d,d")
+   (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (plus:SI (match_dup 1) (match_dup 2)))]
   ""
 {
   switch (which_alternative)
     {
-    case 0: return mdp_add_imm_ucc (operands);
-    case 1: return \"addri.c %0, %1, %c2\";
-    case 2: return mdp_select (operands, "add", true, "");
+    case 0: return \"addis.c %0, %U2\";
+    case 1: return mdp_select_add_imm (operands, true);
+    case 2: return \"addri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "add", true, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -217,9 +310,9 @@
    (set_attr "mode" "SI")])
 
 (define_insn "adddi3"
-  [(set (match_operand:DI 0 "register_operand" "=*e,d")
-        (plus:DI (match_operand:DI 1 "register_operand" "*0,d")
-                 (match_operand:DI 2 "register_operand" "*e,d")))
+  [(set (match_operand:DI 0 "register_operand" "=e,d")
+        (plus:DI (match_operand:DI 1 "register_operand" "0,d")
+                 (match_operand:DI 2 "register_operand" "e,d")))
   (clobber (reg:CC CC_REGNUM))]
   ""
   "@
@@ -233,17 +326,22 @@
         (minus:SI (match_operand:SI 1 "register_operand" "d")
                   (match_operand:SI 2 "register_operand" "d")))]
   ""
-  "sub     %0, %1, %2"
+{
+  return mdp_select (operands, "sub", false, "", false);
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "*subsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (minus:SI (match_operand:SI 0 "register_operand" "d")
-                                 (match_operand:SI 1 "register_operand" "d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "d")
+                                 (match_operand:SI 2 "register_operand" "d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
-  "%[        sub.c   r1, %0, %1        %]"
+{
+  return mdp_select (operands, "sub", false, "", true);
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -255,11 +353,10 @@
    (set (reg:CC CC_REGNUM)
         (compare:CC (match_dup 1) (match_dup 2)))]
   ""
-  [(parallel
-       [(set (reg:CC CC_REGNUM)
-             (compare:CC (match_dup 1) (match_dup 2)))
-        (set (match_dup 0)
-             (minus:SI (match_dup 1) (match_dup 2)))])])
+  [(set (reg:CC CC_REGNUM)
+        (compare:CC (match_dup 1) (match_dup 2)))
+   (set (match_dup 0)
+        (minus:SI (match_dup 1) (match_dup 2)))])
 
 (define_insn "subsi3_ucc_pcmp"
   [(parallel
@@ -270,7 +367,7 @@
              (minus:SI (match_dup 1) (match_dup 2)))])]
   ""
 {
-  return mdp_select (operands, "sub", false, "");
+  return mdp_select (operands, "sub", false, "", true);
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
@@ -285,16 +382,16 @@
         (minus:SI (match_dup 1) (match_dup 2)))]
   ""
 {
-  return mdp_select (operands, "sub", false, "");
+  return mdp_select (operands, "sub", false, "", true);
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
 (define_insn "subdi3"
-  [(set (match_operand:DI 0 "register_operand" "=*e,d")
-        (minus:DI (match_operand:DI 1 "register_operand" "*0,d")
-                  (match_operand:DI 2 "register_operand" "*e,d")))
+  [(set (match_operand:DI 0 "register_operand" "=e,d")
+        (minus:DI (match_operand:DI 1 "register_operand" "0,d")
+                  (match_operand:DI 2 "register_operand" "e,d")))
    (clobber (reg:CC CC_REGNUM))]
   ""
   "@
@@ -306,36 +403,47 @@
 (define_insn "andsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (and:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
-                (match_operand:SI 2 "arith_operand" "K,Q,M,d")))]
+                (match_operand:SI 2 "arith_operand" "I,K,M,d")))]
   ""
-  "@
-   andi    %0, %c2
-   andis   %0, %U2
-   andri   %0, %1, %c2
-   and     %0, %1, %2"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"andis %0, %U2\";
+    case 1: return \"andi  %0, %c2";
+    case 2: return \"andri %0, %1, %c2\";
+    case 3: return mdp_select (operands, "and", true, "", false);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "andsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (and:SI (match_operand:SI 0 "register_operand" "d,d,d,d")
-                               (match_operand:SI 1 "arith_operand" "M,K,Q,d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (and:SI (match_operand:SI 1 "register_operand" "0,0,0,d")
+                               (match_operand:SI 2 "arith_operand" "I,K,M,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d,d,d"))]
   ""
-  "@
-   %[        andri.c r1, %0, %c1      %]
-   %[        m%V0    r1, %0\;andi.c  r1, %c1        %]
-   %[        m%V0    r1, %0\;andis.c r1, %U1        %]
-   %[        and.c   r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"andis.c %0, %U2\";
+    case 1: return \"andi.c  %0, %c2";
+    case 2: return \"andri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "and", true, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "andsi3_ucc"
+(define_insn "*andsi3_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (and:SI
                         (match_operand:SI 1 "register_operand" "0,0,d,d")
-                        (match_operand:SI 2 "arith_operand" "K,Q,M,d"))
+                        (match_operand:SI 2 "arith_operand" "I,K,M,d"))
                        (const_int 0)))
    (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (and:SI (match_dup 1) (match_dup 2)))]
@@ -343,10 +451,10 @@
 {
   switch (which_alternative)
     {
-    case 0:  return \"andi.c  %0, %c2\";
-    case 1:  return \"andis.c %0, %U2\";
-    case 2:  return \"andri.c %0, %1, %c2\";
-    case 3:  return mdp_select (operands, "and", true, "");
+    case 0: return \"andis.c %0, %U2\";
+    case 1: return \"andi.c  %0, %c2";
+    case 2: return \"andri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "and", true, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -355,12 +463,12 @@
    (set_attr "mode" "SI")])
 
 (define_insn_and_split "*zero_extract_andi"
-  [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (zero_extract:SI
-                        (match_operand:SI 0 "register_operand" "d")
-                        (match_operand:SI 1 "const_bi_operand" "")
-                        (match_operand:SI 2 "const_bi_operand" ""))
-                       (const_int 0)))]
+  [(set (reg:CC CC_REGNUM)
+        (compare:CC (zero_extract:SI
+                     (match_operand:SI 0 "register_operand" "d")
+                     (match_operand:SI 1 "const_uimm5" "")
+                     (match_operand:SI 2 "const_uimm5" ""))
+                    (const_int 0)))]
   ""
   "#"
   ""
@@ -373,26 +481,39 @@
 (define_insn "iorsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (ior:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
-                (match_operand:SI 2 "arith_operand" "K,Q,M,d")))]
+                (match_operand:SI 2 "arith_operand" "I,K,M,d")))]
   ""
-  "@
-   ori     %0, %c2
-   oris    %0, %U2
-   orri    %0, %1, %c2
-   or      %0, %1, %2"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"oris %0, %U2\";
+    case 1: return \"ori  %0, %c2\";
+    case 2: return \"orri %0, %1, %c2\";
+    case 3: return mdp_select (operands, "or", true, "", false);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "iorsi3_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (ior:SI (match_operand:SI 1 "register_operand" "d")
-                               (match_operand:SI 2 "register_operand" "d"))
+        (compare:CC_NZ (ior:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,K,M,d"))
                        (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d")
+   (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (ior:SI (match_dup 1) (match_dup 2)))]
   ""
 {
-  return mdp_select (operands, "or", true, "");
+  switch (which_alternative)
+    {
+    case 0: return \"oris.c %0, %U2\";
+    case 1: return \"ori.c  %0, %c2\";
+    case 2: return \"orri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "or", true, "", true);
+    default: gcc_unreachable ();
+    }
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
@@ -400,11 +521,22 @@
 
 (define_insn "iorsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (ior:SI (match_operand:SI 0 "register_operand" "d")
-                               (match_operand:SI 1 "register_operand" "d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (ior:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,K,M,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d,d,d"))]
   ""
-  "%[        or.c    r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"oris.c %0, %U2\";
+    case 1: return \"ori.c  %0, %c2\";
+    case 2: return \"orri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "or", true, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -414,7 +546,9 @@
         (xor:SI (match_operand:SI 1 "register_operand" "d")
                 (match_operand:SI 2 "register_operand" "d")))]
   ""
-  "xor     %0, %1, %2"
+{
+  return mdp_select (operands, "xor", true, "", false);
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
@@ -427,7 +561,7 @@
         (xor:SI (match_dup 1) (match_dup 2)))]
   ""
 {
-  return mdp_select (operands, "xor", true, "");
+  return mdp_select (operands, "xor", true, "", true);
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
@@ -435,11 +569,14 @@
 
 (define_insn "xorsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (xor:SI (match_operand:SI 0 "register_operand" "d")
-                               (match_operand:SI 1 "register_operand" "d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (xor:SI (match_operand:SI 1 "register_operand" "d")
+                               (match_operand:SI 2 "register_operand" "d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
-  "%[        xor.c   r1, %0, %1       %]"
+{
+  return mdp_select (operands, "xor", true, "", true);
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -459,49 +596,35 @@
   [(set_attr "type" "arith,load")
    (set_attr "mode" "SI")])
 
-(define_insn "extendqisi2_cmp"
+(define_insn "*extendqisi2_ucc"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
-                       (ashift:SI (match_operand:SI 0 "register_operand" "d")
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 24))
                        (const_int 24))
-                      (const_int 0)))]
+                      (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d")
+        (sign_extend:SI (match_operand:QI 2 "register_operand" "0")))]
   ""
-  "%[        extsb.c r1, %0       %]"
+  "extsb.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "extendqisi2_ucc"
+(define_insn "*extendqisi2_cmp"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
                        (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 24))
                        (const_int 24))
                       (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d")
-        (sign_extend:SI (match_operand:QI 2 "register_operand" "0")))]
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
   "extsb.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "zero_extendqisi2"
-  [(set (match_operand:SI 0 "register_operand""=d,d")
-        (zero_extend:SI (match_operand:QI 1 "register_operand" "d,m")))]
-  ""
-{
-  switch (which_alternative)
-    {
-    case 0: return \"extzb   %0, %1\";
-    case 1: return mdp_linsn (operands, MDA_BYTE, false);
-    default: gcc_unreachable ();
-    }
-}
-  [(set_attr "type" "arith, load")
-   (set_attr "mode" "SI")])
-
 (define_insn "extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
@@ -517,34 +640,79 @@
   [(set_attr "type" "arith, load")
    (set_attr "mode" "SI")])
 
-(define_insn "extendhisi2_cmp"
+(define_insn "*extendhisi2_ucc"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
-                       (ashift:SI (match_operand:SI 0 "register_operand" "d")
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 16))
                        (const_int 16))
-                      (const_int 0)))]
+                      (const_int 0)))
+  (set (match_operand:SI 0 "register_operand" "=d")
+       (sign_extend:SI (match_operand:HI 2 "register_operand" "0")))]
   ""
-  "%[        extsh.c r1, %0       %]"
+  "extsh.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "extendhisi2_ucc"
+(define_insn "*extendhisi2_cmp"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
                        (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 16))
                        (const_int 16))
                       (const_int 0)))
-  (set (match_operand:SI 0 "register_operand" "=d")
-       (sign_extend:SI (match_operand:HI 2 "register_operand" "0")))]
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
   "extsh.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=d,d")
+        (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
+  ""
+{
+  switch (which_alternative)
+    {
+    case 0: return \"extzb   %0, %1\";
+    case 1: return mdp_linsn (operands, MDA_BYTE, false);
+    default: gcc_unreachable ();
+    }
+  }
+  [(set_attr "type" "arith, load")
+   (set_attr "mode" "SI")])
+
+(define_insn "*zero_extendqisi2_ucc"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 24))
+                       (const_int 24))
+                      (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d")
+        (zero_extend:SI (match_operand:QI 2 "register_operand" "0")))]
+  ""
+  "extzb.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
+(define_insn "*zero_extendqisi2_cmp"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 24))
+                       (const_int 24))
+                      (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
+  ""
+  "extzb.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
 (define_insn "zero_extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
@@ -560,6 +728,35 @@
   [(set_attr "type" "arith, load")
    (set_attr "mode" "SI")])
 
+(define_insn "*zero_extendhisi2_ucc"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 16))
+                       (const_int 16))
+                      (const_int 0)))
+  (set (match_operand:SI 0 "register_operand" "=d")
+       (zero_extend:SI (match_operand:HI 2 "register_operand" "0")))]
+  ""
+  "extzh.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
+(define_insn "*zero_extendhisi2_cmp"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 16))
+                       (const_int 16))
+                      (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
+  ""
+  "extzh.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand" "=l")
         (mult:SI (match_operand:SI 1 "register_operand" "d")
@@ -572,7 +769,8 @@
 
 (define_insn "mulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=x")
-        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
+        (mult:DI (sign_extend:DI
+                  (match_operand:SI 1 "register_operand" "d"))
                  (sign_extend:DI
                   (match_operand:SI 2 "register_operand" "d"))))]
   "!TARGET_SCORE5U"
@@ -582,7 +780,8 @@
 
 (define_insn "umulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=x")
-        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+        (mult:DI (zero_extend:DI
+                  (match_operand:SI 1 "register_operand" "d"))
                  (zero_extend:DI
                   (match_operand:SI 2 "register_operand" "d"))))]
   "!TARGET_SCORE5U"
@@ -635,8 +834,8 @@
 {
   switch (which_alternative)
     {
-    case 0: return mdp_select (operands, "slli", false, "c");
-    case 1: return mdp_select (operands, "sll", false, "");
+    case 0: return mdp_select (operands, "slli", false, "c", true);
+    case 1: return mdp_select (operands, "sll", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -647,13 +846,19 @@
 (define_insn "ashlsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (ashift:SI
-                        (match_operand:SI 0 "register_operand" "d,d")
-                        (match_operand:SI 1 "arith_operand" "J,d"))
-                       (const_int 0)))]
+                        (match_operand:SI 1 "register_operand" "d,d")
+                        (match_operand:SI 2 "arith_operand" "J,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d"))]
   ""
-  "@
-   %[        slli.c  r1, %0, %c1      %]
-   %[        sll.c   r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return mdp_select (operands, "slli", false, "c", true);
+    case 1: return mdp_select (operands, "sll", false, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -682,7 +887,7 @@
   switch (which_alternative)
     {
     case 0: return \"srai.c  %0, %1, %c2\";
-    case 1: return mdp_select (operands, "sra", false, "");
+    case 1: return mdp_select (operands, "sra", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -693,31 +898,16 @@
 (define_insn "ashrsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (ashiftrt:SI
-                        (match_operand:SI 0 "register_operand" "d,d")
-                        (match_operand:SI 1 "arith_operand" "J,d"))
-                       (const_int 0)))]
-  ""
-  "@
-   %[        srai.c  r1, %0, %c1      %]
-   %[        sra.c   r1, %0, %1       %]"
-  [(set_attr "type" "arith")
-   (set_attr "up_c" "yes")
-   (set_attr "mode" "SI")])
-
-(define_insn "ashrsi3_ucc_n"
-  [(set (reg:CC_N CC_REGNUM)
-        (compare:CC_N (ashiftrt:SI
-                       (match_operand:SI 1 "register_operand" "d,d")
-                       (match_operand:SI 2 "arith_operand" "J,d"))
-                      (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d,d")
-        (ashiftrt:SI (match_dup 1) (match_dup 2)))]
+                        (match_operand:SI 1 "register_operand" "d,d")
+                        (match_operand:SI 2 "arith_operand" "J,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d"))]
   ""
 {
   switch (which_alternative)
     {
     case 0: return \"srai.c  %0, %1, %c2\";
-    case 1: return mdp_select (operands, "sra", false, "");
+    case 1: return mdp_select (operands, "sra", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -725,20 +915,6 @@
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "ashrsi3_cmp_n"
-  [(set (reg:CC_N CC_REGNUM)
-        (compare:CC_N (ashiftrt:SI
-                       (match_operand:SI 0 "register_operand" "d,d")
-                       (match_operand:SI 1 "arith_operand" "J,d"))
-                      (const_int 0)))]
-  ""
-  "@
-   %[        srai.c  r1, %0, %c1      %]
-   %[        sra.c   r1, %0, %1       %]"
-  [(set_attr "type" "arith")
-   (set_attr "up_c" "yes")
-   (set_attr "mode" "SI")])
-
 (define_insn "lshrsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
@@ -762,8 +938,8 @@
 {
   switch (which_alternative)
     {
-    case 0: return mdp_select (operands, "srli", false, "c");
-    case 1: return mdp_select (operands, "srl", false, "");
+    case 0: return mdp_select (operands, "srli", false, "c", true);
+    case 1: return mdp_select (operands, "srl", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -774,13 +950,19 @@
 (define_insn "lshrsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (lshiftrt:SI
-                        (match_operand:SI 0 "register_operand" "d,d")
-                        (match_operand:SI 1 "arith_operand" "J,d"))
-                       (const_int 0)))]
+                        (match_operand:SI 1 "register_operand" "d,d")
+                        (match_operand:SI 2 "arith_operand" "J,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d"))]
   ""
-  "@
-   %[        srli.c  r1, %0, %c1      %]
-   %[        srl.c   r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return mdp_select (operands, "srli", false, "c", true);
+    case 1: return mdp_select (operands, "srl", false, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -793,11 +975,24 @@
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
+(define_insn "*negsi2_cmp"
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ (neg:SI (match_operand:SI 1 "register_operand" "e,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=e,d"))]
+  ""
+  "@
+   neg!    %0, %1
+   neg.c   %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
 (define_insn "negsi2_ucc"
-  [(set (reg:CC CC_REGNUM)
-        (compare:CC (neg:SI (match_operand:SI 1 "register_operand" "*e,d"))
-                    (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=*e,d")
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ (neg:SI (match_operand:SI 1 "register_operand" "e,d"))
+                       (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=e,d")
         (neg:SI (match_dup 1)))]
   ""
   "@
@@ -817,9 +1012,9 @@
 
 (define_insn "one_cmplsi2_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "*e,d"))
+        (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "e,d"))
                        (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=*e,d")
+   (set (match_operand:SI 0 "register_operand" "=e,d")
         (not:SI (match_dup 1)))]
   ""
   "@
@@ -831,12 +1026,13 @@
 
 (define_insn "one_cmplsi2_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (not:SI (match_operand:SI 0 "register_operand" "*e,d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "e,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=e,d"))]
   ""
   "@
-   %[        not!    r1, %0       %]
-   %[        not.c   r1, %0       %]"
+   not!    %0, %1
+   not.c   %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -877,8 +1073,8 @@
 
 (define_insn "cmpsi_nz"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (match_operand:SI 0 "register_operand" "d,*e,d")
-                       (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+        (compare:CC_NZ (match_operand:SI 0 "register_operand" "d,e,d")
+                       (match_operand:SI 1 "arith_operand" "L,e,d")))]
   ""
   "@
    cmpi.c  %0, %c1
@@ -890,8 +1086,8 @@
 
 (define_insn "cmpsi_n"
   [(set (reg:CC_N CC_REGNUM)
-        (compare:CC_N (match_operand:SI 0 "register_operand" "d,*e,d")
-                      (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+        (compare:CC_N (match_operand:SI 0 "register_operand" "d,e,d")
+                      (match_operand:SI 1 "arith_operand" "L,e,d")))]
   ""
   "@
    cmpi.c  %0, %c1
@@ -901,10 +1097,23 @@
     (set_attr "up_c" "yes")
     (set_attr "mode" "SI")])
 
+(define_insn "*cmpsi_to_addsi"
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ (match_operand:SI 1 "register_operand" "0,d")
+                       (neg:SI (match_operand:SI 2 "register_operand" "e,d"))))
+   (clobber (match_scratch:SI 0 "=e,d"))]
+  ""
+  "@
+   add!    %0, %2
+   add.c   %0, %1, %2"
+   [(set_attr "type" "cmp")
+    (set_attr "up_c" "yes")
+    (set_attr "mode" "SI")])
+
 (define_insn "cmpsi_cc"
   [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_operand:SI 0 "register_operand" "d,*e,d")
-                    (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+        (compare:CC (match_operand:SI 0 "register_operand" "d,e,d")
+                    (match_operand:SI 1 "arith_operand" "L,e,d")))]
   ""
   "@
    cmpi.c  %0, %c1
@@ -1078,17 +1287,17 @@
    (clobber (reg:SI RT_REGNUM))]
   "SIBLING_CALL_P (insn)"
 {
-  if (!flag_pic) 
-    switch (which_alternative) 
+  if (!flag_pic)
+    switch (which_alternative)
       {
       case 0: return \"br%S0   %0\";
       case 1: return \"j       %0\";
       default: gcc_unreachable ();
       }
   else
-    switch (which_alternative) 
+    switch (which_alternative)
       {
-      case 0: return \"mv      r29, %0\;.cpadd  r29\;br      r29\";
+      case 0: return \"mv      r29, %0\;br      r29\";
       case 1: return \"la      r29, %0\;br      r29\";
       default: gcc_unreachable ();
       }
@@ -1112,17 +1321,17 @@
    (clobber (reg:SI RT_REGNUM))]
   "SIBLING_CALL_P (insn)"
 {
-  if (!flag_pic) 
-    switch (which_alternative) 
+  if (!flag_pic)
+    switch (which_alternative)
       {
       case 0: return \"br%S1   %1\";
       case 1: return \"j       %1\";
       default: gcc_unreachable ();
       }
   else
-    switch (which_alternative) 
+    switch (which_alternative)
       {
-      case 0: return \"mv      r29, %1\;.cpadd  r29\;br      r29\";
+      case 0: return \"mv      r29, %1\;br      r29\";
       case 1: return \"la      r29, %1\;br      r29\";
       default: gcc_unreachable ();
       }
@@ -1154,7 +1363,7 @@
   else
      switch (which_alternative)
       {
-      case 0: return \"mv      r29, %0\;.cpadd  r29\;brl     r29\";
+      case 0: return \"mv      r29, %0\;brl     r29\";
       case 1: return \"la      r29, %0\;brl     r29\";
       default: gcc_unreachable ();
       }
@@ -1163,7 +1372,7 @@
 
 (define_expand "call_value"
   [(parallel [(set (match_operand 0 "" "")
-              (call (match_operand 1 "" "") (match_operand 2 "" "")))
+                   (call (match_operand 1 "" "") (match_operand 2 "" "")))
               (use (match_operand 3 "" ""))])]
   ""
 {
@@ -1188,7 +1397,7 @@
   else
     switch (which_alternative)
       {
-      case 0: return \"mv      r29, %1\;.cpadd  r29\;brl     r29\";
+      case 0: return \"mv      r29, %1\;brl     r29\";
       case 1: return \"la      r29, %1\;brl     r29\";
       default: gcc_unreachable ();
       }
@@ -1277,13 +1486,59 @@
 )
 
 (define_insn "cpload"
-  [(unspec:SI [(const_int 1)] 1)]
+  [(unspec_volatile:SI [(const_int 1)] CPLOAD)]
   "flag_pic"
   ".cpload r29"
 )
 
-(define_insn "cprestore"
-  [(unspec:SI [(match_operand:SI 0 "" "")] 2)]
+(define_insn "cprestore_use_fp"
+  [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE)
+   (use (reg:SI FP_REGNUM))]
   "flag_pic"
-  ".cprestore %0"
+  ".cprestore r2, %0"
 )
+
+(define_insn "cprestore_use_sp"
+  [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE)
+   (use (reg:SI SP_REGNUM))]
+  "flag_pic"
+  ".cprestore r0, %0"
+)
+
+(define_expand "doloop_end"
+  [(use (match_operand 0 "" ""))    ; loop pseudo
+   (use (match_operand 1 "" ""))    ; iterations; zero if unknown
+   (use (match_operand 2 "" ""))    ; max iterations
+   (use (match_operand 3 "" ""))    ; loop level
+   (use (match_operand 4 "" ""))]   ; label
+  ""
+  {
+    if (INTVAL (operands[3]) > 1)
+      FAIL;
+
+    if (GET_MODE (operands[0]) == SImode)
+      {
+        rtx sr0 = gen_rtx_REG (SImode, CN_REGNUM);
+        emit_jump_insn (gen_doloop_end_si (sr0, operands[4]));
+      }
+    else
+      FAIL;
+
+    DONE;
+  })
+
+(define_insn "doloop_end_si"
+  [(set (pc)
+        (if_then_else
+         (ne (match_operand:SI 0 "sr0_operand" "")
+             (const_int 0))
+         (label_ref (match_operand 1 "" ""))
+         (pc)))
+   (set (match_dup 0)
+        (plus:SI (match_dup 0)
+                 (const_int -1)))
+   (clobber (reg:CC CC_REGNUM))
+]
+  ""
+  "bcnz %1"
+  [(set_attr "type" "branch")])
Index: gcc/config/score/score-modes.def
===================================================================
--- gcc/config/score/score-modes.def	(revision 120252)
+++ gcc/config/score/score-modes.def	(working copy)
@@ -21,6 +21,5 @@
 /* CC_NZmode should be used if the N (sign) and Z (zero) flag is set correctly.
    CC_Nmode should be used if only the N flag is set correctly.  */
 
-CC_MODE (CC_NZ);
 CC_MODE (CC_N);
-
+CC_MODE (CC_NZ);
Index: gcc/config/score/score-mdaux.h
===================================================================
--- gcc/config/score/score-mdaux.h	(revision 120252)
+++ gcc/config/score/score-mdaux.h	(working copy)
@@ -69,8 +69,6 @@ void mda_gen_cmp (enum machine_mode mode
 
 int mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type);
 
-bool mda_pindex_mem (rtx addr);
-
 int mda_bp (void);
 
 /* Machine Expand.  */
@@ -87,8 +85,6 @@ void mdx_call_value (rtx *ops, bool sibc
 /* Machine Split.  */
 void mds_movdi (rtx *ops);
 
-void mds_addsi (rtx *ops);
-
 void mds_zero_extract_andi (rtx *ops);
 
 /* Machine Print.  */
@@ -100,14 +96,21 @@ const char * mdp_linsn (rtx *ops, enum m
 
 const char * mdp_sinsn (rtx *ops, enum mda_mem_unit unit);
 
-const char * mdp_add_imm_ucc (rtx *ops);
+const char * mdp_select_add_imm (rtx *ops, bool set_cc);
 
 const char * mdp_select (rtx *ops, const char *inst_pre,
-                        bool comu, const char *let);
+                        bool commu, const char *letter, bool set_cc);
 
 const char * mdp_limm (rtx *ops);
 
 const char * mdp_move (rtx *ops);
 
+/* Machine unaligned memory load/store. */
+bool mdx_unaligned_load (rtx* ops);
+
+bool mdx_unaligned_store (rtx* ops);
+
+bool mdx_block_move (rtx* ops);
+
 #endif
 
Index: gcc/config/score/mul-div.S
===================================================================
--- gcc/config/score/mul-div.S	(revision 120252)
+++ gcc/config/score/mul-div.S	(working copy)
@@ -242,7 +242,7 @@ _flush_cache:
         #nop!
         addi    r8, 16
         bcnz    2b
-        .cprestore      12              # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      r3
 #endif
@@ -278,7 +278,7 @@ __mulsi3_loop2:
         cmpi.c  a1, 0
         bne     __mulsi3_loop
         mv      r4, t1
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      ra
         .end    __mulsi3
@@ -334,7 +334,7 @@ __uds_loop3:
 __uds_exit:
         mv      a1, a0
         mv      r4, t4
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      ra
         .end    __udivsi3
@@ -350,7 +350,7 @@ __umodsi3:
         la      r29, __udivsi3
         brl     r29
         mv      r4, a1
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      t3
         .end    __umodsi3
@@ -383,7 +383,7 @@ __divsi3_adjust:
         bge     __divsi3_exit
         neg     r4, r4
 __divsi3_exit:
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      t3
         .end    __divsi3

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix _Unwind_Context backward compatibility issues
  2006-12-28 20:46 [PATCH] Fix _Unwind_Context backward compatibility issues Jakub Jelinek
  2006-12-29  6:54 ` [PATCH]: for Score backend liqin
@ 2007-01-03 18:07 ` Richard Henderson
  1 sibling, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2007-01-03 18:07 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Thu, Dec 28, 2006 at 03:40:41PM -0500, Jakub Jelinek wrote:
> Perhaps to be even more compatible even with older GCC 4.2 (plus
> all the 4.1 branches where this has been backported) unwinders,
> _Unwind_Context could be...

I'm ok with the first patch, where this is not done.  While you're
preserving the layout in the second patch, you're not preserving
the values stuck into, or read from, those fields.

Really, this is all being done to cater to A Well Known Commercial
Program, whose authors ought to be hit with a clue bat.  You've
done an admirable job working around their brokenness.  I think it
would be a bit over the top to try to really preserve the field 
values as the second patch would have to do.  Particularly since
this doesn't seem to be necessary for a known case.



r~

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH]: for Score backend
  2006-12-29  6:54 ` [PATCH]: for Score backend liqin
@ 2007-01-04  1:30   ` liqin
  2007-01-08  4:53     ` liqin
  0 siblings, 1 reply; 5+ messages in thread
From: liqin @ 2007-01-04  1:30 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1601 bytes --]

Can I commit this patch to gcc-4.2.0/gcc-trunk repository,
because I had put it here for one week, and not get
any response.




Rgds
Liqin

gcc-patches-owner@gcc.gnu.org 写于 2006-12-29 14:53:32:

> Hi,
> this patch did many changes for Score backend.
> 
> Changelog:
>         * config/score/predicates.md (const_uimm5, sr0_operand, 
> const_simm12,
>         const_simm15, const_pow2, const_npow2): Added.
>         * config/score/misc.md (insv, extv, extzv, movmemsi, 
>         move_lbu_a/b, mov_lhu_a/b etc): Added and fix some bug.
>         * config/score/score.c (score_address_cost, 
score_select_cc_mode): 
> 
>         Added.
>         Change CONST_OK_FOR_LETTER_P/EXTRA_CONSTRAINT define.
>         Update score_rtx_costs for MACRO TARGET_RTX_COSTS.
>        Update score_print_operand.
>         * config/score/score.h (DATA_ALIGNMENT, SELECT_CC_MODE): Added.
>         Adjust register allocate order and update some macro define.
>         * config/score/score-mdaux.c (mdx_unaligned_load, 
> mdx_unsigned_store,
>         mdx_block_move_straight, mdx_block_move_loop_head, 
> mdx_block_move_loop_body,
>         mdx_block_move_loop_foot, mdx_block_move_loop  mdx_block_move):
>         Added.
>         (mdx_movsicc, mdp_select_add_imm, mdp_select, 
> mds_zero_extract_andi, mdp_limm):
>         Updated and fix some bug and typo.
>         * config/score/score.md (movqi/hi/si, add/sub/zero/ext): 
Updated.
>         (movsf, movdf, doloop_end): Added.
>         * config/score/t-score-elf (MULTILIB_OPTIONS): Change.
> 
> Rgds
> Liqin


[-- Attachment #2: score-20061229.patch --]
[-- Type: application/octet-stream, Size: 99711 bytes --]

Index: gcc/config/score/t-score-elf
===================================================================
--- gcc/config/score/t-score-elf	(revision 120252)
+++ gcc/config/score/t-score-elf	(working copy)
@@ -35,7 +35,7 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
 # without the $gp register.
 TARGET_LIBGCC2_CFLAGS = -G 0
 
-MULTILIB_OPTIONS = fPIC mel mscore7
+MULTILIB_OPTIONS = mmac mel fPIC
 MULTILIB_MATCHES = fPIC=fpic
 
 EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
@@ -43,4 +43,3 @@ EXTRA_MULTILIB_PARTS = crtbegin.o crtend
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
 
-
Index: gcc/config/score/crti.asm
===================================================================
--- gcc/config/score/crti.asm	(revision 120252)
+++ gcc/config/score/crti.asm	(working copy)
@@ -43,8 +43,8 @@
         .mask   0x00000000, 0
 _start:
         la      r28, _gp
-        la      r8, __bss_start
-        la      r9, __bss_end__
+        la      r8, _bss_start
+        la      r9, _bss_end__
         sub!    r9, r8
         srli!   r9, 2
         addi    r9, -1
@@ -91,8 +91,8 @@ _fini:
         .mask   0x00000000,0
 _start:
         la      r28, _gp
-        la      r8, __bss_start
-        la      r9, __bss_end__
+        la      r8, _bss_start
+        la      r9, _bss_end__
         sub!    r9, r8
         srli!   r9, 2
         addi    r9, -1
@@ -102,15 +102,10 @@ _start:
         sw      r9, [r8]+, 4
         bcnz    1b
         la      r0, _stack
-#       jl      _init
-#       la      r4, _end
-#       jl      _init_argv
         ldiu!   r4, 0
         ldiu!   r5, 0
-#       jl      main
         la      r29, main
         brl     r29
-#       jl      exit
         la      r29, exit
         brl     r29
         .end    _start
Index: gcc/config/score/predicates.md
===================================================================
--- gcc/config/score/predicates.md	(revision 120252)
+++ gcc/config/score/predicates.md	(working copy)
@@ -35,13 +35,11 @@
   (ior (match_operand 0 "const_call_insn_operand")
        (match_operand 0 "register_operand")))
 
-(define_predicate "const_bi_operand"
-  (and (match_code "const_int")
-       (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'J')")))
-
-(define_predicate "pindex_off_operand"
-  (and (match_code "const_int")
-       (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'P')")))
+(define_predicate "const_uimm5"
+  (match_code "const_int")
+{
+  return IMM_IN_RANGE (INTVAL (op), 5, 0);
+})
 
 (define_predicate "hireg_operand"
   (and (match_code "reg")
@@ -51,6 +49,10 @@
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
 
+(define_predicate "sr0_operand"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == CN_REGNUM")))
+
 (define_predicate "g32reg_operand"
   (and (match_code "reg")
        (match_test "GP_REG_P (REGNO (op))")))
@@ -61,3 +63,26 @@
 (define_predicate "branch_nz_operator"
   (match_code "eq,ne,lt,ge"))
 
+(define_predicate "const_simm12"
+  (match_code "const_int")
+{
+  return IMM_IN_RANGE (INTVAL (op), 12, 1);
+})
+
+(define_predicate "const_simm15"
+  (match_code "const_int")
+{
+  return IMM_IN_RANGE (INTVAL (op), 15, 1);
+})
+
+(define_predicate "const_pow2"
+  (match_code "const_int")
+{
+  return IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) INTVAL (op), 0, 31);
+})
+
+(define_predicate "const_npow2"
+  (match_code "const_int")
+{
+  return IMM_IS_POW_OF_2 (~(unsigned HOST_WIDE_INT) INTVAL (op), 0, 31);
+})
Index: gcc/config/score/score-version.h
===================================================================
--- gcc/config/score/score-version.h	(revision 120252)
+++ gcc/config/score/score-version.h	(working copy)
@@ -18,4 +18,4 @@
    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.  */
 
-#define SCORE_GCC_VERSION "1.1"
+#define SCORE_GCC_VERSION "1.2"
Index: gcc/config/score/crtn.asm
===================================================================
--- gcc/config/score/crtn.asm	(revision 120252)
+++ gcc/config/score/crtn.asm	(working copy)
@@ -59,4 +59,3 @@
         br      r3
 #endif
 
-
Index: gcc/config/score/score-protos.h
===================================================================
--- gcc/config/score/score-protos.h	(revision 120252)
+++ gcc/config/score/score-protos.h	(working copy)
@@ -36,7 +36,7 @@ enum reg_class score_preferred_reload_cl
 enum reg_class score_secondary_reload_class (enum reg_class class,
                                              enum machine_mode mode, rtx x);
 
-int score_const_ok_for_letter_p (int value, char c);
+int score_const_ok_for_letter_p (HOST_WIDE_INT value, char c);
 
 int score_extra_constraint (rtx op, char c);
 
Index: gcc/config/score/misc.md
===================================================================
--- gcc/config/score/misc.md	(revision 120252)
+++ gcc/config/score/misc.md	(working copy)
@@ -84,8 +84,8 @@
   [(set (match_operand:SI 0 "register_operand" "=d")
         (if_then_else:SI (match_operator 1 "comparison_operator"
                           [(reg:CC CC_REGNUM) (const_int 0)])
-                         (match_operand:SI 2 "register_operand" "d")
-                         (match_operand:SI 3 "register_operand" "0")))]
+                         (match_operand:SI 2 "arith_operand" "d")
+                         (match_operand:SI 3 "arith_operand" "0")))]
   ""
   "mv%C1   %0, %2"
   [(set_attr "type" "cndmv")
@@ -95,7 +95,7 @@
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (unspec:SI
                         [(match_operand:SI 0 "register_operand" "*e,d")
-                         (match_operand:SI 1 "const_bi_operand" "")]
+                         (match_operand:SI 1 "const_uimm5" "")]
                         BITTST)
                        (const_int 0)))]
   ""
@@ -106,3 +106,312 @@
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
+(define_expand "extzv"
+  [(set (match_operand:SI 0 "register_operand" "")
+        (zero_extract (match_operand:SI 1 "memory_operand" "")
+                      (match_operand:SI 2 "immediate_operand" "")
+                      (match_operand:SI 3 "immediate_operand" "")))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+{
+  if (mdx_unaligned_load (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_expand "insv"
+  [(set (zero_extract (match_operand:SI 0 "memory_operand" "")
+                      (match_operand:SI 1 "immediate_operand" "")
+                      (match_operand:SI 2 "immediate_operand" ""))
+        (match_operand:SI 3 "register_operand" ""))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+{
+  if (mdx_unaligned_store (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_expand "extv"
+  [(set (match_operand:SI 0 "register_operand" "")
+        (sign_extract (match_operand:SI 1 "memory_operand" "")
+                      (match_operand:SI 2 "immediate_operand" "")
+                      (match_operand:SI 3 "immediate_operand" "")))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+{
+  if (mdx_unaligned_load (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_expand "movmemsi"
+  [(parallel [(set (match_operand:BLK 0 "general_operand")
+                   (match_operand:BLK 1 "general_operand"))
+              (use (match_operand:SI 2 ""))
+              (use (match_operand:SI 3 "const_int_operand"))])]
+  "!TARGET_SCORE5U"
+{
+  if (mdx_block_move (operands))
+    DONE;
+  else
+    FAIL;
+})
+
+(define_insn "move_lbu_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:QI 3 "register_operand" "=d")
+        (mem:QI (match_dup 1)))]
+  "!TARGET_SCORE5U"
+  "lbu     %3, [%1]+, %2"
+  [(set_attr "type" "load")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_lhu_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:HI 3 "register_operand" "=d")
+        (mem:HI (match_dup 1)))]
+  "!TARGET_SCORE5U"
+  "lhu     %3, [%1]+, %2"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_lw_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:SI 3 "register_operand" "=d")
+        (mem:SI (match_dup 1)))]
+  "!TARGET_SCORE5U"
+  "lw      %3, [%1]+, %2"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_sb_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:QI (match_dup 1))
+        (match_operand:QI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sb      %3, [%1]+, %2"
+  [(set_attr "type" "store")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_sh_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:HI (match_dup 1))
+        (match_operand:HI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sh      %3, [%1]+, %2"
+  [(set_attr "type" "store")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_sw_a"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:SI (match_dup 1))
+        (match_operand:SI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sw      %3, [%1]+, %2"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lbu_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:QI 3 "register_operand" "=d")
+        (mem:QI (plus:SI (match_dup 1)
+                         (match_dup 2))))]
+  "!TARGET_SCORE5U"
+  "lbu     %3, [%1, %2]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_lhu_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:HI 3 "register_operand" "=d")
+        (mem:HI (plus:SI (match_dup 1)
+                         (match_dup 2))))]
+  "!TARGET_SCORE5U"
+  "lhu     %3, [%1, %2]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_lw_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (match_operand:SI 3 "register_operand" "=d")
+        (mem:SI (plus:SI (match_dup 1)
+                         (match_dup 2))))]
+  "!TARGET_SCORE5U"
+  "lw      %3, [%1, %2]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_sb_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:QI (plus:SI (match_dup 1)
+                         (match_dup 2)))
+        (match_operand:QI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sb      %3, [%1, %2]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "QI")])
+
+(define_insn "move_sh_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:HI (plus:SI (match_dup 1)
+                         (match_dup 2)))
+        (match_operand:HI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sh      %3, [%1, %2]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "HI")])
+
+(define_insn "move_sw_b"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (match_operand:SI 2 "const_simm12" "")))
+   (set (mem:SI (plus:SI (match_dup 1)
+                         (match_dup 2)))
+        (match_operand:SI 3 "register_operand" "d"))]
+  "!TARGET_SCORE5U"
+  "sw      %3, [%1, %2]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lcb"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (reg:SI LC_REGNUM)
+        (unspec:SI [(mem:BLK (match_dup 1))] LCB))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "lcb     [%1]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lcw"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (match_operand:SI 2 "register_operand" "=d")
+        (unspec:SI [(mem:BLK (match_dup 1))
+                    (reg:SI LC_REGNUM)] LCW))
+   (set (reg:SI LC_REGNUM)
+        (unspec:SI [(mem:BLK (match_dup 1))] LCB))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "lcw     %2, [%1]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_lce"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (match_operand:SI 2 "register_operand" "=d")
+        (unspec:SI [(mem:BLK (match_dup 1))
+                    (reg:SI LC_REGNUM)] LCE))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "lce     %2, [%1]+"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_scb"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (mem:BLK (match_dup 1))
+        (unspec:BLK [(match_operand:SI 2 "register_operand" "d")] SCB))
+   (set (reg:SI SC_REGNUM)
+        (unspec:SI [(match_dup 2)] SCLC))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "scb     %2, [%1]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_scw"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (mem:BLK (match_dup 1))
+        (unspec:BLK [(match_operand:SI 2 "register_operand" "d")
+                     (reg:SI SC_REGNUM)] SCW))
+   (set (reg:SI SC_REGNUM)
+        (unspec:SI [(match_dup 2)] SCLC))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "scw     %2, [%1]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "move_sce"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0")
+                 (const_int 4)))
+   (set (mem:BLK (match_dup 1))
+        (unspec:BLK [(reg:SI SC_REGNUM)] SCE))]
+  "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN"
+  "sce     [%1]+"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")])
+
+(define_insn "andsi3_extzh"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (and:SI (match_operand:SI 1 "register_operand" "d")
+                (const_int 65535)))]
+  ""
+  "extzh   %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "bitclr_c"
+  [(set (match_operand:SI 0 "register_operand" "=e,d")
+        (and:SI (match_operand:SI 1 "register_operand" "0,d")
+                (match_operand:SI 2 "const_npow2")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "@
+   bitclr!    %0, %F2
+   bitclr.c   %0, %1, %F2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "bitset_c"
+  [(set (match_operand:SI 0 "register_operand" "=e,d")
+        (ior:SI (match_operand:SI 1 "register_operand" "0,d")
+                (match_operand:SI 2 "const_pow2")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "@
+   bitset!    %0, %E2
+   bitset.c   %0, %1, %E2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "bittgl_c"
+  [(set (match_operand:SI 0 "register_operand" "=e,d")
+        (xor:SI (match_operand:SI 1 "register_operand" "0,d")
+                (match_operand:SI 2 "const_pow2")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "@
+   bittgl!    %0, %E2
+   bittgl.c   %0, %1, %E2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
Index: gcc/config/score/score.c
===================================================================
--- gcc/config/score/score.c	(revision 120252)
+++ gcc/config/score/score.c	(working copy)
@@ -67,7 +67,9 @@ static int score_symbol_insns (enum scor
 
 static int score_address_insns (rtx, enum machine_mode);
 
-static bool score_rtx_costs (rtx, int, int, int *);
+static bool score_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *);
+
+static int score_address_cost (rtx);
 
 #undef  TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START           th_asm_file_start
@@ -126,6 +128,9 @@ static bool score_rtx_costs (rtx, int, i
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS                score_rtx_costs
 
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST             score_address_cost
+
 #undef TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS     TARGET_DEFAULT
 
@@ -154,7 +159,7 @@ score_pass_by_reference (CUMULATIVE_ARGS
 static rtx
 score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
 {
-  if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
+  if (!IMM_IN_RANGE (offset, 15, 1))
     {
       reg = expand_simple_binop (GET_MODE (reg), PLUS,
                                  gen_int_mode (offset & 0xffffc000,
@@ -499,12 +504,13 @@ enum reg_class score_char_to_class[256];
 void
 score_override_options (void)
 {
+  flag_pic = false;
   if (!flag_pic)
     sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
   else
     {
       sdata_max = 0;
-      if (g_switch_set)
+      if (g_switch_set && (g_switch_value != 0))
         warning (0, "-fPIC and -G are incompatible");
     }
 
@@ -540,7 +546,7 @@ score_reg_class (int regno)
       || regno == ARG_POINTER_REGNUM)
     return ALL_REGS;
 
-  for (c = 0 ; c < N_REG_CLASSES ; c++)
+  for (c = 0; c < N_REG_CLASSES; c++)
     if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
       return c;
 
@@ -551,10 +557,10 @@ score_reg_class (int regno)
 enum reg_class
 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
 {
-  if (reg_class_subset_p (G32_REGS, class))
-    class = G32_REGS;
   if (reg_class_subset_p (G16_REGS, class))
-    class = G16_REGS;
+    return G16_REGS;
+  if (reg_class_subset_p (G32_REGS, class))
+    return G32_REGS;
   return class;
 }
 
@@ -576,41 +582,34 @@ score_secondary_reload_class (enum reg_c
 
 /* Implement CONST_OK_FOR_LETTER_P macro.  */
 /* imm constraints
-   I        IMM8        (i15-2-form)
-   J        IMM5        (i15_1-form)
-   K        IMM16       (i-form)
-   L        IMM16s      (i-form)
-   M        IMM14       (ri-form)
-   N        IMM14s      (ri-form)
-   O        IMM15s      (ri-form)
-   P        IMM12s      (rix-form) / IMM10s(cop-form) << 2  */
+   I        imm16 << 16
+   J        uimm5
+   K        uimm16
+   L        simm16
+   M        uimm14
+   N        simm14  */
 int
-score_const_ok_for_letter_p (int value, char c)
+score_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
 {
   switch (c)
     {
-    case 'I': return IMM_IN_RANGE (value, 8, 0);
+    case 'I': return ((value & 0xffff) == 0);
     case 'J': return IMM_IN_RANGE (value, 5, 0);
     case 'K': return IMM_IN_RANGE (value, 16, 0);
     case 'L': return IMM_IN_RANGE (value, 16, 1);
     case 'M': return IMM_IN_RANGE (value, 14, 0);
     case 'N': return IMM_IN_RANGE (value, 14, 1);
-    case 'O': return IMM_IN_RANGE (value, 15, 1);
-    case 'P': return IMM_IN_RANGE (value, 12, 1);
     default : return 0;
     }
 }
 
 /* Implement EXTRA_CONSTRAINT macro.  */
-/* Q        const_hi    imm
-   Z        symbol_ref  */
+/* Z        symbol_ref  */
 int
 score_extra_constraint (rtx op, char c)
 {
   switch (c)
     {
-    case 'Q':
-      return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
     case 'Z':
       return GET_CODE (op) == SYMBOL_REF;
     default:
@@ -917,10 +916,8 @@ score_address_insns (rtx x, enum machine
   int factor;
 
   if (mode == BLKmode)
-    /* BLKmode is used for single unaligned loads and stores.  */
     factor = 1;
   else
-    /* Each word of a multi-word value will be accessed individually.  */
     factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
   if (mda_classify_address (&addr, mode, x, false))
@@ -938,24 +935,53 @@ score_address_insns (rtx x, enum machine
 
 /* Implement TARGET_RTX_COSTS macro.  */
 static bool
-score_rtx_costs (rtx x, int code, int outer_code, int *total)
+score_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
+                 int *total)
 {
   enum machine_mode mode = GET_MODE (x);
 
   switch (code)
     {
     case CONST_INT:
-      /* These can be used anywhere. */
-      *total = 0;
+      if (outer_code == SET)
+        {
+          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+              || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
+            *total = COSTS_N_INSNS (1);
+          else
+            *total = COSTS_N_INSNS (2);
+        }
+      else if (outer_code == PLUS || outer_code == MINUS)
+        {
+          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
+            *total = 0;
+          else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
+            *total = 1;
+          else
+            *total = COSTS_N_INSNS (2);
+        }
+      else if (outer_code == AND || outer_code == IOR)
+        {
+          if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
+            *total = 0;
+          else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
+            *total = 1;
+          else
+            *total = COSTS_N_INSNS (2);
+        }
+      else
+        {
+          *total = 0;
+        }
       return true;
 
-      /* Otherwise fall through to the handling below because
-         we'll need to construct the constant.  */
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_DOUBLE:
-      *total = COSTS_N_INSNS (1);
+      *total = COSTS_N_INSNS (2);
       return true;
 
     case MEM:
@@ -1011,7 +1037,8 @@ score_rtx_costs (rtx x, int code, int ou
           *total = COSTS_N_INSNS (4);
           return true;
         }
-      return false;
+      *total = COSTS_N_INSNS (1);
+      return true;
 
     case NEG:
       if (mode == DImode)
@@ -1022,22 +1049,38 @@ score_rtx_costs (rtx x, int code, int ou
       return false;
 
     case MULT:
-      *total = COSTS_N_INSNS (12);
+      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
       return true;
 
     case DIV:
     case MOD:
     case UDIV:
     case UMOD:
-      *total = COSTS_N_INSNS (33);
+      *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
       return true;
 
     case SIGN_EXTEND:
-      *total = COSTS_N_INSNS (2);
-      return true;
-
     case ZERO_EXTEND:
-      *total = COSTS_N_INSNS (1);
+      switch (GET_MODE (XEXP (x, 0)))
+        {
+        case QImode:
+        case HImode:
+          if (GET_CODE (XEXP (x, 0)) == MEM)
+            {
+              *total = COSTS_N_INSNS (2);
+
+              if (!TARGET_LITTLE_ENDIAN &&
+                  side_effects_p (XEXP (XEXP (x, 0), 0)))
+                *total = 100;
+            }
+          else
+            *total = COSTS_N_INSNS (1);
+          break;
+
+        default:
+          *total = COSTS_N_INSNS (1);
+          break;
+        }
       return true;
 
     default:
@@ -1045,6 +1088,13 @@ score_rtx_costs (rtx x, int code, int ou
     }
 }
 
+/* Implement TARGET_ADDRESS_COST macro.  */
+int
+score_address_cost (rtx addr)
+{
+  return score_address_insns (addr, SImode);
+}
+
 /* Implement ASM_OUTPUT_EXTERNAL macro.  */
 int
 score_output_external (FILE *file ATTRIBUTE_UNUSED,
@@ -1089,18 +1139,16 @@ score_return_addr (int count, rtx frame 
 /* Implement PRINT_OPERAND macro.  */
 /* Score-specific operand codes:
    '['        print .set nor1 directive
-   ']'        print .set r1        directive
-
+   ']'        print .set r1 directive
    'U'        print hi part of a CONST_INT rtx
-   'D'        print first part of const double
-   'S'        selectively print '!' if operand is 15bit instruction accessible
-   'V'        print "v!" if operand is 15bit instruction accessible, or
-   "lfh!"
-
+   'E'        print log2(v)
+   'F'        print log2(~v)
+   'D'        print SFmode const double
+   'S'        selectively print "!" if operand is 15bit instruction accessible
+   'V'        print "v!" if operand is 15bit instruction accessible, or "lfh!"
    'L'        low  part of DImode reg operand
    'H'        high part of DImode reg operand
-
-   'C'  print part of opcode for a branch condition.  */
+   'C'        print part of opcode for a branch condition.  */
 void
 score_print_operand (FILE *file, rtx op, int c)
 {
@@ -1125,9 +1173,11 @@ score_print_operand (FILE *file, rtx op,
   else if (c == 'D')
     {
       if (GET_CODE (op) == CONST_DOUBLE)
-        fprintf (file, HOST_WIDE_INT_PRINT_HEX,
-                 TARGET_LITTLE_ENDIAN
-                 ? CONST_DOUBLE_LOW (op) : CONST_DOUBLE_HIGH (op));
+        {
+          rtx temp = gen_lowpart (SImode, op);
+          gcc_assert (GET_MODE (op) == SFmode);
+          fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp));
+        }
       else
         output_addr_const (file, op);
     }
@@ -1142,23 +1192,17 @@ score_print_operand (FILE *file, rtx op,
       gcc_assert (code == REG);
       fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
     }
-  else if (code == REG)
-    {
-      int regnum = REGNO (op);
-      if ((c == 'H' && !WORDS_BIG_ENDIAN)
-          || (c == 'L' && WORDS_BIG_ENDIAN))
-        regnum ++;
-      fprintf (file, "%s", reg_names[regnum]);
-    }
   else if (c == 'C')
     {
+      enum machine_mode mode = GET_MODE (XEXP (op, 0));
+
       switch (code)
         {
         case EQ: fputs ("eq", file); break;
         case NE: fputs ("ne", file); break;
         case GT: fputs ("gt", file); break;
-        case GE: fputs ("ge", file); break;
-        case LT: fputs ("lt", file); break;
+        case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
+        case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
         case LE: fputs ("le", file); break;
         case GTU: fputs ("gtu", file); break;
         case GEU: fputs ("cs", file); break;
@@ -1168,6 +1212,46 @@ score_print_operand (FILE *file, rtx op,
           output_operand_lossage ("invalid operand for code: '%c'", code);
         }
     }
+  else if (c == 'E')
+    {
+      unsigned HOST_WIDE_INT i;
+      unsigned HOST_WIDE_INT pow2mask = 1;
+      unsigned HOST_WIDE_INT val;
+
+      val = INTVAL (op);
+      for (i = 0; i < 32; i++)
+        {
+          if (val == pow2mask)
+            break;
+          pow2mask <<= 1;
+        }
+      gcc_assert (i < 32);
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
+    }
+  else if (c == 'F')
+    {
+      unsigned HOST_WIDE_INT i;
+      unsigned HOST_WIDE_INT pow2mask = 1;
+      unsigned HOST_WIDE_INT val;
+
+      val = ~INTVAL (op);
+      for (i = 0; i < 32; i++)
+        {
+          if (val == pow2mask)
+            break;
+          pow2mask <<= 1;
+        }
+      gcc_assert (i < 32);
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
+    }
+  else if (code == REG)
+    {
+      int regnum = REGNO (op);
+      if ((c == 'H' && !WORDS_BIG_ENDIAN)
+          || (c == 'L' && WORDS_BIG_ENDIAN))
+        regnum ++;
+      fprintf (file, "%s", reg_names[regnum]);
+    }
   else
     {
       switch (code)
@@ -1233,4 +1317,48 @@ score_print_operand_address (FILE *file,
   gcc_unreachable ();
 }
 
+/* Implement SELECT_CC_MODE macro.  */
+enum machine_mode
+score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
+{
+  if ((op == EQ || op == NE || op == LT || op == GE)
+      && y == const0_rtx
+      && GET_MODE (x) == SImode)
+    {
+      switch (GET_CODE (x))
+        {
+        case PLUS:
+        case MINUS:
+        case NEG:
+        case AND:
+        case IOR:
+        case XOR:
+        case NOT:
+        case ASHIFT:
+        case LSHIFTRT:
+        case ASHIFTRT:
+          return CC_NZmode;
+
+        case SIGN_EXTEND:
+        case ZERO_EXTEND:
+        case ROTATE:
+        case ROTATERT:
+          return (op == LT || op == GE) ? CC_Nmode : CCmode;
+
+        default:
+          return CCmode;
+        }
+    }
+
+  if ((op == EQ || op == NE)
+      && (GET_CODE (y) == NEG)
+      && register_operand (XEXP (y, 0), SImode)
+      && register_operand (x, SImode))
+    {
+      return CC_NZmode;
+    }
+
+  return CCmode;
+}
+
 struct gcc_target targetm = TARGET_INITIALIZER;
Index: gcc/config/score/score.h
===================================================================
--- gcc/config/score/score.h	(revision 120252)
+++ gcc/config/score/score.h	(working copy)
@@ -28,19 +28,20 @@ extern GTY(()) rtx cmp_op0;
 extern GTY(()) rtx cmp_op1;
 
 /* Controlling the Compilation Driver.  */
+#undef SWITCH_TAKES_ARG
 #define SWITCH_TAKES_ARG(CHAR) \
   (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
 
 /* CC1_SPEC is the set of arguments to pass to the compiler proper.  */
 #undef CC1_SPEC
-#define CC1_SPEC                 "%{!mel:-meb}"
+#define CC1_SPEC                 "%{G*} %{!mel:-meb}"
 
 #undef ASM_SPEC
 #define ASM_SPEC \
   "%{!mel:-EB} %{mel:-EL} %{mscore5u:-SCORE5U} %{mscore7:-SCORE7} %{G*}"
 
 #undef LINK_SPEC
-#define LINK_SPEC                 "%{!mel:-EB} %{mel:-EL} %{G*}"
+#define LINK_SPEC                "%{!mel:-EB} %{mel:-EL} %{G*}"
 
 /* Run-time Target Specification.  */
 #define TARGET_CPU_CPP_BUILTINS()               \
@@ -96,7 +97,7 @@ extern GTY(()) rtx cmp_op1;
 
 /* Allocation boundary (in *bits*) for storing arguments in argument list.  */
 #define PARM_BOUNDARY                  BITS_PER_WORD
-#define STACK_BOUNDARY                 64
+#define STACK_BOUNDARY                 BITS_PER_WORD
 
 /* Allocation boundary (in *bits*) for the code of a function.  */
 #define FUNCTION_BOUNDARY              BITS_PER_WORD
@@ -115,12 +116,41 @@ extern GTY(()) rtx cmp_op1;
    data to make it all fit in fewer cache lines.  Another is to
    cause character arrays to be word-aligned so that `strcpy' calls
    that copy constants to character arrays can be done inline.  */
-#define DATA_ALIGNMENT(TYPE, ALIGN)                                     \
-  ((((ALIGN) < BITS_PER_WORD)                                           \
-    && (TREE_CODE (TYPE) == ARRAY_TYPE                                  \
-        || TREE_CODE (TYPE) == UNION_TYPE                               \
+#define DATA_ALIGNMENT(TYPE, ALIGN)                                      \
+  ((((ALIGN) < BITS_PER_WORD)                                            \
+    && (TREE_CODE (TYPE) == ARRAY_TYPE                                   \
+        || TREE_CODE (TYPE) == UNION_TYPE                                \
         || TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
 
+/* If defined, a C expression to compute the alignment given to a
+   constant that is being placed in memory.  EXP is the constant
+   and ALIGN is the alignment that the object would ordinarily have.
+   The value of this macro is used instead of that alignment to align
+   the object.
+
+   If this macro is not defined, then ALIGN is used.
+
+   The typical use of this macro is to increase alignment for string
+   constants to be word aligned so that `strcpy' calls that copy
+   constants can be done inline.  */
+#define CONSTANT_ALIGNMENT(EXP, ALIGN)                                  \
+  ((TREE_CODE (EXP) == STRING_CST  || TREE_CODE (EXP) == CONSTRUCTOR)   \
+   && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* If defined, a C expression to compute the alignment for a local
+   variable.  TYPE is the data type, and ALIGN is the alignment that
+   the object would ordinarily have.  The value of this macro is used
+   instead of that alignment to align the object.
+
+   If this macro is not defined, then ALIGN is used.
+
+   One use of this macro is to increase alignment of medium-size
+   data to make it all fit in fewer cache lines.  */
+#define LOCAL_ALIGNMENT(TYPE, ALIGN)                                    \
+  ((TREE_CODE (TYPE) == ARRAY_TYPE                                      \
+    && TYPE_MODE (TREE_TYPE (TYPE)) == QImode                           \
+    && (ALIGN) < BITS_PER_WORD) ? BITS_PER_WORD : (ALIGN))
+
 /* Alignment of field after `int : 0' in a structure.  */
 #define EMPTY_FIELD_BOUNDARY           32
 
@@ -209,7 +239,7 @@ extern GTY(()) rtx cmp_op1;
 {                                                        \
   /* General Purpose Registers  */                       \
   1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        \
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,        \
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,        \
   /* Control Registers  */                               \
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,        \
   /* CEH/ CEL/ CNT/ LCR/ SCR / ARG_POINTER_REGNUM/ FRAME_POINTER_REGNUM */\
@@ -245,8 +275,8 @@ extern GTY(()) rtx cmp_op1;
 }
 
 #define REG_ALLOC_ORDER                                                   \
-{   0,  1,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,        \
-   18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  2,  3,        \
+{   0,  1,  6,  7,  8,  9, 10, 11,  4,  5, 22, 23, 24, 25, 26, 27,        \
+   12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 28, 29, 30, 31,  2,  3,        \
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,        \
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,        \
    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,        \
@@ -386,18 +416,18 @@ enum reg_class
   score_preferred_reload_class (X, CLASS)
 
 /* If we need to load shorts byte-at-a-time, then we need a scratch.  */
-#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X)        \
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
   score_secondary_reload_class (CLASS, MODE, X)
 
 /* Return the register class of a scratch register needed to copy IN into
    or out of a register in CLASS in MODE.  If it can be done directly,
    NO_REGS is returned.  */
-#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X)       \
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \
   score_secondary_reload_class (CLASS, MODE, X)
 
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS.  */
-#define CLASS_MAX_NREGS(CLASS, MODE)    \
+#define CLASS_MAX_NREGS(CLASS, MODE) \
   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 
 #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)    \
@@ -607,8 +637,8 @@ typedef struct score_args
 #define HAVE_PRE_DECREMENT              1
 #define HAVE_POST_INCREMENT             1
 #define HAVE_POST_DECREMENT             1
-#define HAVE_PRE_MODIFY_DISP            0
-#define HAVE_POST_MODIFY_DISP           0
+#define HAVE_PRE_MODIFY_DISP            1
+#define HAVE_POST_MODIFY_DISP           1
 #define HAVE_PRE_MODIFY_REG             0
 #define HAVE_POST_MODIFY_REG            0
 
@@ -660,6 +690,13 @@ typedef struct score_args
 
 #define LEGITIMATE_CONSTANT_P(X)        1
 
+/* Condition Code Status.  */
+#define SELECT_CC_MODE(OP, X, Y)        score_select_cc_mode (OP, X, Y)
+
+/* Return nonzero if SELECT_CC_MODE will never return MODE for a
+   floating point inequality comparison.  */
+#define REVERSIBLE_CC_MODE(MODE)        1
+
 /* Describing Relative Costs of Operations  */
 /* Compute extra cost of moving data between one register class and another.  */
 #define REGISTER_MOVE_COST(MODE, FROM, TO) \
@@ -753,32 +790,32 @@ typedef struct score_args
   sprintf ((LABEL), "*%s%s%ld", (LOCAL_LABEL_PREFIX), (PREFIX), (long) (NUM))
 
 /* Output of Assembler Instructions.  */
-#define REGISTER_NAMES                                                   \
-{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",                        \
-  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",                  \
-  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",                \
-  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",                \
-                                                                         \
-  "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",                \
-  "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",          \
-                                                                         \
-  "ceh", "cel", "sr0", "sr1", "sr2", "_arg", "_frame", "",               \
-  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",        \
-                                                                         \
-  "c1r0", "c1r1", "c1r2", "c1r3", "c1r4", "c1r5", "c1r6", "c1r7",        \
-  "c1r8", "c1r9", "c1r10", "c1r11", "c1r12", "c1r13", "c1r14", "c1r15",  \
-  "c1r16", "c1r17", "c1r18", "c1r19", "c1r20", "c1r21", "c1r22", "c1r23",\
-  "c1r24", "c1r25", "c1r26", "c1r27", "c1r28", "c1r29", "c1r30", "c1r31",\
-                                                                         \
-  "c2r0", "c2r1", "c2r2", "c2r3", "c2r4", "c2r5", "c2r6", "c2r7",        \
-  "c2r8", "c2r9", "c2r10", "c2r11", "c2r12", "c2r13", "c2r14", "c2r15",  \
-  "c2r16", "c2r17", "c2r18", "c2r19", "c2r20", "c2r21", "c2r22", "c2r23",\
-  "c2r24", "c2r25", "c2r26", "c2r27", "c2r28", "c2r29", "c2r30", "c2r31",\
-                                                                         \
-  "c3r0", "c3r1", "c3r2", "c3r3", "c3r4", "c3r5", "c3r6", "c3r7",        \
-  "c3r8", "c3r9", "c3r10", "c3r11", "c3r12", "c3r13", "c3r14", "c3r15",  \
-  "c3r16", "c3r17", "c3r18", "c3r19", "c3r20", "c3r21", "c3r22", "c3r23",\
-  "c3r24", "c3r25", "c3r26", "c3r27", "c3r28", "c3r29", "c3r30", "c3r31",\
+#define REGISTER_NAMES                                                    \
+{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",                         \
+  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",                   \
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",                 \
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",                 \
+                                                                          \
+  "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",                 \
+  "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",           \
+                                                                          \
+  "ceh", "cel", "sr0", "sr1", "sr2", "_arg", "_frame", "",                \
+  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",         \
+                                                                          \
+  "c1r0", "c1r1", "c1r2", "c1r3", "c1r4", "c1r5", "c1r6", "c1r7",         \
+  "c1r8", "c1r9", "c1r10", "c1r11", "c1r12", "c1r13", "c1r14", "c1r15",   \
+  "c1r16", "c1r17", "c1r18", "c1r19", "c1r20", "c1r21", "c1r22", "c1r23", \
+  "c1r24", "c1r25", "c1r26", "c1r27", "c1r28", "c1r29", "c1r30", "c1r31", \
+                                                                          \
+  "c2r0", "c2r1", "c2r2", "c2r3", "c2r4", "c2r5", "c2r6", "c2r7",         \
+  "c2r8", "c2r9", "c2r10", "c2r11", "c2r12", "c2r13", "c2r14", "c2r15",   \
+  "c2r16", "c2r17", "c2r18", "c2r19", "c2r20", "c2r21", "c2r22", "c2r23", \
+  "c2r24", "c2r25", "c2r26", "c2r27", "c2r28", "c2r29", "c2r30", "c2r31", \
+                                                                          \
+  "c3r0", "c3r1", "c3r2", "c3r3", "c3r4", "c3r5", "c3r6", "c3r7",         \
+  "c3r8", "c3r9", "c3r10", "c3r11", "c3r12", "c3r13", "c3r14", "c3r15",   \
+  "c3r16", "c3r17", "c3r18", "c3r19", "c3r20", "c3r21", "c3r22", "c3r23", \
+  "c3r24", "c3r25", "c3r26", "c3r27", "c3r28", "c3r29", "c3r30", "c3r31", \
 }
 
 /* Print operand X (an rtx) in assembler syntax to file FILE.  */
@@ -907,4 +944,4 @@ struct extern_list GTY ((chain_next ("%h
   int size;                             /* size in bytes  */
 };
 
-extern GTY (()) struct extern_list      *extern_head ;
+extern GTY (()) struct extern_list      *extern_head;
Index: gcc/config/score/score-conv.h
===================================================================
--- gcc/config/score/score-conv.h	(revision 120252)
+++ gcc/config/score/score-conv.h	(working copy)
@@ -45,7 +45,7 @@ extern int target_flags;
 
 #define CE_REG_P(REGNO)        REG_CONTAIN (REGNO, CE_REG_FIRST, CE_REG_NUM)
 
-#define UIMM_IN_RANGE(V, W)  ((V) >= 0 && (V) < ((HOST_WIDE_INT)1 << (W)))
+#define UIMM_IN_RANGE(V, W)  ((V) >= 0 && (V) < ((HOST_WIDE_INT) 1 << (W)))
 
 #define SIMM_IN_RANGE(V, W)                            \
   ((V) >= (-1 * ((HOST_WIDE_INT) 1 << ((W) - 1)))      \
@@ -54,6 +54,11 @@ extern int target_flags;
 #define IMM_IN_RANGE(V, W, S) \
   ((S) ? SIMM_IN_RANGE (V, W) : UIMM_IN_RANGE (V, W))
 
+#define IMM_IS_POW_OF_2(V, E1, E2)                \
+  ((V) >= ((unsigned HOST_WIDE_INT) 1 << (E1))     \
+   && (V) <= ((unsigned HOST_WIDE_INT) 1 << (E2))  \
+   && ((V) & ((V) - 1)) == 0)
+
 #define SCORE_STACK_ALIGN(LOC)          (((LOC) + 3) & ~3)
 
 #define SCORE_MAX_FIRST_STACK_STEP      (0x3ff0)
Index: gcc/config/score/score-mdaux.c
===================================================================
--- gcc/config/score/score-mdaux.c	(revision 120252)
+++ gcc/config/score/score-mdaux.c	(working copy)
@@ -108,10 +108,9 @@ score_symbol_type score_classify_symbol 
   if (GET_CODE (x) == LABEL_REF)
     return SYMBOL_GENERAL;
 
-  if (GET_CODE (x) != SYMBOL_REF)
-    gcc_unreachable ();
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
-  if (CONSTANT_POOL_ADDRESS_P(x))
+  if (CONSTANT_POOL_ADDRESS_P (x))
     {
       if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
         return SYMBOL_SMALL_DATA;
@@ -185,14 +184,14 @@ mda_compute_frame_size (HOST_WIDE_INT si
   f->mask = 0;
   f->var_size = SCORE_STACK_ALIGN (size);
   f->args_size = current_function_outgoing_args_size;
-  f->cprestore_size = SCORE_STACK_ALIGN (STARTING_FRAME_OFFSET) - f->args_size;
+  f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
   if (f->var_size == 0 && current_function_is_leaf)
     f->args_size = f->cprestore_size = 0;
 
   if (f->args_size == 0 && current_function_calls_alloca)
     f->args_size = UNITS_PER_WORD;
 
-  f->total_size = f->var_size + f->args_size;
+  f->total_size = f->var_size + f->args_size + f->cprestore_size;
   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
     {
       if (score_save_reg_p (regno))
@@ -205,7 +204,7 @@ mda_compute_frame_size (HOST_WIDE_INT si
   if (current_function_calls_eh_return)
     {
       unsigned int i;
-      for (i = 0; ; ++i)
+      for (i = 0;; ++i)
         {
           regno = EH_RETURN_DATA_REGNO (i);
           if (regno == INVALID_REGNUM)
@@ -215,7 +214,7 @@ mda_compute_frame_size (HOST_WIDE_INT si
         }
     }
 
-  f->total_size += SCORE_STACK_ALIGN (f->gp_reg_size);
+  f->total_size += f->gp_reg_size;
   f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
 
   if (f->mask)
@@ -226,12 +225,7 @@ mda_compute_frame_size (HOST_WIDE_INT si
       f->gp_sp_offset = offset;
     }
   else
-    {
-      f->gp_sp_offset = 0;
-    }
-
-  if ((f->total_size == f->gp_reg_size) && flag_pic)
-    f->total_size += 8;
+    f->gp_sp_offset = 0;
 
   return f;
 }
@@ -294,8 +288,13 @@ mdx_prologue (void)
   if (frame_pointer_needed)
     EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
 
-  if (flag_pic)
-    emit_insn (gen_cprestore (GEN_INT (size + 4)));
+  if (flag_pic && f->cprestore_size)
+    {
+      if (frame_pointer_needed)
+        emit_insn (gen_cprestore_use_fp (GEN_INT (size - f->cprestore_size)));
+      else
+        emit_insn (gen_cprestore_use_sp (GEN_INT (size - f->cprestore_size)));
+    }
 
 #undef EMIT_PL
 }
@@ -392,7 +391,7 @@ mda_classify_address (struct score_addre
       info->offset = XEXP (x, 1);
       return (mda_valid_base_register_p (info->reg, strict)
               && GET_CODE (info->offset) == CONST_INT
-              && CONST_OK_FOR_LETTER_P (INTVAL (info->offset), 'O'));
+              && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
     case PRE_DEC:
     case POST_DEC:
     case PRE_INC:
@@ -405,7 +404,7 @@ mda_classify_address (struct score_addre
       return mda_valid_base_register_p (info->reg, strict);
     case CONST_INT:
       info->type = ADD_CONST_INT;
-      return CONST_OK_FOR_LETTER_P (INTVAL (x), 'O');
+      return IMM_IN_RANGE (INTVAL (x), 15, 1);
     case CONST:
     case LABEL_REF:
     case SYMBOL_REF:
@@ -443,7 +442,7 @@ mda_symbolic_constant_p (rtx x, enum sco
     return 1;
 
   /* if offset > 15bit, must reload  */
-  if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
+  if (!IMM_IN_RANGE (offset, 15, 1))
     return 0;
 
   switch (*symbol_type)
@@ -459,11 +458,9 @@ mda_symbolic_constant_p (rtx x, enum sco
 void
 mdx_movsicc (rtx *ops)
 {
-  enum machine_mode mode = CCmode;
-
-  if (GET_CODE (ops[1]) == EQ || GET_CODE (ops[1]) == NE)
-    mode = CC_NZmode;
+  enum machine_mode mode;
 
+  mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
                           gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
 }
@@ -533,14 +530,15 @@ mds_movdi (rtx *ops)
 void
 mds_zero_extract_andi (rtx *ops)
 {
-  if (INTVAL (ops[1]) == 1 && const_bi_operand (ops[2], SImode))
+  if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
     emit_insn (gen_zero_extract_bittst (ops[0], ops[2]));
   else
     {
       unsigned HOST_WIDE_INT mask;
       mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
       mask = mask << INTVAL (ops[2]);
-      emit_insn (gen_andsi3_cmp (ops[0], gen_int_mode (mask, SImode)));
+      emit_insn (gen_andsi3_cmp (ops[3], ops[0],
+                                 gen_int_mode (mask, SImode)));
     }
 }
 
@@ -637,17 +635,20 @@ mdp_sinsn (rtx *ops, enum mda_mem_unit u
 const char *
 mdp_limm (rtx *ops)
 {
+  HOST_WIDE_INT v;
+
   gcc_assert (GET_CODE (ops[0]) == REG);
+  gcc_assert (GET_CODE (ops[1]) == CONST_INT);
 
-  if (G16_REG_P (REGNO (ops[0]))
-      && CONST_OK_FOR_LETTER_P (INTVAL (ops[1]), 'I'))
+  v = INTVAL (ops[1]);
+  if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
     return "ldiu!   %0, %c1";
-  else if (CONST_OK_FOR_LETTER_P (INTVAL (ops[1]), 'L'))
+  else if (IMM_IN_RANGE (v, 16, 1))
     return "ldi     %0, %c1";
-  else if (EXTRA_CONSTRAINT (ops[1], 'Q'))
+  else if ((v & 0xffff) == 0)
     return "ldis    %0, %U1";
   else
-    return "li      %0, %D1";
+    return "li      %0, %c1";
 }
 
 /* Output asm insn for move.  */
@@ -670,69 +671,389 @@ mdp_move (rtx *ops)
     return "mv      %0, %1";
 }
 
-/* Score support add/sub with exponent immediate insn,
-   use to judge imm condition.  */
-static unsigned int
-num_bits1 (unsigned HOST_WIDE_INT v)
+/* Emit lcb/lce insns.  */
+bool
+mdx_unaligned_load (rtx *ops)
+{
+  rtx dst = ops[0];
+  rtx src = ops[1];
+  rtx len = ops[2];
+  rtx off = ops[3];
+  rtx addr_reg;
+
+  if (INTVAL (len) != BITS_PER_WORD
+      || (INTVAL (off) % BITS_PER_UNIT) != 0)
+    return false;
+
+  gcc_assert (GET_MODE_SIZE (GET_MODE (dst)) == GET_MODE_SIZE (SImode));
+
+  addr_reg = copy_addr_to_reg (XEXP (src, 0));
+  emit_insn (gen_move_lcb (addr_reg, addr_reg));
+  emit_insn (gen_move_lce (addr_reg, addr_reg, dst));
+
+  return true;
+}
+
+/* Emit scb/sce insns.  */
+bool
+mdx_unaligned_store (rtx *ops)
+{
+  rtx dst = ops[0];
+  rtx len = ops[1];
+  rtx off = ops[2];
+  rtx src = ops[3];
+  rtx addr_reg;
+
+  if (INTVAL(len) != BITS_PER_WORD
+      || (INTVAL(off) % BITS_PER_UNIT) != 0)
+    return false;
+
+  gcc_assert (GET_MODE_SIZE (GET_MODE (src)) == GET_MODE_SIZE (SImode));
+
+  addr_reg = copy_addr_to_reg (XEXP (dst, 0));
+  emit_insn (gen_move_scb (addr_reg, addr_reg, src));
+  emit_insn (gen_move_sce (addr_reg, addr_reg));
+
+  return true;
+}
+
+/* If length is short, generate move insns straight.  */
+static void
+mdx_block_move_straight (rtx dst, rtx src, HOST_WIDE_INT length)
+{
+  HOST_WIDE_INT leftover;
+  int i, reg_count;
+  rtx *regs;
+
+  leftover = length % UNITS_PER_WORD;
+  length -= leftover;
+  reg_count = length / UNITS_PER_WORD;
+
+  regs = alloca (sizeof (rtx) * reg_count);
+  for (i = 0; i < reg_count; i++)
+    regs[i] = gen_reg_rtx (SImode);
+
+  /* Load from src to regs.  */
+  if (MEM_ALIGN (src) >= BITS_PER_WORD)
+    {
+      HOST_WIDE_INT offset = 0;
+      for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
+        emit_move_insn (regs[i], adjust_address (src, SImode, offset));
+    }
+  else if (reg_count >= 1)
+    {
+      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
+
+      emit_insn (gen_move_lcb (src_reg, src_reg));
+      for (i = 0; i < (reg_count - 1); i++)
+        emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
+      emit_insn (gen_move_lce (src_reg, src_reg, regs[i]));
+    }
+
+  /* Store regs to dest.  */
+  if (MEM_ALIGN (dst) >= BITS_PER_WORD)
+    {
+      HOST_WIDE_INT offset = 0;
+      for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
+        emit_move_insn (adjust_address (dst, SImode, offset), regs[i]);
+    }
+  else if (reg_count >= 1)
+    {
+      rtx dst_reg = copy_addr_to_reg (XEXP (dst, 0));
+
+      emit_insn (gen_move_scb (dst_reg, dst_reg, regs[0]));
+      for (i = 1; i < reg_count; i++)
+        emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
+      emit_insn (gen_move_sce (dst_reg, dst_reg));
+    }
+
+  /* Mop up any left-over bytes.  */
+  if (leftover > 0)
+    {
+      src = adjust_address (src, BLKmode, length);
+      dst = adjust_address (dst, BLKmode, length);
+      move_by_pieces (dst, src, leftover,
+                      MIN (MEM_ALIGN (src), MEM_ALIGN (dst)), 0);
+    }
+}
+
+/* Generate loop head when dst or src is unaligned.  */
+static void
+mdx_block_move_loop_head (rtx dst_reg, HOST_WIDE_INT dst_align,
+                          rtx src_reg, HOST_WIDE_INT src_align,
+                          HOST_WIDE_INT length)
 {
-  int i, n = 0;
+  bool src_unaligned = (src_align < BITS_PER_WORD);
+  bool dst_unaligned = (dst_align < BITS_PER_WORD);
+
+  rtx temp = gen_reg_rtx (SImode);
 
-  for (i = 0; i < BITS_PER_WORD; i++)
-    n += BITSET_P (v, i) ? 1 : 0;
-  return n;
+  gcc_assert (length == UNITS_PER_WORD);
+
+  if (src_unaligned)
+    {
+      emit_insn (gen_move_lcb (src_reg, src_reg));
+      emit_insn (gen_move_lcw (src_reg, src_reg, temp));
+    }
+  else
+    emit_insn (gen_move_lw_a (src_reg,
+                              src_reg, gen_int_mode (4, SImode), temp));
+
+  if (dst_unaligned)
+    emit_insn (gen_move_scb (dst_reg, dst_reg, temp));
+  else
+    emit_insn (gen_move_sw_a (dst_reg,
+                              dst_reg, gen_int_mode (4, SImode), temp));
 }
 
-/* Generate add insn, insn will affect condition flag. Optimize used.  */
+/* Generate loop body, copy length bytes per iteration.  */
+static void
+mdx_block_move_loop_body (rtx dst_reg, HOST_WIDE_INT dst_align,
+                          rtx src_reg, HOST_WIDE_INT src_align,
+                          HOST_WIDE_INT length)
+{
+  int reg_count = length / UNITS_PER_WORD;
+  rtx *regs = alloca (sizeof (rtx) * reg_count);
+  int i;
+  bool src_unaligned = (src_align < BITS_PER_WORD);
+  bool dst_unaligned = (dst_align < BITS_PER_WORD);
+
+  for (i = 0; i < reg_count; i++)
+    regs[i] = gen_reg_rtx (SImode);
+
+  if (src_unaligned)
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
+    }
+  else
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_lw_a (src_reg,
+                                  src_reg, gen_int_mode (4, SImode), regs[i]));
+    }
+
+  if (dst_unaligned)
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
+    }
+  else
+    {
+      for (i = 0; i < reg_count; i++)
+        emit_insn (gen_move_sw_a (dst_reg,
+                                  dst_reg, gen_int_mode (4, SImode), regs[i]));
+    }
+}
+
+/* Generate loop foot, copy the leftover bytes.  */
+static void
+mdx_block_move_loop_foot (rtx dst_reg, HOST_WIDE_INT dst_align,
+                          rtx src_reg, HOST_WIDE_INT src_align,
+                          HOST_WIDE_INT length)
+{
+  bool src_unaligned = (src_align < BITS_PER_WORD);
+  bool dst_unaligned = (dst_align < BITS_PER_WORD);
+
+  HOST_WIDE_INT leftover;
+
+  leftover = length % UNITS_PER_WORD;
+  length -= leftover;
+
+  if (length > 0)
+    mdx_block_move_loop_body (dst_reg, dst_align,
+                              src_reg, src_align, length);
+
+  if (dst_unaligned)
+    emit_insn (gen_move_sce (dst_reg, dst_reg));
+
+  if (leftover > 0)
+    {
+      HOST_WIDE_INT src_adj = src_unaligned ? -4 : 0;
+      HOST_WIDE_INT dst_adj = dst_unaligned ? -4 : 0;
+      rtx temp;
+
+      gcc_assert (leftover < UNITS_PER_WORD);
+
+      if (leftover >= UNITS_PER_WORD / 2
+          && src_align >= BITS_PER_WORD / 2
+          && dst_align >= BITS_PER_WORD / 2)
+        {
+          temp = gen_reg_rtx (HImode);
+          emit_insn (gen_move_lhu_b (src_reg, src_reg,
+                                     gen_int_mode (src_adj, SImode), temp));
+          emit_insn (gen_move_sh_b (dst_reg, dst_reg,
+                                    gen_int_mode (dst_adj, SImode), temp));
+          leftover -= UNITS_PER_WORD / 2;
+          src_adj = UNITS_PER_WORD / 2;
+          dst_adj = UNITS_PER_WORD / 2;
+        }
+
+      while (leftover > 0)
+        {
+          temp = gen_reg_rtx (QImode);
+          emit_insn (gen_move_lbu_b (src_reg, src_reg,
+                                     gen_int_mode (src_adj, SImode), temp));
+          emit_insn (gen_move_sb_b (dst_reg, dst_reg,
+                                    gen_int_mode (dst_adj, SImode), temp));
+          leftover--;
+          src_adj = 1;
+          dst_adj = 1;
+        }
+    }
+}
+
+#define MIN_MOVE_REGS 3
+#define MIN_MOVE_BYTES (MIN_MOVE_REGS * UNITS_PER_WORD)
+#define MAX_MOVE_REGS 4
+#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
+
+/* The length is large, generate a loop if necessary.
+   The loop is consisted by loop head/body/foot.  */
+static void
+mdx_block_move_loop (rtx dst, rtx src, HOST_WIDE_INT length)
+{
+  HOST_WIDE_INT src_align = MEM_ALIGN (src);
+  HOST_WIDE_INT dst_align = MEM_ALIGN (dst);
+  HOST_WIDE_INT loop_mov_bytes;
+  HOST_WIDE_INT iteration = 0;
+  HOST_WIDE_INT head_length = 0, leftover;
+  rtx label, src_reg, dst_reg, final_dst;
+
+  bool gen_loop_head = (src_align < BITS_PER_WORD
+                        || dst_align < BITS_PER_WORD);
+
+  if (gen_loop_head)
+    head_length += UNITS_PER_WORD;
+
+  for (loop_mov_bytes = MAX_MOVE_BYTES;
+       loop_mov_bytes >= MIN_MOVE_BYTES;
+       loop_mov_bytes -= UNITS_PER_WORD)
+    {
+      iteration = (length - head_length) / loop_mov_bytes;
+      if (iteration > 1)
+        break;
+    }
+  if (iteration <= 1)
+    {
+      mdx_block_move_straight (dst, src, length);
+      return;
+    }
+
+  leftover = (length - head_length) % loop_mov_bytes;
+  length -= leftover;
+
+  src_reg = copy_addr_to_reg (XEXP (src, 0));
+  dst_reg = copy_addr_to_reg (XEXP (dst, 0));
+  final_dst = expand_simple_binop (Pmode, PLUS, dst_reg, GEN_INT (length),
+                                   0, 0, OPTAB_WIDEN);
+
+  if (gen_loop_head)
+    mdx_block_move_loop_head (dst_reg, dst_align,
+                              src_reg, src_align, head_length);
+
+  label = gen_label_rtx ();
+  emit_label (label);
+
+  mdx_block_move_loop_body (dst_reg, dst_align,
+                            src_reg, src_align, loop_mov_bytes);
+
+  emit_insn (gen_cmpsi (dst_reg, final_dst));
+  emit_jump_insn (gen_bne (label));
+
+  mdx_block_move_loop_foot (dst_reg, dst_align,
+                            src_reg, src_align, leftover);
+}
+
+/* Generate block move, for misc.md: "movmemsi".  */
+bool
+mdx_block_move (rtx *ops)
+{
+  rtx dst = ops[0];
+  rtx src = ops[1];
+  rtx length = ops[2];
+
+  if (TARGET_LITTLE_ENDIAN
+      && (MEM_ALIGN (src) < BITS_PER_WORD || MEM_ALIGN (dst) < BITS_PER_WORD)
+      && INTVAL (length) >= UNITS_PER_WORD)
+    return false;
+
+  if (GET_CODE (length) == CONST_INT)
+    {
+      if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
+        {
+           mdx_block_move_straight (dst, src, INTVAL (length));
+           return true;
+        }
+      else if (optimize &&
+               !(flag_unroll_loops || flag_unroll_all_loops))
+        {
+          mdx_block_move_loop (dst, src, INTVAL (length));
+          return true;
+        }
+    }
+  return false;
+}
+
+/* Generate add insn.  */
 const char *
-mdp_add_imm_ucc (rtx *ops)
+mdp_select_add_imm (rtx *ops, bool set_cc)
 {
   HOST_WIDE_INT v = INTVAL (ops[2]);
 
   gcc_assert (GET_CODE (ops[2]) == CONST_INT);
   gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
 
-  if (G16_REG_P (REGNO (ops[0])))
+  if (set_cc && G16_REG_P (REGNO (ops[0])))
     {
-      if (v > 0 && num_bits1 (v) == 1 && IMM_IN_RANGE (ffs (v) - 1, 4, 0))
+      if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
         {
           ops[2] = GEN_INT (ffs (v) - 1);
           return "addei!  %0, %c2";
         }
 
-      if (v < 0 && num_bits1 (-v) == 1 && IMM_IN_RANGE (ffs (-v) - 1, 4, 0))
+      if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
         {
           ops[2] = GEN_INT (ffs (-v) - 1);
           return "subei!  %0, %c2";
         }
     }
+
+  if (set_cc)
     return "addi.c  %0, %c2";
+  else
+    return "addi    %0, %c2";
 }
 
-/* Output arith insn, insn will update condition flag.  */
+/* Output arith insn.  */
 const char *
-mdp_select (rtx *ops, const char *inst_pre, bool commu, const char *let)
+mdp_select (rtx *ops, const char *inst_pre,
+            bool commu, const char *letter, bool set_cc)
 {
   gcc_assert (GET_CODE (ops[0]) == REG);
   gcc_assert (GET_CODE (ops[1]) == REG);
 
-  if (G16_REG_P (REGNO (ops[0]))
+  if (set_cc && G16_REG_P (REGNO (ops[0]))
       && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
       && REGNO (ops[0]) == REGNO (ops[1]))
     {
-      snprintf (ins, INS_BUF_SZ, "%s!        %%0, %%%s2", inst_pre, let);
+      snprintf (ins, INS_BUF_SZ, "%s!  %%0, %%%s2", inst_pre, letter);
       return ins;
     }
 
-  if (commu && G16_REG_P (REGNO (ops[0]))
+  if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
       && G16_REG_P (REGNO (ops[1]))
       && REGNO (ops[0]) == REGNO (ops[2]))
     {
       gcc_assert (GET_CODE (ops[2]) == REG);
-      snprintf (ins, INS_BUF_SZ, "%s!        %%0, %%%s1", inst_pre, let);
+      snprintf (ins, INS_BUF_SZ, "%s!  %%0, %%%s1", inst_pre, letter);
       return ins;
     }
 
-  snprintf (ins, INS_BUF_SZ, "%s.c        %%0, %%1, %%%s2", inst_pre, let);
+  if (set_cc)
+    snprintf (ins, INS_BUF_SZ, "%s.c  %%0, %%1, %%%s2", inst_pre, letter);
+  else
+    snprintf (ins, INS_BUF_SZ, "%s    %%0, %%1, %%%s2", inst_pre, letter);
   return ins;
 }
 
Index: gcc/config/score/score.md
===================================================================
--- gcc/config/score/score.md	(revision 120252)
+++ gcc/config/score/score.md	(working copy)
@@ -59,8 +59,8 @@
 
 (define_constants
    [(BITTST         0)
-    (LOAD_ADD       1)
-    (STORE_ADD      2)
+    (CPLOAD         1)
+    (CPRESTORE      2)
 
     (SCB            3)
     (SCW            4)
@@ -88,10 +88,22 @@
 (include "misc.md")
 (include "mac.md")
 
-(define_insn "movqi"
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand")
+        (match_operand:QI 1 "general_operand"))]
+  ""
+{
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], QImode))
+    {
+      operands[1] = force_reg (QImode, operands[1]);
+    }
+})
+
+(define_insn "*movqi_insns"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a")
         (match_operand:QI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))]
-  ""
+  "!MEM_P (operands[0]) || register_operand (operands[1], QImode)"
 {
   switch (which_alternative)
     {
@@ -109,10 +121,22 @@
   [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr")
    (set_attr "mode" "QI")])
 
-(define_insn "movhi"
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand")
+        (match_operand:HI 1 "general_operand"))]
+  ""
+{
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], HImode))
+    {
+      operands[1] = force_reg (HImode, operands[1]);
+    }
+})
+
+(define_insn "*movhi_insns"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a")
         (match_operand:HI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))]
-  ""
+  "!MEM_P (operands[0]) || register_operand (operands[1], HImode)"
 {
   switch (which_alternative)
     {
@@ -130,11 +154,23 @@
   [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr")
    (set_attr "mode" "HI")])
 
-(define_insn "movsi"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a,d,c")
-        (match_operand:SI 1 "general_operand" "i,d,m,d,*x,d,*a,d,c,d"))]
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand")
+        (match_operand:SI 1 "general_operand"))]
   ""
 {
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], SImode))
+    {
+      operands[1] = force_reg (SImode, operands[1]);
+    }
+})
+
+(define_insn "*movsi_insns"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a,d,*c")
+        (match_operand:SI 1 "general_operand" "i,d,m,d,*x,d,*a,d,*c,d"))]
+  "!MEM_P (operands[0]) || register_operand (operands[1], SImode)"
+{
   switch (which_alternative)
     {
     case 0:
@@ -169,46 +205,103 @@
   DONE;
 })
 
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand")
+        (match_operand:SF 1 "general_operand"))]
+  ""
+{
+  if (MEM_P (operands[0])
+      && !register_operand (operands[1], SFmode))
+    {
+      operands[1] = force_reg (SFmode, operands[1]);
+    }
+})
+
+(define_insn "*movsf_insns"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,m")
+        (match_operand:SF 1 "general_operand" "i,d,m,d"))]
+  "!MEM_P (operands[0]) || register_operand (operands[1], SFmode)"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"li      %0, %D1\";;
+    case 1: return mdp_move (operands);
+    case 2: return mdp_linsn (operands, MDA_WORD, false);
+    case 3: return mdp_sinsn (operands, MDA_WORD);
+    default: gcc_unreachable ();
+    }
+}
+  [(set_attr "type" "arith,move,load,store")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "movdf"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,m")
+        (match_operand:DF 1 "general_operand" "i,d,m,d"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  mds_movdi (operands);
+  DONE;
+})
+
 (define_insn "addsi3"
-  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
-        (plus:SI (match_operand:SI 1 "register_operand" "0,d,%d")
-                 (match_operand:SI 2 "arith_operand" "L,N,d")))]
+  [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+        (plus:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
+                 (match_operand:SI 2 "arith_operand" "I,L,N,d")))]
   ""
-  "@
-   addi    %0, %c2
-   addri   %0, %1, %c2
-   add     %0, %1, %2"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"addis %0, %U2\";
+    case 1: return mdp_select_add_imm (operands, false);
+    case 2: return \"addri %0, %1, %c2\";
+    case 3: return mdp_select (operands, "add", true, "", false);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "*addsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (plus:SI (match_operand:SI 0 "register_operand" "d,d,d")
-                                (match_operand:SI 1 "arith_operand" "N,L,d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (plus:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,L,N,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d,d,d"))]
   ""
-  "@
-   %[       addri.c r1, %0, %c1       %]
-   %[       m%V0    r1, %0\;addi.c  r1, %2        %]
-   %[       add.c   r1, %0, %1        %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"addis.c %0, %U2\";
+    case 1: return mdp_select_add_imm (operands, true);
+    case 2: return \"addri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "add", true, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "addsi3_ucc"
+(define_insn "*addsi3_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
-                                (match_operand:SI 2 "arith_operand" "L,N,d"))
+        (compare:CC_NZ (plus:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,L,N,d"))
                        (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d,d,d")
+   (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (plus:SI (match_dup 1) (match_dup 2)))]
   ""
 {
   switch (which_alternative)
     {
-    case 0: return mdp_add_imm_ucc (operands);
-    case 1: return \"addri.c %0, %1, %c2\";
-    case 2: return mdp_select (operands, "add", true, "");
+    case 0: return \"addis.c %0, %U2\";
+    case 1: return mdp_select_add_imm (operands, true);
+    case 2: return \"addri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "add", true, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -217,9 +310,9 @@
    (set_attr "mode" "SI")])
 
 (define_insn "adddi3"
-  [(set (match_operand:DI 0 "register_operand" "=*e,d")
-        (plus:DI (match_operand:DI 1 "register_operand" "*0,d")
-                 (match_operand:DI 2 "register_operand" "*e,d")))
+  [(set (match_operand:DI 0 "register_operand" "=e,d")
+        (plus:DI (match_operand:DI 1 "register_operand" "0,d")
+                 (match_operand:DI 2 "register_operand" "e,d")))
   (clobber (reg:CC CC_REGNUM))]
   ""
   "@
@@ -233,17 +326,22 @@
         (minus:SI (match_operand:SI 1 "register_operand" "d")
                   (match_operand:SI 2 "register_operand" "d")))]
   ""
-  "sub     %0, %1, %2"
+{
+  return mdp_select (operands, "sub", false, "", false);
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "*subsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (minus:SI (match_operand:SI 0 "register_operand" "d")
-                                 (match_operand:SI 1 "register_operand" "d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "d")
+                                 (match_operand:SI 2 "register_operand" "d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
-  "%[        sub.c   r1, %0, %1        %]"
+{
+  return mdp_select (operands, "sub", false, "", true);
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -255,11 +353,10 @@
    (set (reg:CC CC_REGNUM)
         (compare:CC (match_dup 1) (match_dup 2)))]
   ""
-  [(parallel
-       [(set (reg:CC CC_REGNUM)
-             (compare:CC (match_dup 1) (match_dup 2)))
-        (set (match_dup 0)
-             (minus:SI (match_dup 1) (match_dup 2)))])])
+  [(set (reg:CC CC_REGNUM)
+        (compare:CC (match_dup 1) (match_dup 2)))
+   (set (match_dup 0)
+        (minus:SI (match_dup 1) (match_dup 2)))])
 
 (define_insn "subsi3_ucc_pcmp"
   [(parallel
@@ -270,7 +367,7 @@
              (minus:SI (match_dup 1) (match_dup 2)))])]
   ""
 {
-  return mdp_select (operands, "sub", false, "");
+  return mdp_select (operands, "sub", false, "", true);
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
@@ -285,16 +382,16 @@
         (minus:SI (match_dup 1) (match_dup 2)))]
   ""
 {
-  return mdp_select (operands, "sub", false, "");
+  return mdp_select (operands, "sub", false, "", true);
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
 (define_insn "subdi3"
-  [(set (match_operand:DI 0 "register_operand" "=*e,d")
-        (minus:DI (match_operand:DI 1 "register_operand" "*0,d")
-                  (match_operand:DI 2 "register_operand" "*e,d")))
+  [(set (match_operand:DI 0 "register_operand" "=e,d")
+        (minus:DI (match_operand:DI 1 "register_operand" "0,d")
+                  (match_operand:DI 2 "register_operand" "e,d")))
    (clobber (reg:CC CC_REGNUM))]
   ""
   "@
@@ -306,36 +403,47 @@
 (define_insn "andsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (and:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
-                (match_operand:SI 2 "arith_operand" "K,Q,M,d")))]
+                (match_operand:SI 2 "arith_operand" "I,K,M,d")))]
   ""
-  "@
-   andi    %0, %c2
-   andis   %0, %U2
-   andri   %0, %1, %c2
-   and     %0, %1, %2"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"andis %0, %U2\";
+    case 1: return \"andi  %0, %c2";
+    case 2: return \"andri %0, %1, %c2\";
+    case 3: return mdp_select (operands, "and", true, "", false);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "andsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (and:SI (match_operand:SI 0 "register_operand" "d,d,d,d")
-                               (match_operand:SI 1 "arith_operand" "M,K,Q,d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (and:SI (match_operand:SI 1 "register_operand" "0,0,0,d")
+                               (match_operand:SI 2 "arith_operand" "I,K,M,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d,d,d"))]
   ""
-  "@
-   %[        andri.c r1, %0, %c1      %]
-   %[        m%V0    r1, %0\;andi.c  r1, %c1        %]
-   %[        m%V0    r1, %0\;andis.c r1, %U1        %]
-   %[        and.c   r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"andis.c %0, %U2\";
+    case 1: return \"andi.c  %0, %c2";
+    case 2: return \"andri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "and", true, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "andsi3_ucc"
+(define_insn "*andsi3_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (and:SI
                         (match_operand:SI 1 "register_operand" "0,0,d,d")
-                        (match_operand:SI 2 "arith_operand" "K,Q,M,d"))
+                        (match_operand:SI 2 "arith_operand" "I,K,M,d"))
                        (const_int 0)))
    (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (and:SI (match_dup 1) (match_dup 2)))]
@@ -343,10 +451,10 @@
 {
   switch (which_alternative)
     {
-    case 0:  return \"andi.c  %0, %c2\";
-    case 1:  return \"andis.c %0, %U2\";
-    case 2:  return \"andri.c %0, %1, %c2\";
-    case 3:  return mdp_select (operands, "and", true, "");
+    case 0: return \"andis.c %0, %U2\";
+    case 1: return \"andi.c  %0, %c2";
+    case 2: return \"andri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "and", true, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -355,12 +463,12 @@
    (set_attr "mode" "SI")])
 
 (define_insn_and_split "*zero_extract_andi"
-  [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (zero_extract:SI
-                        (match_operand:SI 0 "register_operand" "d")
-                        (match_operand:SI 1 "const_bi_operand" "")
-                        (match_operand:SI 2 "const_bi_operand" ""))
-                       (const_int 0)))]
+  [(set (reg:CC CC_REGNUM)
+        (compare:CC (zero_extract:SI
+                     (match_operand:SI 0 "register_operand" "d")
+                     (match_operand:SI 1 "const_uimm5" "")
+                     (match_operand:SI 2 "const_uimm5" ""))
+                    (const_int 0)))]
   ""
   "#"
   ""
@@ -373,26 +481,39 @@
 (define_insn "iorsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (ior:SI (match_operand:SI 1 "register_operand" "0,0,d,d")
-                (match_operand:SI 2 "arith_operand" "K,Q,M,d")))]
+                (match_operand:SI 2 "arith_operand" "I,K,M,d")))]
   ""
-  "@
-   ori     %0, %c2
-   oris    %0, %U2
-   orri    %0, %1, %c2
-   or      %0, %1, %2"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"oris %0, %U2\";
+    case 1: return \"ori  %0, %c2\";
+    case 2: return \"orri %0, %1, %c2\";
+    case 3: return mdp_select (operands, "or", true, "", false);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
 (define_insn "iorsi3_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (ior:SI (match_operand:SI 1 "register_operand" "d")
-                               (match_operand:SI 2 "register_operand" "d"))
+        (compare:CC_NZ (ior:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,K,M,d"))
                        (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d")
+   (set (match_operand:SI 0 "register_operand" "=d,d,d,d")
         (ior:SI (match_dup 1) (match_dup 2)))]
   ""
 {
-  return mdp_select (operands, "or", true, "");
+  switch (which_alternative)
+    {
+    case 0: return \"oris.c %0, %U2\";
+    case 1: return \"ori.c  %0, %c2\";
+    case 2: return \"orri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "or", true, "", true);
+    default: gcc_unreachable ();
+    }
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
@@ -400,11 +521,22 @@
 
 (define_insn "iorsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (ior:SI (match_operand:SI 0 "register_operand" "d")
-                               (match_operand:SI 1 "register_operand" "d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (ior:SI
+                        (match_operand:SI 1 "register_operand" "0,0,d,d")
+                        (match_operand:SI 2 "arith_operand" "I,K,M,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d,d,d"))]
   ""
-  "%[        or.c    r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return \"oris.c %0, %U2\";
+    case 1: return \"ori.c  %0, %c2\";
+    case 2: return \"orri.c %0, %1, %c2\";
+    case 3: return mdp_select (operands, "or", true, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -414,7 +546,9 @@
         (xor:SI (match_operand:SI 1 "register_operand" "d")
                 (match_operand:SI 2 "register_operand" "d")))]
   ""
-  "xor     %0, %1, %2"
+{
+  return mdp_select (operands, "xor", true, "", false);
+}
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
@@ -427,7 +561,7 @@
         (xor:SI (match_dup 1) (match_dup 2)))]
   ""
 {
-  return mdp_select (operands, "xor", true, "");
+  return mdp_select (operands, "xor", true, "", true);
 }
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
@@ -435,11 +569,14 @@
 
 (define_insn "xorsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (xor:SI (match_operand:SI 0 "register_operand" "d")
-                               (match_operand:SI 1 "register_operand" "d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (xor:SI (match_operand:SI 1 "register_operand" "d")
+                               (match_operand:SI 2 "register_operand" "d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
-  "%[        xor.c   r1, %0, %1       %]"
+{
+  return mdp_select (operands, "xor", true, "", true);
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -459,49 +596,35 @@
   [(set_attr "type" "arith,load")
    (set_attr "mode" "SI")])
 
-(define_insn "extendqisi2_cmp"
+(define_insn "*extendqisi2_ucc"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
-                       (ashift:SI (match_operand:SI 0 "register_operand" "d")
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 24))
                        (const_int 24))
-                      (const_int 0)))]
+                      (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d")
+        (sign_extend:SI (match_operand:QI 2 "register_operand" "0")))]
   ""
-  "%[        extsb.c r1, %0       %]"
+  "extsb.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "extendqisi2_ucc"
+(define_insn "*extendqisi2_cmp"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
                        (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 24))
                        (const_int 24))
                       (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d")
-        (sign_extend:SI (match_operand:QI 2 "register_operand" "0")))]
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
   "extsb.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "zero_extendqisi2"
-  [(set (match_operand:SI 0 "register_operand""=d,d")
-        (zero_extend:SI (match_operand:QI 1 "register_operand" "d,m")))]
-  ""
-{
-  switch (which_alternative)
-    {
-    case 0: return \"extzb   %0, %1\";
-    case 1: return mdp_linsn (operands, MDA_BYTE, false);
-    default: gcc_unreachable ();
-    }
-}
-  [(set_attr "type" "arith, load")
-   (set_attr "mode" "SI")])
-
 (define_insn "extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
@@ -517,34 +640,79 @@
   [(set_attr "type" "arith, load")
    (set_attr "mode" "SI")])
 
-(define_insn "extendhisi2_cmp"
+(define_insn "*extendhisi2_ucc"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
-                       (ashift:SI (match_operand:SI 0 "register_operand" "d")
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 16))
                        (const_int 16))
-                      (const_int 0)))]
+                      (const_int 0)))
+  (set (match_operand:SI 0 "register_operand" "=d")
+       (sign_extend:SI (match_operand:HI 2 "register_operand" "0")))]
   ""
-  "%[        extsh.c r1, %0       %]"
+  "extsh.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "extendhisi2_ucc"
+(define_insn "*extendhisi2_cmp"
   [(set (reg:CC_N CC_REGNUM)
         (compare:CC_N (ashiftrt:SI
                        (ashift:SI (match_operand:SI 1 "register_operand" "d")
                                   (const_int 16))
                        (const_int 16))
                       (const_int 0)))
-  (set (match_operand:SI 0 "register_operand" "=d")
-       (sign_extend:SI (match_operand:HI 2 "register_operand" "0")))]
+   (clobber (match_scratch:SI 0 "=d"))]
   ""
   "extsh.c %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=d,d")
+        (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))]
+  ""
+{
+  switch (which_alternative)
+    {
+    case 0: return \"extzb   %0, %1\";
+    case 1: return mdp_linsn (operands, MDA_BYTE, false);
+    default: gcc_unreachable ();
+    }
+  }
+  [(set_attr "type" "arith, load")
+   (set_attr "mode" "SI")])
+
+(define_insn "*zero_extendqisi2_ucc"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 24))
+                       (const_int 24))
+                      (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=d")
+        (zero_extend:SI (match_operand:QI 2 "register_operand" "0")))]
+  ""
+  "extzb.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
+(define_insn "*zero_extendqisi2_cmp"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 24))
+                       (const_int 24))
+                      (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
+  ""
+  "extzb.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
 (define_insn "zero_extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
@@ -560,6 +728,35 @@
   [(set_attr "type" "arith, load")
    (set_attr "mode" "SI")])
 
+(define_insn "*zero_extendhisi2_ucc"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 16))
+                       (const_int 16))
+                      (const_int 0)))
+  (set (match_operand:SI 0 "register_operand" "=d")
+       (zero_extend:SI (match_operand:HI 2 "register_operand" "0")))]
+  ""
+  "extzh.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
+(define_insn "*zero_extendhisi2_cmp"
+  [(set (reg:CC_N CC_REGNUM)
+        (compare:CC_N (lshiftrt:SI
+                       (ashift:SI (match_operand:SI 1 "register_operand" "d")
+                                  (const_int 16))
+                       (const_int 16))
+                      (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d"))]
+  ""
+  "extzh.c %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand" "=l")
         (mult:SI (match_operand:SI 1 "register_operand" "d")
@@ -572,7 +769,8 @@
 
 (define_insn "mulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=x")
-        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
+        (mult:DI (sign_extend:DI
+                  (match_operand:SI 1 "register_operand" "d"))
                  (sign_extend:DI
                   (match_operand:SI 2 "register_operand" "d"))))]
   "!TARGET_SCORE5U"
@@ -582,7 +780,8 @@
 
 (define_insn "umulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=x")
-        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+        (mult:DI (zero_extend:DI
+                  (match_operand:SI 1 "register_operand" "d"))
                  (zero_extend:DI
                   (match_operand:SI 2 "register_operand" "d"))))]
   "!TARGET_SCORE5U"
@@ -635,8 +834,8 @@
 {
   switch (which_alternative)
     {
-    case 0: return mdp_select (operands, "slli", false, "c");
-    case 1: return mdp_select (operands, "sll", false, "");
+    case 0: return mdp_select (operands, "slli", false, "c", true);
+    case 1: return mdp_select (operands, "sll", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -647,13 +846,19 @@
 (define_insn "ashlsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (ashift:SI
-                        (match_operand:SI 0 "register_operand" "d,d")
-                        (match_operand:SI 1 "arith_operand" "J,d"))
-                       (const_int 0)))]
+                        (match_operand:SI 1 "register_operand" "d,d")
+                        (match_operand:SI 2 "arith_operand" "J,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d"))]
   ""
-  "@
-   %[        slli.c  r1, %0, %c1      %]
-   %[        sll.c   r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return mdp_select (operands, "slli", false, "c", true);
+    case 1: return mdp_select (operands, "sll", false, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -682,7 +887,7 @@
   switch (which_alternative)
     {
     case 0: return \"srai.c  %0, %1, %c2\";
-    case 1: return mdp_select (operands, "sra", false, "");
+    case 1: return mdp_select (operands, "sra", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -693,31 +898,16 @@
 (define_insn "ashrsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (ashiftrt:SI
-                        (match_operand:SI 0 "register_operand" "d,d")
-                        (match_operand:SI 1 "arith_operand" "J,d"))
-                       (const_int 0)))]
-  ""
-  "@
-   %[        srai.c  r1, %0, %c1      %]
-   %[        sra.c   r1, %0, %1       %]"
-  [(set_attr "type" "arith")
-   (set_attr "up_c" "yes")
-   (set_attr "mode" "SI")])
-
-(define_insn "ashrsi3_ucc_n"
-  [(set (reg:CC_N CC_REGNUM)
-        (compare:CC_N (ashiftrt:SI
-                       (match_operand:SI 1 "register_operand" "d,d")
-                       (match_operand:SI 2 "arith_operand" "J,d"))
-                      (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=d,d")
-        (ashiftrt:SI (match_dup 1) (match_dup 2)))]
+                        (match_operand:SI 1 "register_operand" "d,d")
+                        (match_operand:SI 2 "arith_operand" "J,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d"))]
   ""
 {
   switch (which_alternative)
     {
     case 0: return \"srai.c  %0, %1, %c2\";
-    case 1: return mdp_select (operands, "sra", false, "");
+    case 1: return mdp_select (operands, "sra", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -725,20 +915,6 @@
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
 
-(define_insn "ashrsi3_cmp_n"
-  [(set (reg:CC_N CC_REGNUM)
-        (compare:CC_N (ashiftrt:SI
-                       (match_operand:SI 0 "register_operand" "d,d")
-                       (match_operand:SI 1 "arith_operand" "J,d"))
-                      (const_int 0)))]
-  ""
-  "@
-   %[        srai.c  r1, %0, %c1      %]
-   %[        sra.c   r1, %0, %1       %]"
-  [(set_attr "type" "arith")
-   (set_attr "up_c" "yes")
-   (set_attr "mode" "SI")])
-
 (define_insn "lshrsi3"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
@@ -762,8 +938,8 @@
 {
   switch (which_alternative)
     {
-    case 0: return mdp_select (operands, "srli", false, "c");
-    case 1: return mdp_select (operands, "srl", false, "");
+    case 0: return mdp_select (operands, "srli", false, "c", true);
+    case 1: return mdp_select (operands, "srl", false, "", true);
     default: gcc_unreachable ();
     }
 }
@@ -774,13 +950,19 @@
 (define_insn "lshrsi3_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
         (compare:CC_NZ (lshiftrt:SI
-                        (match_operand:SI 0 "register_operand" "d,d")
-                        (match_operand:SI 1 "arith_operand" "J,d"))
-                       (const_int 0)))]
+                        (match_operand:SI 1 "register_operand" "d,d")
+                        (match_operand:SI 2 "arith_operand" "J,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=d,d"))]
   ""
-  "@
-   %[        srli.c  r1, %0, %c1      %]
-   %[        srl.c   r1, %0, %1       %]"
+{
+  switch (which_alternative)
+    {
+    case 0: return mdp_select (operands, "srli", false, "c", true);
+    case 1: return mdp_select (operands, "srl", false, "", true);
+    default: gcc_unreachable ();
+    }
+}
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -793,11 +975,24 @@
   [(set_attr "type" "arith")
    (set_attr "mode" "SI")])
 
+(define_insn "*negsi2_cmp"
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ (neg:SI (match_operand:SI 1 "register_operand" "e,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=e,d"))]
+  ""
+  "@
+   neg!    %0, %1
+   neg.c   %0, %1"
+  [(set_attr "type" "arith")
+   (set_attr "up_c" "yes")
+   (set_attr "mode" "SI")])
+
 (define_insn "negsi2_ucc"
-  [(set (reg:CC CC_REGNUM)
-        (compare:CC (neg:SI (match_operand:SI 1 "register_operand" "*e,d"))
-                    (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=*e,d")
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ (neg:SI (match_operand:SI 1 "register_operand" "e,d"))
+                       (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=e,d")
         (neg:SI (match_dup 1)))]
   ""
   "@
@@ -817,9 +1012,9 @@
 
 (define_insn "one_cmplsi2_ucc"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "*e,d"))
+        (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "e,d"))
                        (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=*e,d")
+   (set (match_operand:SI 0 "register_operand" "=e,d")
         (not:SI (match_dup 1)))]
   ""
   "@
@@ -831,12 +1026,13 @@
 
 (define_insn "one_cmplsi2_cmp"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (not:SI (match_operand:SI 0 "register_operand" "*e,d"))
-                       (const_int 0)))]
+        (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "e,d"))
+                       (const_int 0)))
+   (clobber (match_scratch:SI 0 "=e,d"))]
   ""
   "@
-   %[        not!    r1, %0       %]
-   %[        not.c   r1, %0       %]"
+   not!    %0, %1
+   not.c   %0, %1"
   [(set_attr "type" "arith")
    (set_attr "up_c" "yes")
    (set_attr "mode" "SI")])
@@ -877,8 +1073,8 @@
 
 (define_insn "cmpsi_nz"
   [(set (reg:CC_NZ CC_REGNUM)
-        (compare:CC_NZ (match_operand:SI 0 "register_operand" "d,*e,d")
-                       (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+        (compare:CC_NZ (match_operand:SI 0 "register_operand" "d,e,d")
+                       (match_operand:SI 1 "arith_operand" "L,e,d")))]
   ""
   "@
    cmpi.c  %0, %c1
@@ -890,8 +1086,8 @@
 
 (define_insn "cmpsi_n"
   [(set (reg:CC_N CC_REGNUM)
-        (compare:CC_N (match_operand:SI 0 "register_operand" "d,*e,d")
-                      (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+        (compare:CC_N (match_operand:SI 0 "register_operand" "d,e,d")
+                      (match_operand:SI 1 "arith_operand" "L,e,d")))]
   ""
   "@
    cmpi.c  %0, %c1
@@ -901,10 +1097,23 @@
     (set_attr "up_c" "yes")
     (set_attr "mode" "SI")])
 
+(define_insn "*cmpsi_to_addsi"
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ (match_operand:SI 1 "register_operand" "0,d")
+                       (neg:SI (match_operand:SI 2 "register_operand" "e,d"))))
+   (clobber (match_scratch:SI 0 "=e,d"))]
+  ""
+  "@
+   add!    %0, %2
+   add.c   %0, %1, %2"
+   [(set_attr "type" "cmp")
+    (set_attr "up_c" "yes")
+    (set_attr "mode" "SI")])
+
 (define_insn "cmpsi_cc"
   [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_operand:SI 0 "register_operand" "d,*e,d")
-                    (match_operand:SI 1 "arith_operand" "L,*e,d")))]
+        (compare:CC (match_operand:SI 0 "register_operand" "d,e,d")
+                    (match_operand:SI 1 "arith_operand" "L,e,d")))]
   ""
   "@
    cmpi.c  %0, %c1
@@ -1078,17 +1287,17 @@
    (clobber (reg:SI RT_REGNUM))]
   "SIBLING_CALL_P (insn)"
 {
-  if (!flag_pic) 
-    switch (which_alternative) 
+  if (!flag_pic)
+    switch (which_alternative)
       {
       case 0: return \"br%S0   %0\";
       case 1: return \"j       %0\";
       default: gcc_unreachable ();
       }
   else
-    switch (which_alternative) 
+    switch (which_alternative)
       {
-      case 0: return \"mv      r29, %0\;.cpadd  r29\;br      r29\";
+      case 0: return \"mv      r29, %0\;br      r29\";
       case 1: return \"la      r29, %0\;br      r29\";
       default: gcc_unreachable ();
       }
@@ -1112,17 +1321,17 @@
    (clobber (reg:SI RT_REGNUM))]
   "SIBLING_CALL_P (insn)"
 {
-  if (!flag_pic) 
-    switch (which_alternative) 
+  if (!flag_pic)
+    switch (which_alternative)
       {
       case 0: return \"br%S1   %1\";
       case 1: return \"j       %1\";
       default: gcc_unreachable ();
       }
   else
-    switch (which_alternative) 
+    switch (which_alternative)
       {
-      case 0: return \"mv      r29, %1\;.cpadd  r29\;br      r29\";
+      case 0: return \"mv      r29, %1\;br      r29\";
       case 1: return \"la      r29, %1\;br      r29\";
       default: gcc_unreachable ();
       }
@@ -1154,7 +1363,7 @@
   else
      switch (which_alternative)
       {
-      case 0: return \"mv      r29, %0\;.cpadd  r29\;brl     r29\";
+      case 0: return \"mv      r29, %0\;brl     r29\";
       case 1: return \"la      r29, %0\;brl     r29\";
       default: gcc_unreachable ();
       }
@@ -1163,7 +1372,7 @@
 
 (define_expand "call_value"
   [(parallel [(set (match_operand 0 "" "")
-              (call (match_operand 1 "" "") (match_operand 2 "" "")))
+                   (call (match_operand 1 "" "") (match_operand 2 "" "")))
               (use (match_operand 3 "" ""))])]
   ""
 {
@@ -1188,7 +1397,7 @@
   else
     switch (which_alternative)
       {
-      case 0: return \"mv      r29, %1\;.cpadd  r29\;brl     r29\";
+      case 0: return \"mv      r29, %1\;brl     r29\";
       case 1: return \"la      r29, %1\;brl     r29\";
       default: gcc_unreachable ();
       }
@@ -1277,13 +1486,59 @@
 )
 
 (define_insn "cpload"
-  [(unspec:SI [(const_int 1)] 1)]
+  [(unspec_volatile:SI [(const_int 1)] CPLOAD)]
   "flag_pic"
   ".cpload r29"
 )
 
-(define_insn "cprestore"
-  [(unspec:SI [(match_operand:SI 0 "" "")] 2)]
+(define_insn "cprestore_use_fp"
+  [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE)
+   (use (reg:SI FP_REGNUM))]
   "flag_pic"
-  ".cprestore %0"
+  ".cprestore r2, %0"
 )
+
+(define_insn "cprestore_use_sp"
+  [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE)
+   (use (reg:SI SP_REGNUM))]
+  "flag_pic"
+  ".cprestore r0, %0"
+)
+
+(define_expand "doloop_end"
+  [(use (match_operand 0 "" ""))    ; loop pseudo
+   (use (match_operand 1 "" ""))    ; iterations; zero if unknown
+   (use (match_operand 2 "" ""))    ; max iterations
+   (use (match_operand 3 "" ""))    ; loop level
+   (use (match_operand 4 "" ""))]   ; label
+  ""
+  {
+    if (INTVAL (operands[3]) > 1)
+      FAIL;
+
+    if (GET_MODE (operands[0]) == SImode)
+      {
+        rtx sr0 = gen_rtx_REG (SImode, CN_REGNUM);
+        emit_jump_insn (gen_doloop_end_si (sr0, operands[4]));
+      }
+    else
+      FAIL;
+
+    DONE;
+  })
+
+(define_insn "doloop_end_si"
+  [(set (pc)
+        (if_then_else
+         (ne (match_operand:SI 0 "sr0_operand" "")
+             (const_int 0))
+         (label_ref (match_operand 1 "" ""))
+         (pc)))
+   (set (match_dup 0)
+        (plus:SI (match_dup 0)
+                 (const_int -1)))
+   (clobber (reg:CC CC_REGNUM))
+]
+  ""
+  "bcnz %1"
+  [(set_attr "type" "branch")])
Index: gcc/config/score/score-modes.def
===================================================================
--- gcc/config/score/score-modes.def	(revision 120252)
+++ gcc/config/score/score-modes.def	(working copy)
@@ -21,6 +21,5 @@
 /* CC_NZmode should be used if the N (sign) and Z (zero) flag is set correctly.
    CC_Nmode should be used if only the N flag is set correctly.  */
 
-CC_MODE (CC_NZ);
 CC_MODE (CC_N);
-
+CC_MODE (CC_NZ);
Index: gcc/config/score/score-mdaux.h
===================================================================
--- gcc/config/score/score-mdaux.h	(revision 120252)
+++ gcc/config/score/score-mdaux.h	(working copy)
@@ -69,8 +69,6 @@ void mda_gen_cmp (enum machine_mode mode
 
 int mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type);
 
-bool mda_pindex_mem (rtx addr);
-
 int mda_bp (void);
 
 /* Machine Expand.  */
@@ -87,8 +85,6 @@ void mdx_call_value (rtx *ops, bool sibc
 /* Machine Split.  */
 void mds_movdi (rtx *ops);
 
-void mds_addsi (rtx *ops);
-
 void mds_zero_extract_andi (rtx *ops);
 
 /* Machine Print.  */
@@ -100,14 +96,21 @@ const char * mdp_linsn (rtx *ops, enum m
 
 const char * mdp_sinsn (rtx *ops, enum mda_mem_unit unit);
 
-const char * mdp_add_imm_ucc (rtx *ops);
+const char * mdp_select_add_imm (rtx *ops, bool set_cc);
 
 const char * mdp_select (rtx *ops, const char *inst_pre,
-                        bool comu, const char *let);
+                        bool commu, const char *letter, bool set_cc);
 
 const char * mdp_limm (rtx *ops);
 
 const char * mdp_move (rtx *ops);
 
+/* Machine unaligned memory load/store. */
+bool mdx_unaligned_load (rtx* ops);
+
+bool mdx_unaligned_store (rtx* ops);
+
+bool mdx_block_move (rtx* ops);
+
 #endif
 
Index: gcc/config/score/mul-div.S
===================================================================
--- gcc/config/score/mul-div.S	(revision 120252)
+++ gcc/config/score/mul-div.S	(working copy)
@@ -242,7 +242,7 @@ _flush_cache:
         #nop!
         addi    r8, 16
         bcnz    2b
-        .cprestore      12              # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      r3
 #endif
@@ -278,7 +278,7 @@ __mulsi3_loop2:
         cmpi.c  a1, 0
         bne     __mulsi3_loop
         mv      r4, t1
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      ra
         .end    __mulsi3
@@ -334,7 +334,7 @@ __uds_loop3:
 __uds_exit:
         mv      a1, a0
         mv      r4, t4
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      ra
         .end    __udivsi3
@@ -350,7 +350,7 @@ __umodsi3:
         la      r29, __udivsi3
         brl     r29
         mv      r4, a1
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      t3
         .end    __umodsi3
@@ -383,7 +383,7 @@ __divsi3_adjust:
         bge     __divsi3_exit
         neg     r4, r4
 __divsi3_exit:
-        .cprestore 12                   # pic used
+        .cprestore r0, 12               # pic used
         addi    r0, 8                   # pic used
         br      t3
         .end    __divsi3

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH]: for Score backend
  2007-01-04  1:30   ` liqin
@ 2007-01-08  4:53     ` liqin
  0 siblings, 0 replies; 5+ messages in thread
From: liqin @ 2007-01-08  4:53 UTC (permalink / raw)
  To: gcc-patches

Commit Score backend code to gcc-4.2.0 and gcc-trunk repository.

-liqin

gcc-patches-owner@gcc.gnu.org 写于 2007-01-04 09:29:30:

> Can I commit this patch to gcc-4.2.0/gcc-trunk repository,
> because I had put it here for one week, and not get
> any response.
> 
> Rgds
> Liqin
> 
> gcc-patches-owner@gcc.gnu.org 写于 2006-12-29 14:53:32:
> 
> > Hi,
> > this patch did many changes for Score backend.
> > 
> > Changelog:
> >         * config/score/predicates.md (const_uimm5, sr0_operand, 
> > const_simm12,
> >         const_simm15, const_pow2, const_npow2): Added.
> >         * config/score/misc.md (insv, extv, extzv, movmemsi, 
> >         move_lbu_a/b, mov_lhu_a/b etc): Added and fix some bug.
> >         * config/score/score.c (score_address_cost, 
> score_select_cc_mode): 
> > 
> >         Added.
> >         Change CONST_OK_FOR_LETTER_P/EXTRA_CONSTRAINT define.
> >         Update score_rtx_costs for MACRO TARGET_RTX_COSTS.
> >        Update score_print_operand.
> >         * config/score/score.h (DATA_ALIGNMENT, SELECT_CC_MODE): 
Added.
> >         Adjust register allocate order and update some macro define.
> >         * config/score/score-mdaux.c (mdx_unaligned_load, 
> > mdx_unsigned_store,
> >         mdx_block_move_straight, mdx_block_move_loop_head, 
> > mdx_block_move_loop_body,
> >         mdx_block_move_loop_foot, mdx_block_move_loop mdx_block_move):
> >         Added.
> >         (mdx_movsicc, mdp_select_add_imm, mdp_select, 
> > mds_zero_extract_andi, mdp_limm):
> >         Updated and fix some bug and typo.
> >         * config/score/score.md (movqi/hi/si, add/sub/zero/ext): 
> Updated.
> >         (movsf, movdf, doloop_end): Added.
> >         * config/score/t-score-elf (MULTILIB_OPTIONS): Change.
> > 
> > Rgds
> > Liqin
> 
> [附件 "score-20061229.patch" 被 liqin/Sunnorth 删除]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-01-08  4:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-12-28 20:46 [PATCH] Fix _Unwind_Context backward compatibility issues Jakub Jelinek
2006-12-29  6:54 ` [PATCH]: for Score backend liqin
2007-01-04  1:30   ` liqin
2007-01-08  4:53     ` liqin
2007-01-03 18:07 ` [PATCH] Fix _Unwind_Context backward compatibility issues Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).