Patchwork [2/6] Andes nds32: machine description of nds32 porting (3).

login
register
mail settings
Submitter Chung-Ju Wu
Date Sept. 8, 2013, 4:14 p.m.
Message ID <522CA277.2040806@gmail.com>
Download mbox | patch
Permalink /patch/273448/
State New
Headers show

Comments

Chung-Ju Wu - Sept. 8, 2013, 4:14 p.m.
On 7/25/13 5:44 PM, Chung-Ju Wu wrote:
> On 7/24/13 11:52 PM, Chung-Ju Wu wrote:
> So we created another revised patch and here is a summary.
> The new modification is listed as item 5:
> 
>   1. Add GPLv3+exception copyright and license notice in nds32_intrinsic.h.
>   2. Using only one t-mlibs is enough.
>   3. Remove nds32-isa-v2.h, nds32-isa-v3.h, and nds32-isa-v3m.h.
>   4. Add nds32-opts.h included by nds32.opt.
>   5. Use form-feeds (Control-L character) to separate logical sections.
> 

It has been a while since last v2 patch.
I create a new v3 patch to fix some typo and indentation.

Is it OK to apply on the trunk?


Best regards,
jasonwucj
Richard Sandiford - Sept. 15, 2013, 10:33 a.m.
Some comments about the final part:

Chung-Ju Wu <jasonwucj@gmail.com> writes:
> +(define_constraint "Ibms"
> +  "The immediate value with power of 2"
> +  (and (match_code "const_int")
> +       (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M)
> +		    && (floor_log2 (ival) < 8)
> +		    && (ival > 0)
> +		    && (ival == (1 << floor_log2 (ival)))")))

I think the last three lines are equivalent to:

   IN_RANGE (exact_log2 (ival), 0, 7)

> +(define_constraint "Ifex"
> +  "The immediate value with power of 2 minus 1"
> +  (and (match_code "const_int")
> +       (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M)
> +		    && (ival < 256)
> +		    && (ival > 0)
> +		    && (floor_log2 (ival + 1) - 1 < 8)
> +		    && ((ival + 1) == (1 << floor_log2 (ival + 1)))")))

And here:

   IN_RANGE (exact_log2 (ival + 1), 1, 8)

> +#ifndef nds32_OPTS_H
> +#define nds32_OPTS_H

Very minor, but the mixture of case looks odd.

> +;; -------------------------------------------------------------
> +;; Boolean DImode instructions.
> +;; -------------------------------------------------------------
> +
> +;; Boolean and,ior,xor insns.
> +
> +;; 'and' operation.
> +
> +(define_expand "anddi3"
> +  [(set (match_operand:DI 0 "register_operand" "")
> +	(and:DI (match_operand:DI 1 "register_operand" "")
> +		(match_operand:DI 2 "register_operand" "")))]
> +  ""
> +  ""
> +)
> +
> +; Use '#' to split instruction.
> +(define_insn "*anddi3_insn"
> +  [(set (match_operand:DI 0 "register_operand"          "=&r, &r")
> +	(and:DI (match_operand:DI 1 "register_operand"  " %0,  r")
> +		(match_operand:DI 2 "register_operand"  "  r,  r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +; Use '#' to split instruction.
> +; The zero extend of operand 2 clears the high word of the output operand.
> +(define_insn_and_split "*anddi_zesidi_di"
> +  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
> +	(and:DI (zero_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
> +		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
> +  ""
> +  "#"
> +  "reload_completed"
> +  [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))
> +   (set (match_dup 3) (const_int 0))]
> +{
> +  operands[3] = gen_highpart (SImode, operands[0]);
> +  operands[0] = gen_lowpart (SImode, operands[0]);
> +  operands[1] = gen_lowpart (SImode, operands[1]);
> +}
> +  [(set_attr "length" "8")])
> +
> +; Use '#' to split instruction.
> +(define_insn "*anddi_sesidi_di"
> +  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
> +	(and:DI (sign_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
> +		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +
> +;; 'ior' operation.
> +
> +(define_expand "iordi3"
> +  [(set (match_operand:DI 0 "register_operand" "")
> +	(ior:DI (match_operand:DI 1 "register_operand" "")
> +		(match_operand:DI 2 "register_operand" "")))]
> +  ""
> +  ""
> +)
> +
> +; Use '#' to split instruction.
> +(define_insn "*iordi3_insn"
> +  [(set (match_operand:DI 0 "register_operand"          "=&r, &r")
> +	(ior:DI (match_operand:DI 1 "register_operand"  " %0,  r")
> +		(match_operand:DI 2 "register_operand"  "  r,  r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +; Use '#' to split instruction.
> +(define_insn "*iordi_zesidi_di"
> +  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
> +	(ior:DI (zero_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
> +		(match_operand:DI 1 "register_operand"                  "  0, ?r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +; Use '#' to split instruction.
> +(define_insn "*iordi_sesidi_di"
> +  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
> +	(ior:DI (sign_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
> +		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +
> +;; 'xor' operation.
> +
> +(define_expand "xordi3"
> +  [(set (match_operand:DI 0 "register_operand" "")
> +	(xor:DI (match_operand:DI 1 "register_operand" "")
> +		(match_operand:DI 2 "register_operand" "")))]
> +  ""
> +  ""
> +)
> +
> +; Use '#' to split instruction.
> +(define_insn "*xordi3_insn"
> +  [(set (match_operand:DI 0 "register_operand"          "=&r, &r")
> +	(xor:DI (match_operand:DI 1 "register_operand"  " %0,  r")
> +		(match_operand:DI 2 "register_operand"  "  r,  r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +; Use '#' to split instruction.
> +(define_insn "*xordi_zesidi_di"
> +  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
> +	(xor:DI (zero_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
> +		(match_operand:DI 1 "register_operand"                  "  0, ?r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +; Use '#' to split instruction.
> +(define_insn "*xordi_sesidi_di"
> +  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
> +	(xor:DI (sign_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
> +		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
> +  ""
> +  "#"
> +  [(set_attr "length" "8")])
> +
> +
> +;; Split up double word logical operations.
> +
> +;; Split up simple DImode logical operations.  Simply perform the logical
> +;; operation on the upper and lower halves of the registers.
> +(define_split
> +  [(set (match_operand:DI 0 "register_operand" "")
> +	(match_operator:DI 6 "nds32_logical_binary_operator"
> +	  [(match_operand:DI 1 "register_operand" "")
> +	   (match_operand:DI 2 "register_operand" "")]))]
> +  "reload_completed"
> +  [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
> +   (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))]
> +{
> +  /* Note that operands[0], operands[1],
> +     and operands[2] will be assigned new rtx,
> +     so be careful of the order when using them.  */
> +
> +  operands[3] = gen_highpart (SImode, operands[0]);
> +  operands[0] = gen_lowpart  (SImode, operands[0]);
> +
> +  operands[4] = gen_highpart (SImode, operands[1]);
> +  operands[1] = gen_lowpart  (SImode, operands[1]);
> +
> +  operands[5] = gen_highpart (SImode, operands[2]);
> +  operands[2] = gen_lowpart  (SImode, operands[2]);
> +})

In the past it was good practice to define multiword operations like
these so that they could be seen as simple binary operations during
early rtl optimisation.  That shouldn't be necessary now that we have
gimple-level optimisation though.  Instead, splitting from the outset
allows the rtl passes to see and optimise the individual word operations.

If you don't define the patterns, the generic code will split the
operation in the same way.  You should then get the zero_extend
optimisation above for free.  You should also get better code for
cases where operand 2 is constant.

So in theory it should be better to remove these patterns.

> +;; Interrupt Instructions.
> +
> +(define_insn "unspec_volatile_setgie_en"
> +  [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_EN)]
> +  ""
> +  "setgie.e"
> +  [(set_attr "type" "misc")]
> +)
> +
> +(define_insn "unspec_volatile_setgie_dis"
> +  [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_DIS)]
> +  ""
> +  "setgie.d"
> +  [(set_attr "type" "misc")]
> +)

Ah, following up from my comment in part 1 about plain [(unspec ...)]
(as opposed to [(set ... (unspec ...))]) insns being dangerous: it looks
like the intrinsics are all unspec_volatile instead, which is good.
Maybe it'd be worth changing the .c comment to say unspec_volatile instead.

> +;; Load Multiple Insns.
> +;;
> +;; opernads[0] is the first of the consecutive registers.

Typo: operands

> +misr-vector-size=
> +Target Report RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE)
> +Specify the size of each vector for interrupt handler.  The valid value is 4 or 16.

Maybe:

  Specify the size of each interrupt vector, which must be 4 or 16.

> +mcache-block-size=
> +Target Report RejectNegative Joined UInteger Var(nds32_cache_block_size) Init(NDS32_DEFAULT_CACHE_BLOCK_SIZE)
> +Specify the size of each cache block.  The size is the power of 2 in bytes.  The valid value is: 4, 8, 16, 32, 64, 128, 256, or 512.

And here:

  Specify the size of each cache block, which must be a power of 2 between 4 and 512.

> +march=
> +Target RejectNegative Joined Enum(nds32_arch_type) Var(nds32_arch_option) Init(ARCH_V3)
> +Specify the name of the target architecture.  The valid value is: v2, v3, or v3m.

"The valid value..." part shouldn't be needed, since the general options
machinery will print out the enum values.

> +mforce-fp-as-gp
> +Target Report RejectNegative Mask(FORCE_FP_AS_GP)
> +Prevent $fp being allocated during register allocation so that compiler is able to force using $fp to access static and global variables for code-size reduction.  Then compiler will use special directives and code generation to guide linker doing fp-as-gp optimization (NOTE: This is link time optimization so make sure you pass '--relax' option to linker at linking stage).

This seems a bit long for help text.  Also, it might be better to drop
the RejectNegative, so that "-mforce-fp-as-gp -mno-force-fp-as-gp" works.
(This is sometimes useful when dealing with badly-written makefiles.)

> +mex9
> +Target Report RejectNegative Mask(EX9)
> +Use special directives to guide linker doing ex9 optimization (NOTE: This is link time optimization so make sure you pass '--relax' and '--mex9' option to linker at linking stage).

The driver ought to pass down -mex9 as --mex9 instead, via LINK_SPEC,
so that the user doesn't have to.  Maybe it should pass down --relax too,
if that makes sense.  I.e. something like:

  %{mex9: --mex9}

or (if there are no drawbacks to making -mex9 imply --relax):

  %{mex9: --relax --mex9}

> +mno-ctor-dtor
> +Target Report RejectNegative
> +Disable constructor/destructor feature.

How is this option used?

> +;; Merge single move to sign_extend load.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(match_operand:SI 1 "register_operand" ""))
> +   (set (match_operand:SI 2 "register_operand" "")
> +	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
> +					     (match_operand:SI 3 "immediate_operand")))))]
> +  "peep2_reg_dead_p (2, operands[0])"
> +  [(set (match_dup 2)
> +	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
> +					     (match_dup 3)))))]
> +)
> +
> +;; Merge single move to zero_extend load.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(match_operand:SI 1 "register_operand" ""))
> +   (set (match_operand:SI 2 "register_operand" "")
> +	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
> +					     (match_operand:SI 3 "immediate_operand")))))]
> +  "peep2_reg_dead_p (2, operands[0])"
> +  [(set (match_dup 2)
> +	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
> +					     (match_dup 3)))))]
> +)
> +
> +;; Merge single move to load.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(match_operand:SI 1 "register_operand" ""))
> +   (set (match_operand:QIHISI 2 "register_operand" "")
> +	(mem:QIHISI (plus:SI (match_dup 0)
> +			     (match_operand:SI 3 "immediate_operand"))))]
> +  "peep2_reg_dead_p (2, operands[0])"
> +  [(set (match_dup 2)
> +	(mem:QIHISI (plus:SI (match_dup 1)
> +			     (match_dup 3))))]
> +)
> +
> +;; Merge single move to store.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(match_operand:SI 1 "register_operand" ""))
> +   (set (mem:QIHISI (plus:SI (match_dup 0)
> +			     (match_operand:SI 3 "immediate_operand")))
> +	(match_operand:QIHISI 2 "register_operand" ""))]
> +  "peep2_reg_dead_p (2, operands[0])"
> +  [(set (mem:QIHISI (plus:SI (match_dup 1)
> +			     (match_dup 3)))
> +	(match_dup 2))]
> +)

It looks like these peepholes are working around the fact that the move,
sign_extend and zero_extend alternatives are split across several patterns.
Hopefully they won't be needed if each operation has a single define_insn
that lists all the alternatives.

> +;; Merge single addi to sign_extend load.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(plus:SI (match_operand:SI 1 "register_operand" "")
> +		 (match_operand:SI 4 "immediate_operand" "")))
> +   (set (match_operand:SI 2 "register_operand" "")
> +	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
> +					     (match_operand:SI 3 "immediate_operand")))))]
> +  "peep2_reg_dead_p (2, operands[0])
> +   && CONST_INT_P (operands[4])
> +   && CONST_INT_P (operands[3])
> +   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
> +   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
> +  [(set (match_dup 2)
> +	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
> +					     (match_dup 3)))))]
> +{
> +  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
> +			      SImode);
> +})
> +
> +;; Merge single addi to zero_extend load.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(plus:SI (match_operand:SI 1 "register_operand" "")
> +		 (match_operand:SI 4 "immediate_operand" "")))
> +   (set (match_operand:SI 2 "register_operand" "")
> +	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
> +					     (match_operand:SI 3 "immediate_operand")))))]
> +  "peep2_reg_dead_p (2, operands[0])
> +   && CONST_INT_P (operands[4])
> +   && CONST_INT_P (operands[3])
> +   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
> +   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
> +  [(set (match_dup 2)
> +	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
> +					     (match_dup 3)))))]
> +{
> +  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
> +			      SImode);
> +})
> +
> +;; Merge single addi to load.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(plus:SI (match_operand:SI 1 "register_operand" "")
> +		 (match_operand:SI 4 "immediate_operand" "")))
> +   (set (match_operand:QIHISI 2 "register_operand" "")
> +	(mem:QIHISI (plus:SI (match_dup 0)
> +			     (match_operand:SI 3 "immediate_operand"))))]
> +  "peep2_reg_dead_p (2, operands[0])
> +   && CONST_INT_P (operands[4])
> +   && CONST_INT_P (operands[3])
> +   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
> +   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
> +  [(set (match_dup 2)
> +	(mem:QIHISI (plus:SI (match_dup 1)
> +			     (match_dup 3))))]
> +{
> +  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
> +			      SImode);
> +})
> +
> +;; Merge single addi to store.
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +	(plus:SI (match_operand:SI 1 "register_operand" "")
> +		 (match_operand:SI 4 "immediate_operand" "")))
> +   (set (mem:QIHISI (plus:SI (match_dup 0)
> +			     (match_operand:SI 3 "immediate_operand")))
> +	(match_operand:QIHISI 2 "register_operand" ""))]
> +  "peep2_reg_dead_p (2, operands[0])
> +   && CONST_INT_P (operands[4])
> +   && CONST_INT_P (operands[3])
> +   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
> +   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
> +  [(set (mem:QIHISI (plus:SI (match_dup 1)
> +			     (match_dup 3)))
> +	(match_dup 2))]
> +{
> +  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
> +			      SImode);
> +})

TBH I'm suprised these are necessary.  They seem to be doing a simple
forward-propagation of the addition, which is something that the post-reload
optimisers ought to be able to do already.  Could you double-check whether
these still trigger?  It'd be interesting to know why if so.

> +;; Reg, subreg(reg) or const_int.
> +(define_predicate "nds32_reg_or_int_operand"
> +  (ior (match_operand 0 "immediate_operand")
> +       (match_operand 0 "register_operand"))
> +{
> +  if (GET_CODE (op) == SUBREG)
> +    op = SUBREG_REG (op);
> +
> +  if (REG_P (op))
> +    return true;
> +
> +  if (GET_CODE (op) == CONST_INT)
> +    return true;
> +  return false;
> +})
> +
> +(define_predicate "nds32_nonmemory_nonsymbol_operand"
> +  (match_operand 0 "nonmemory_operand")
> +{
> +  switch (GET_CODE (op))
> +    {
> +      case SYMBOL_REF:
> +      case LABEL_REF:
> +      case CONST:
> +        return false;
> +      default:
> +        return true;
> +    }
> +})

Following up from my other comment yesterday, I'm not sure about the
difference between these two.  Is there something that one of the
predicates is trying to reject but the other isn't?  I suppose
"nds32_nonmemory_nonsymbol_operand" could be used in a floating-point
context to allow floating-point constants, but its only use was with SImode.

You also have:

(define_predicate "nds32_reg_constant_operand"
  (ior (match_operand 0 "register_operand")
       (match_operand 0 "const_int_operand")))

which looks like the natural definition of "nds32_reg_or_int_operand".
Would it be possible to just keep that predicate (with whichever name
seems best) and remove the two quoted above?

> +(define_predicate "nds32_rimm15s_operand"
> +  (match_operand 0 "general_operand")
> +{
> +  if (GET_CODE (op) == SUBREG)
> +    op = SUBREG_REG (op);
> +  if (GET_CODE (op) == REG)
> +    return true;
> +  if (GET_CODE (op) != CONST_INT)
> +    return false;
> +
> +  return satisfies_constraint_Is15 (op);
> +})

Maybe:

  (ior (match_operand 0 "register_operand")
       (and (match_operand 0 "const_int_operand")
            (match_test "satisfies_constraint_Is15 (op)")))

In general, defining predicates in terms of other predicates should
lead to better insn-recog.c code (although I'm sure there are exceptions).

> +(define_predicate "nds32_imm5u_operand"
> +  (match_operand 0 "immediate_operand")
> +{
> +  return satisfies_constraint_Iu05 (op);
> +})

Using const_int_operand would be tighter than immediate_operand.

> +(define_special_predicate "nds32_load_multiple_operation"
> +  (match_code "parallel")
> +{
> +  HOST_WIDE_INT count;
> +  int dest_regno;
> +  rtx src_addr;
> +
> +  int i;
> +  rtx elt;
> +
> +  /* Get the counts of elements in the parallel rtx.  */
> +  count = XVECLEN (op, 0);
> +
> +  /* Pick up the first element.  */
> +  elt = XVECEXP (op, 0, 0);
> +
> +  /* Perform some quick check for the first element in the parallel rtx.  */
> +  if (GET_CODE (elt) != SET
> +      || count <= 1
> +      || count > 8
> +      || GET_CODE (SET_DEST (elt)) != REG
> +      || GET_CODE (SET_SRC  (elt)) != MEM)
> +    return false;
> +
> +  dest_regno = REGNO (SET_DEST (elt));
> +  src_addr   = XEXP (SET_SRC (elt), 0);
> +
> +  /* Perform detail check for each element.  */
> +  for (i = 0; i < count; i++)
> +    {
> +      elt = XVECEXP (op, 0, i);
> +
> +      /* Refer to nds32.multiple.md for more information
> +         about following checking.  */
> +      if (GET_CODE (elt) != SET
> +          || GET_CODE (SET_DEST (elt)) != REG
> +          || GET_MODE (SET_DEST (elt)) != SImode
> +          || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i)
> +          || GET_CODE (SET_SRC (elt)) != MEM
> +          || GET_MODE (SET_SRC (elt)) != SImode
> +          || (GET_CODE (src_addr) != REG && GET_CODE (src_addr) != PLUS))
> +        return false;
> +    }
> +
> +  return true;
> +})
> +
> +(define_special_predicate "nds32_store_multiple_operation"
> +  (match_code "parallel")
> +{
> +  HOST_WIDE_INT count;
> +  int src_regno;
> +  rtx dest_addr;
> +
> +  int i;
> +  rtx elt;
> +
> +  /* Get the counts of elements in the parallel rtx.  */
> +  count = XVECLEN (op, 0);
> +
> +  /* Pick up the first element.  */
> +  elt = XVECEXP (op, 0, 0);
> +
> +  /* Perform some quick check for the first element in the parallel rtx.  */
> +  if (GET_CODE (elt) != SET
> +      || count <= 1
> +      || count > 8
> +      || GET_CODE (SET_SRC  (elt)) != REG
> +      || GET_CODE (SET_DEST (elt)) != MEM)
> +    return false;
> +
> +  src_regno = REGNO (SET_SRC (elt));
> +  dest_addr = XEXP (SET_DEST (elt), 0);
> +
> +  /* Perform detail check for each element.  */
> +  for (i = 0; i < count; i++)
> +    {
> +      elt = XVECEXP (op, 0, i);
> +
> +      /* Refer to nds32.multiple.md for more information
> +         about following checking.  */
> +      if (GET_CODE (elt) != SET
> +          || GET_CODE (SET_SRC (elt)) != REG
> +          || GET_MODE (SET_SRC (elt)) != SImode
> +          || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i)
> +          || GET_CODE (SET_DEST (elt)) != MEM
> +          || GET_MODE (SET_DEST (elt)) != SImode
> +          || (GET_CODE (dest_addr) != REG && GET_CODE (dest_addr) != PLUS))
> +        return false;
> +    }
> +
> +  return true;
> +})

These are basically the same, but with SET_SRC and SET_DEST swapped.
It'd be good to have a single nds32.c function that handles both,
with a parameter to choose between loads and stores.

Those are all the comments I had.  Like I say, it seems very clean overall.

Thanks,
Richard

Patch

diff --git gcc/config/nds32/constants.md gcc/config/nds32/constants.md
new file mode 100644
index 0000000..af51117
--- /dev/null
+++ gcc/config/nds32/constants.md
@@ -0,0 +1,55 @@ 
+;; Constant defintions of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; Register numbers.
+(define_constants
+  [(R8_REGNUM  8)
+   (TA_REGNUM 15)
+   (FP_REGNUM 28)
+   (GP_REGNUM 29)
+   (LP_REGNUM 30)
+   (SP_REGNUM 31)
+  ])
+
+
+;; The unpec operation index.
+(define_c_enum "unspec_element" [
+  UNSPEC_STACK_PUSH_MULTIPLE
+  UNSPEC_STACK_POP_MULTIPLE
+  UNSPEC_STACK_V3PUSH
+  UNSPEC_STACK_V3POP
+  UNSPEC_FUNC_RETURN
+])
+
+
+;; The unspec_volatile operation index.
+(define_c_enum "unspec_volatile_element" [
+  UNSPEC_VOLATILE_ISYNC
+  UNSPEC_VOLATILE_ISB
+  UNSPEC_VOLATILE_MFSR
+  UNSPEC_VOLATILE_MFUSR
+  UNSPEC_VOLATILE_MTSR
+  UNSPEC_VOLATILE_MTUSR
+  UNSPEC_VOLATILE_SETGIE_EN
+  UNSPEC_VOLATILE_SETGIE_DIS
+])
+
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/constraints.md gcc/config/nds32/constraints.md
new file mode 100644
index 0000000..40af0ca
--- /dev/null
+++ gcc/config/nds32/constraints.md
@@ -0,0 +1,248 @@ 
+;; Constraint definitions of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; Check 16.8.7 Defining Machine-Specific Constraints for detail.
+
+;; NO contrains can be prefixed with: E F V X g i m n o p r s
+;; Machine-dependent integer: I J K L M N O P
+;; Machine-dependent floating: G H
+
+
+(define_register_constraint "w" "(TARGET_ISA_V3 || TARGET_ISA_V3M) ? LOW_REGS : NO_REGS"
+  "LOW register class $r0 ~ $r7 constraint for V3 ISA")
+
+(define_register_constraint "l" "LOW_REGS"
+  "LOW register class $r0 ~ $r7")
+
+(define_register_constraint "d" "MIDDLE_REGS"
+  "MIDDLE register class $r0 ~ $r11, $r16 ~ $r19")
+
+(define_register_constraint "h" "HIGH_REGS"
+  "HIGH register class $r12 ~ $r14, $r20 ~ $r31")
+
+
+(define_register_constraint "t" "R15_TA_REG"
+  "Temporary Assist register $ta (i.e. $r15)")
+
+(define_register_constraint "k" "STACK_REG"
+  "Stack register $sp")
+
+
+(define_constraint "Iu03"
+  "Unsigned immediate 3-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 3) && ival >= 0")))
+
+(define_constraint "Iu04"
+  "Unsigned immediate 4-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 4) && ival >= 0")))
+
+(define_constraint "Is05"
+  "Signed immediate 5-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 4) && ival >= -(1 << 4)")))
+
+(define_constraint "Iu05"
+  "Unsigned immediate 5-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 5) && ival >= 0")))
+
+;; Ip05 is special and dedicated for v3 movpi45 instruction.
+;; movpi45 has imm5u field but the range is 16 ~ 47.
+(define_constraint "Ip05"
+  "Unsigned immediate 5-bit value for movpi45 instruction with range 16-47"
+  (and (match_code "const_int")
+       (match_test "ival < ((1 << 5) + 16)
+		    && ival >= (0 + 16)
+		    && (TARGET_ISA_V3 || TARGET_ISA_V3M)")))
+
+(define_constraint "Iu06"
+  "Unsigned immediate 6-bit value constraint for addri36.sp instruction"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 6)
+		    && ival >= 0
+		    && (ival % 4 == 0)
+		    && (TARGET_ISA_V3 || TARGET_ISA_V3M)")))
+
+(define_constraint "Iu08"
+  "Unsigned immediate 8-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 8) && ival >= 0")))
+
+(define_constraint "Iu09"
+  "Unsigned immediate 9-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 9) && ival >= 0")))
+
+
+(define_constraint "Is10"
+  "Signed immediate 10-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 9) && ival >= -(1 << 9)")))
+
+(define_constraint "Is11"
+  "Signed immediate 11-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 10) && ival >= -(1 << 10)")))
+
+
+(define_constraint "Is15"
+  "Signed immediate 15-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 14) && ival >= -(1 << 14)")))
+
+(define_constraint "Iu15"
+  "Unsigned immediate 15-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 15) && ival >= 0")))
+
+
+;; Ic15 is special and dedicated for performance extension
+;; 'bclr' (single-bit-clear) instruction.
+;; It is used in andsi3 pattern and recognized for the immediate
+;; which is NOT in the range of imm15u but OK for 'bclr' instruction.
+;; (If the immediate value IS in the range of imm15u,
+;;  we can directly use 'andi' instruction.)
+(define_constraint "Ic15"
+  "A constant which is not in the range of imm15u but ok for bclr instruction"
+  (and (match_code "const_int")
+       (match_test "(ival & 0xffff8000) && nds32_can_use_bclr_p (ival)")))
+
+;; Ie15 is special and dedicated for performance extension
+;; 'bset' (single-bit-set) instruction.
+;; It is used in iorsi3 pattern and recognized for the immediate
+;; which is NOT in the range of imm15u but OK for 'bset' instruction.
+;; (If the immediate value IS in the range of imm15u,
+;;  we can directly use 'ori' instruction.)
+(define_constraint "Ie15"
+  "A constant which is not in the range of imm15u but ok for bset instruction"
+  (and (match_code "const_int")
+       (match_test "(ival & 0xffff8000) && nds32_can_use_bset_p (ival)")))
+
+;; It15 is special and dedicated for performance extension
+;; 'btgl' (single-bit-toggle) instruction.
+;; It is used in xorsi3 pattern and recognized for the immediate
+;; which is NOT in the range of imm15u but OK for 'btgl' instruction.
+;; (If the immediate value IS in the range of imm15u,
+;;  we can directly use 'xori' instruction.)
+(define_constraint "It15"
+  "A constant which is not in the range of imm15u but ok for btgl instruction"
+  (and (match_code "const_int")
+       (match_test "(ival & 0xffff8000) && nds32_can_use_btgl_p (ival)")))
+
+
+;; Ii15 is special and dedicated for v3 isa
+;; 'bitci' (bit-clear-immediate) instruction.
+;; It is used in andsi3 pattern and recognized for the immediate whose
+;; (~ival) value is in the range of imm15u and OK for 'bitci' instruction.
+;; For example, 'andi $r0,$r0,0xfffffffc' can be presented
+;  with 'bitci $r0,$r0,3'.
+(define_constraint "Ii15"
+  "A constant whose compliment value is in the range of imm15u
+   and ok for bitci instruction"
+  (and (match_code "const_int")
+       (match_test "nds32_can_use_bitci_p (ival)")))
+
+
+(define_constraint "Is16"
+  "Signed immediate 16-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 15) && ival >= -(1 << 15)")))
+
+(define_constraint "Is17"
+  "Signed immediate 17-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 16) && ival >= -(1 << 16)")))
+
+
+(define_constraint "Is19"
+  "Signed immediate 19-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 18) && ival >= -(1 << 18)")))
+
+
+(define_constraint "Is20"
+  "Signed immediate 20-bit value"
+  (and (match_code "const_int")
+       (match_test "ival < (1 << 19) && ival >= -(1 << 19)")))
+
+
+(define_constraint "Ispl"
+  "The immediate value that need to be split"
+  (and (match_code "const_int")
+       (match_test "(ival & 0xfff) != 0")))
+
+(define_constraint "Ihig"
+  "The immediate value that can be simply set high 20-bit"
+  (and (match_code "const_int")
+       (match_test "(ival != 0) && ((ival & 0xfff) == 0)")))
+
+
+(define_constraint "Izeb"
+  "The immediate value 0xff"
+  (and (match_code "const_int")
+       (match_test "(ival == 0xff)")))
+
+(define_constraint "Ixls"
+  "The immediate value 0x01"
+  (and (match_code "const_int")
+       (match_test "TARGET_PERF_EXT && (ival == 0x1)")))
+
+(define_constraint "Ix11"
+  "The immediate value 0x7ff"
+  (and (match_code "const_int")
+       (match_test "TARGET_PERF_EXT && (ival == 0x7ff)")))
+
+(define_constraint "Ibms"
+  "The immediate value with power of 2"
+  (and (match_code "const_int")
+       (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M)
+		    && (floor_log2 (ival) < 8)
+		    && (ival > 0)
+		    && (ival == (1 << floor_log2 (ival)))")))
+
+(define_constraint "Ifex"
+  "The immediate value with power of 2 minus 1"
+  (and (match_code "const_int")
+       (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M)
+		    && (ival < 256)
+		    && (ival > 0)
+		    && (floor_log2 (ival + 1) - 1 < 8)
+		    && ((ival + 1) == (1 << floor_log2 (ival + 1)))")))
+
+
+(define_memory_constraint "U33"
+  "Memory constraint for 333 format"
+  (and (match_code "mem")
+       (match_test "nds32_mem_format (op) == ADDRESS_LO_REG_IMM3U")))
+
+(define_memory_constraint "U45"
+  "Memory constraint for 45 format"
+  (and (match_code "mem")
+       (match_test "nds32_mem_format (op) == ADDRESS_REG")))
+
+(define_memory_constraint "U37"
+  "Memory constraint for 37 format"
+  (and (match_code "mem")
+       (match_test "nds32_mem_format (op) == ADDRESS_SP_IMM7U
+		    || nds32_mem_format (op) == ADDRESS_FP_IMM7U")))
+
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/iterators.md gcc/config/nds32/iterators.md
new file mode 100644
index 0000000..6ec5196
--- /dev/null
+++ gcc/config/nds32/iterators.md
@@ -0,0 +1,55 @@ 
+;; Code and mode itertator and attribute definitions
+;; of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;;----------------------------------------------------------------------------
+;; Mode iterators.
+;;----------------------------------------------------------------------------
+
+;; A list of integer modes that are up to one word long.
+(define_mode_iterator QIHISI [QI HI SI])
+
+;; A list of integer modes that are up to one half-word long.
+(define_mode_iterator QIHI [QI HI])
+
+;; A list of the modes that are up to double-word long.
+(define_mode_iterator DIDF [DI DF])
+
+
+;;----------------------------------------------------------------------------
+;; Mode attributes.
+;;----------------------------------------------------------------------------
+
+(define_mode_attr size [(QI "b") (HI "h") (SI "w")])
+
+(define_mode_attr byte [(QI "1") (HI "2") (SI "4")])
+
+
+;;----------------------------------------------------------------------------
+;; Code iterators.
+;;----------------------------------------------------------------------------
+
+
+;;----------------------------------------------------------------------------
+;; Code attributes.
+;;----------------------------------------------------------------------------
+
+
+;;----------------------------------------------------------------------------
diff --git gcc/config/nds32/nds32-modes.def gcc/config/nds32/nds32-modes.def
new file mode 100644
index 0000000..9d32ada
--- /dev/null
+++ gcc/config/nds32/nds32-modes.def
@@ -0,0 +1,21 @@ 
+/* Extra machine modes of Andes NDS32 cpu for GNU compiler
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* So far, there is no need to define any modes for nds32 target.  */
diff --git gcc/config/nds32/nds32-opts.h gcc/config/nds32/nds32-opts.h
new file mode 100644
index 0000000..86d8b4f
--- /dev/null
+++ gcc/config/nds32/nds32-opts.h
@@ -0,0 +1,35 @@ 
+/* Definitions for option handling of Andes NDS32 cpu for GNU compiler
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef nds32_OPTS_H
+#define nds32_OPTS_H
+
+#define NDS32_DEFAULT_CACHE_BLOCK_SIZE 16
+#define NDS32_DEFAULT_ISR_VECTOR_SIZE (TARGET_ISA_V3 ? 4 : 16)
+
+/* The various ANDES ISA.  */
+enum nds32_arch_type
+{
+  ARCH_V2,
+  ARCH_V3,
+  ARCH_V3M
+};
+
+#endif
diff --git gcc/config/nds32/nds32-protos.h gcc/config/nds32/nds32-protos.h
new file mode 100644
index 0000000..a14ee99
--- /dev/null
+++ gcc/config/nds32/nds32-protos.h
@@ -0,0 +1,114 @@ 
+/* Prototypes for exported functions of Andes NDS32 cpu for GNU compiler
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* ------------------------------------------------------------------------ */
+
+/* Defining Data Structures for Per-function Information.  */
+
+extern void nds32_init_expanders (void);
+
+
+/* Register Usage.  */
+
+/* -- How Values Fit in Registers.  */
+
+extern int nds32_hard_regno_nregs (int, enum machine_mode);
+extern int nds32_hard_regno_mode_ok (int, enum machine_mode);
+
+
+/* Register Classes.  */
+
+extern enum reg_class nds32_regno_reg_class (int);
+
+
+/* Stack Layout and Calling Conventions.  */
+
+/* -- Basic Stack Layout.  */
+
+extern rtx nds32_return_addr_rtx (int, rtx);
+
+/* -- Eliminating Frame Pointer and Arg Pointer.  */
+
+extern HOST_WIDE_INT nds32_initial_elimination_offset (unsigned int,
+						       unsigned int);
+
+/* -- Passing Arguments in Registers.  */
+
+extern void nds32_init_cumulative_args (CUMULATIVE_ARGS *,
+					tree, rtx, tree, int);
+
+/* -- Function Entry and Exit.  */
+
+extern void nds32_expand_prologue (void);
+extern void nds32_expand_epilogue (void);
+extern void nds32_expand_prologue_v3push (void);
+extern void nds32_expand_epilogue_v3pop (void);
+
+/* ------------------------------------------------------------------------ */
+
+/* Auxiliary functions for auxiliary macros in nds32.h.  */
+
+extern bool nds32_ls_333_p (rtx, rtx, rtx, enum machine_mode);
+
+/* Auxiliary functions for expanding rtl used in nds32.multiple.md.  */
+
+extern rtx nds32_expand_load_multiple (int, int, rtx, rtx);
+extern rtx nds32_expand_store_multiple (int, int, rtx, rtx);
+extern int nds32_expand_movmemqi (rtx, rtx, rtx, rtx);
+
+/* Auxiliary functions for bit operation detection.  */
+
+extern int nds32_can_use_bclr_p (int);
+extern int nds32_can_use_bset_p (int);
+extern int nds32_can_use_btgl_p (int);
+
+extern int nds32_can_use_bitci_p (int);
+
+/* Auxiliary function for 'Computing the Length of an Insn'.  */
+
+extern int nds32_adjust_insn_length (rtx, int);
+
+/* Auxiliary functions for FP_AS_GP detection.  */
+
+extern bool nds32_symbol_load_store_p (rtx);
+extern int nds32_fp_as_gp_check_available (void);
+
+/* Auxiliary functions for jump table generation.  */
+
+extern const char *nds32_output_casesi_pc_relative (rtx *);
+extern const char *nds32_output_casesi (rtx *);
+
+/* Auxiliary functions to identify 16 bit addresing mode.  */
+
+extern enum nds32_16bit_address_type nds32_mem_format (rtx);
+
+/* Auxiliary functions to output assembly code.  */
+
+extern const char *nds32_output_16bit_store (rtx *, int);
+extern const char *nds32_output_16bit_load (rtx *, int);
+extern const char *nds32_output_32bit_store (rtx *, int);
+extern const char *nds32_output_32bit_load (rtx *, int);
+
+/* Auxiliary functions to decide output alignment or not.  */
+
+extern int nds32_target_alignment (rtx);
+
+/* ------------------------------------------------------------------------ */
diff --git gcc/config/nds32/nds32.doubleword.md gcc/config/nds32/nds32.doubleword.md
new file mode 100644
index 0000000..b74f532
--- /dev/null
+++ gcc/config/nds32/nds32.doubleword.md
@@ -0,0 +1,393 @@ 
+;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; -------------------------------------------------------------
+;; Move DImode/DFmode instructions.
+;; -------------------------------------------------------------
+
+
+(define_expand "movdi"
+  [(set (match_operand:DI 0 "general_operand" "")
+	(match_operand:DI 1 "general_operand" ""))]
+  ""
+{
+  /* Need to force register if mem <- !reg.  */
+  if (GET_CODE (operands[0]) == MEM && !REG_P (operands[1]))
+    operands[1] = force_reg (DImode, operands[1]);
+})
+
+(define_expand "movdf"
+  [(set (match_operand:DF 0 "general_operand" "")
+	(match_operand:DF 1 "general_operand" ""))]
+  ""
+{
+  /* Need to force register if mem <- !reg.  */
+  if (GET_CODE (operands[0]) == MEM && !REG_P (operands[1]))
+    operands[1] = force_reg (DFmode, operands[1]);
+})
+
+
+(define_insn "move_<mode>"
+  [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, m")
+	(match_operand:DIDF 1 "general_operand"      " r, i, m, r"))]
+  ""
+{
+  rtx addr;
+  rtx otherops[5];
+
+  switch (which_alternative)
+    {
+    case 0:
+      return "movd44\t%0, %1";
+
+    case 1:
+      /* reg <- const_int, we ask gcc to split instruction.  */
+      return "#";
+
+    case 2:
+      /* Refer to nds32_legitimate_address_p() in nds32.c,
+         we only allow "reg", "symbol_ref", "const", and "reg + const_int"
+         as address rtx for DImode/DFmode memory access.  */
+      addr = XEXP (operands[1], 0);
+
+      otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
+      otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+      otherops[2] = addr;
+
+      if (REG_P (addr))
+	{
+	  /* (reg) <- (mem (reg)) */
+	  output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops);
+	}
+      else if (GET_CODE (addr) == PLUS)
+	{
+	  /* (reg) <- (mem (plus (reg) (const_int))) */
+	  rtx op0 = XEXP (addr, 0);
+	  rtx op1 = XEXP (addr, 1);
+
+	  if (REG_P (op0))
+	    {
+	      otherops[2] = op0;
+	      otherops[3] = op1;
+	      otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
+	    }
+	  else
+	    {
+	      otherops[2] = op1;
+	      otherops[3] = op0;
+	      otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
+	    }
+
+	  /* To avoid base overwrite when REGNO(%0) == REGNO(%2).  */
+	  if (REGNO (otherops[0]) != REGNO (otherops[2]))
+	    {
+	      output_asm_insn ("lwi\t%0, [%2 + (%3)]", otherops);
+	      output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
+	    }
+	  else
+	    {
+	      output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
+	      output_asm_insn ("lwi\t%0,[ %2 + (%3)]", otherops);
+	    }
+	}
+      else
+	{
+	  /* (reg) <- (mem (symbol_ref ...))
+	     (reg) <- (mem (const ...)) */
+	  output_asm_insn ("lwi.gp\t%0, [ + %2]", otherops);
+	  output_asm_insn ("lwi.gp\t%1, [ + %2 + 4]", otherops);
+	}
+
+      /* We have already used output_asm_insn() by ourself,
+         so return an empty string.  */
+      return "";
+
+    case 3:
+      /* Refer to nds32_legitimate_address_p() in nds32.c,
+         we only allow "reg", "symbol_ref", "const", and "reg + const_int"
+         as address rtx for DImode/DFmode memory access.  */
+      addr = XEXP (operands[0], 0);
+
+      otherops[0] = gen_rtx_REG (SImode, REGNO (operands[1]));
+      otherops[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
+      otherops[2] = addr;
+
+      if (REG_P (addr))
+	{
+	  /* (mem (reg)) <- (reg) */
+	  output_asm_insn ("smw.bi\t%0, [%2], %1, 0", otherops);
+	}
+      else if (GET_CODE (addr) == PLUS)
+	{
+	  /* (mem (plus (reg) (const_int))) <- (reg) */
+	  rtx op0 = XEXP (addr, 0);
+	  rtx op1 = XEXP (addr, 1);
+
+	  if (REG_P (op0))
+	    {
+	      otherops[2] = op0;
+	      otherops[3] = op1;
+	      otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
+	    }
+	  else
+	    {
+	      otherops[2] = op1;
+	      otherops[3] = op0;
+	      otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
+	    }
+
+	  /* To avoid base overwrite when REGNO(%0) == REGNO(%2).  */
+	  if (REGNO (otherops[0]) != REGNO (otherops[2]))
+	    {
+	      output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
+	      output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
+	    }
+	  else
+	    {
+	      output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
+	      output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
+	    }
+	}
+      else
+	{
+	  /* (mem (symbol_ref ...)) <- (reg)
+	     (mem (const ...))      <- (reg) */
+	  output_asm_insn ("swi.gp\t%0, [ + %2]", otherops);
+	  output_asm_insn ("swi.gp\t%1, [ + %2 + 4]", otherops);
+	}
+
+      /* We have already used output_asm_insn() by ourself,
+         so return an empty string.  */
+      return "";
+
+    default:
+      gcc_unreachable ();
+    }
+}
+  [(set_attr "type"   "move,move,move,move")
+   (set_attr "length" "   4,  16,   8,   8")])
+
+(define_split
+  [(set (match_operand:DIDF 0 "register_operand"     "")
+	(match_operand:DIDF 1 "const_double_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 4) (match_dup 5))]
+{
+  /* Construct lowpart rtx.  */
+  operands[2] = gen_lowpart (SImode, operands[0]);
+  operands[3] = gen_lowpart (SImode, operands[1]);
+
+  /* Construct highpart rtx.  */
+  /* Note that operands[1] can be VOIDmode constant,
+     so we need to use gen_highpart_mode().
+     Refer to gcc/emit-rtl.c for more information.  */
+  operands[4] = gen_highpart (SImode, operands[0]);
+  operands[5] = gen_highpart_mode (SImode,
+				   GET_MODE (operands[0]), operands[1]);
+})
+
+;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA.
+;; We only need to split it under V2 ISA or none-16-bit code generation.
+(define_split
+  [(set (match_operand:DIDF 0 "register_operand" "")
+	(match_operand:DIDF 1 "register_operand" ""))]
+  "reload_completed
+   && (TARGET_ISA_V2 || !TARGET_16_BIT)"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 2) (match_dup 3))]
+{
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_highpart (SImode, operands[1]);
+  operands[0] = gen_lowpart (SImode, operands[0]);
+  operands[1] = gen_lowpart (SImode, operands[1]);
+
+  /* Handle a partial overlap.  */
+  if (rtx_equal_p (operands[0], operands[3]))
+    {
+      rtx tmp0 = operands[0];
+      rtx tmp1 = operands[1];
+
+      operands[0] = operands[2];
+      operands[1] = operands[3];
+      operands[2] = tmp0;
+      operands[3] = tmp1;
+    }
+})
+
+;; -------------------------------------------------------------
+;; Boolean DImode instructions.
+;; -------------------------------------------------------------
+
+;; Boolean and,ior,xor insns.
+
+;; 'and' operation.
+
+(define_expand "anddi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(and:DI (match_operand:DI 1 "register_operand" "")
+		(match_operand:DI 2 "register_operand" "")))]
+  ""
+  ""
+)
+
+; Use '#' to split instruction.
+(define_insn "*anddi3_insn"
+  [(set (match_operand:DI 0 "register_operand"          "=&r, &r")
+	(and:DI (match_operand:DI 1 "register_operand"  " %0,  r")
+		(match_operand:DI 2 "register_operand"  "  r,  r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+; Use '#' to split instruction.
+; The zero extend of operand 2 clears the high word of the output operand.
+(define_insn_and_split "*anddi_zesidi_di"
+  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
+	(and:DI (zero_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
+		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 3) (const_int 0))]
+{
+  operands[3] = gen_highpart (SImode, operands[0]);
+  operands[0] = gen_lowpart (SImode, operands[0]);
+  operands[1] = gen_lowpart (SImode, operands[1]);
+}
+  [(set_attr "length" "8")])
+
+; Use '#' to split instruction.
+(define_insn "*anddi_sesidi_di"
+  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
+	(and:DI (sign_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
+		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+
+;; 'ior' operation.
+
+(define_expand "iordi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(ior:DI (match_operand:DI 1 "register_operand" "")
+		(match_operand:DI 2 "register_operand" "")))]
+  ""
+  ""
+)
+
+; Use '#' to split instruction.
+(define_insn "*iordi3_insn"
+  [(set (match_operand:DI 0 "register_operand"          "=&r, &r")
+	(ior:DI (match_operand:DI 1 "register_operand"  " %0,  r")
+		(match_operand:DI 2 "register_operand"  "  r,  r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+; Use '#' to split instruction.
+(define_insn "*iordi_zesidi_di"
+  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
+	(ior:DI (zero_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
+		(match_operand:DI 1 "register_operand"                  "  0, ?r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+; Use '#' to split instruction.
+(define_insn "*iordi_sesidi_di"
+  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
+	(ior:DI (sign_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
+		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+
+;; 'xor' operation.
+
+(define_expand "xordi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(xor:DI (match_operand:DI 1 "register_operand" "")
+		(match_operand:DI 2 "register_operand" "")))]
+  ""
+  ""
+)
+
+; Use '#' to split instruction.
+(define_insn "*xordi3_insn"
+  [(set (match_operand:DI 0 "register_operand"          "=&r, &r")
+	(xor:DI (match_operand:DI 1 "register_operand"  " %0,  r")
+		(match_operand:DI 2 "register_operand"  "  r,  r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+; Use '#' to split instruction.
+(define_insn "*xordi_zesidi_di"
+  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
+	(xor:DI (zero_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
+		(match_operand:DI 1 "register_operand"                  "  0, ?r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+; Use '#' to split instruction.
+(define_insn "*xordi_sesidi_di"
+  [(set (match_operand:DI 0 "register_operand"                          "=&r, &r")
+	(xor:DI (sign_extend:DI (match_operand:SI 2 "register_operand"  "  r,  r"))
+		(match_operand:DI 1 "register_operand"                  "  0,  r")))]
+  ""
+  "#"
+  [(set_attr "length" "8")])
+
+
+;; Split up double word logical operations.
+
+;; Split up simple DImode logical operations.  Simply perform the logical
+;; operation on the upper and lower halves of the registers.
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+	(match_operator:DI 6 "nds32_logical_binary_operator"
+	  [(match_operand:DI 1 "register_operand" "")
+	   (match_operand:DI 2 "register_operand" "")]))]
+  "reload_completed"
+  [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
+   (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))]
+{
+  /* Note that operands[0], operands[1],
+     and operands[2] will be assigned new rtx,
+     so be careful of the order when using them.  */
+
+  operands[3] = gen_highpart (SImode, operands[0]);
+  operands[0] = gen_lowpart  (SImode, operands[0]);
+
+  operands[4] = gen_highpart (SImode, operands[1]);
+  operands[1] = gen_lowpart  (SImode, operands[1]);
+
+  operands[5] = gen_highpart (SImode, operands[2]);
+  operands[2] = gen_lowpart  (SImode, operands[2]);
+})
+
+
+;; -------------------------------------------------------------
diff --git gcc/config/nds32/nds32.intrinsic.md gcc/config/nds32/nds32.intrinsic.md
new file mode 100644
index 0000000..4ee2d85
--- /dev/null
+++ gcc/config/nds32/nds32.intrinsic.md
@@ -0,0 +1,97 @@ 
+;; Intrinsic patterns description of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; ------------------------------------------------------------------------
+
+;; Register Transfer.
+
+(define_insn "unspec_volatile_mfsr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MFSR))]
+  ""
+  "mfsr\t%0, %V1"
+  [(set_attr "type"   "misc")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "unspec_volatile_mfusr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MFUSR))]
+  ""
+  "mfusr\t%0, %V1"
+  [(set_attr "type"   "misc")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "unspec_volatile_mtsr"
+  [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")
+			(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTSR)]
+  ""
+  "mtsr\t%0, %V1"
+  [(set_attr "type"   "misc")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "unspec_volatile_mtusr"
+  [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")
+			(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTUSR)]
+  ""
+  "mtusr\t%0, %V1"
+  [(set_attr "type"   "misc")
+   (set_attr "length"    "4")]
+)
+
+;; ------------------------------------------------------------------------
+
+;; Interrupt Instructions.
+
+(define_insn "unspec_volatile_setgie_en"
+  [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_EN)]
+  ""
+  "setgie.e"
+  [(set_attr "type" "misc")]
+)
+
+(define_insn "unspec_volatile_setgie_dis"
+  [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_DIS)]
+  ""
+  "setgie.d"
+  [(set_attr "type" "misc")]
+)
+
+;; ------------------------------------------------------------------------
+
+;; Cache Synchronization Instructions
+
+(define_insn "unspec_volatile_isync"
+  [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_ISYNC)]
+  ""
+  "isync\t%0"
+  [(set_attr "type" "misc")]
+)
+
+(define_insn "unspec_volatile_isb"
+  [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_ISB)]
+  ""
+  "isb"
+  [(set_attr "type" "misc")]
+)
+
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/nds32.multiple.md gcc/config/nds32/nds32.multiple.md
new file mode 100644
index 0000000..1b3e05b
--- /dev/null
+++ gcc/config/nds32/nds32.multiple.md
@@ -0,0 +1,410 @@ 
+;; Load/Store Multiple patterns description of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.for NDS32.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; Load Multiple Insns.
+;;
+;; opernads[0] is the first of the consecutive registers.
+;; operands[1] is the first memory location.
+;; operands[2] is the number of consecutive registers.
+
+(define_expand "load_multiple"
+  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+			  (match_operand:SI 1 "" ""))
+		     (use (match_operand:SI 2 "" ""))])]
+  ""
+{
+  int maximum;
+
+  /* Because reduced-set regsiters has few registers
+     (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot
+     be used for register allocation),
+     using 8 registers for load_multiple may easily consume all of them.
+     It makes register allocation/spilling hard to work.
+     So we only allow maximum=4 registers for load_multiple
+     under reduced-set registers.  */
+  if (TARGET_REDUCED_REGS)
+    maximum = 4;
+  else
+    maximum = 8;
+
+  /* Here are the conditions that must be all passed,
+     otherwise we have to FAIL this rtx generation:
+       1. The number of consecutive registers must be integer.
+       2. Maximum 4 or 8 registers for lmw.bi instruction
+          (based on this nds32.multiple.md design).
+       3. Minimum 2 registers for lmw.bi instruction
+          (based on this nds32.multiple.md design).
+       4. operands[0] must be register for sure.
+       5. operands[1] must be memory for sure.
+       6. Do not cross $r15 register because it is not allocatable.  */
+  if (GET_CODE (operands[2]) != CONST_INT
+      || INTVAL (operands[2]) > maximum
+      || INTVAL (operands[2]) < 2
+      || GET_CODE (operands[0]) != REG
+      || GET_CODE (operands[1]) != MEM
+      || REGNO (operands[0]) + INTVAL (operands[2]) > TA_REGNUM)
+    FAIL;
+
+  /* For (mem addr), we force_reg on addr here,
+     so that nds32_expand_load_multiple can easily use it.  */
+  operands[3] = nds32_expand_load_multiple (REGNO (operands[0]),
+					    INTVAL (operands[2]),
+					    force_reg (SImode,
+						       XEXP (operands[1], 0)),
+					    operands[1]);
+})
+
+;; Ordinary Load Multiple.
+
+(define_insn "*lmwsi8"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 24))))
+     (set (match_operand:SI 9 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 28))))])]
+  "(XVECLEN (operands[0], 0) == 8)"
+  "lmw.bi\t%2, [%1], %9, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "*lmwsi7"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 20))))
+     (set (match_operand:SI 8 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 24))))])]
+  "(XVECLEN (operands[0], 0) == 7)"
+  "lmw.bi\t%2, [%1], %8, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "*lmwsi6"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 16))))
+     (set (match_operand:SI 7 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 20))))])]
+  "(XVECLEN (operands[0], 0) == 6)"
+  "lmw.bi\t%2, [%1], %7, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "*lmwsi5"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))
+     (set (match_operand:SI 6 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 16))))])]
+  "(XVECLEN (operands[0], 0) == 5)"
+  "lmw.bi\t%2, [%1], %6, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "*lmwsi4"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
+     (set (match_operand:SI 5 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))])]
+  "(XVECLEN (operands[0], 0) == 4)"
+  "lmw.bi\t%2, [%1], %5, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "*lmwsi3"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
+     (set (match_operand:SI 4 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))])]
+  "(XVECLEN (operands[0], 0) == 3)"
+  "lmw.bi\t%2, [%1], %4, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+(define_insn "*lmwsi2"
+  [(match_parallel 0 "nds32_load_multiple_operation"
+    [(set (match_operand:SI 2 "register_operand" "")
+	  (mem:SI (match_operand:SI 1 "register_operand" "r")))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))])]
+  "(XVECLEN (operands[0], 0) == 2)"
+  "lmw.bi\t%2, [%1], %3, 0x0"
+  [(set_attr "type"   "load")
+   (set_attr "length"    "4")]
+)
+
+
+;; Store Multiple Insns.
+;;
+;; operands[0] is the first memory location.
+;; opernads[1] is the first of the consecutive registers.
+;; operands[2] is the number of consecutive registers.
+
+(define_expand "store_multiple"
+  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+			  (match_operand:SI 1 "" ""))
+		     (use (match_operand:SI 2 "" ""))])]
+  ""
+{
+  int maximum;
+
+  /* Because reduced-set regsiters has few registers
+     (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot
+     be used for register allocation),
+     using 8 registers for store_multiple may easily consume all of them.
+     It makes register allocation/spilling hard to work.
+     So we only allow maximum=4 registers for store_multiple
+     under reduced-set registers.  */
+  if (TARGET_REDUCED_REGS)
+    maximum = 4;
+  else
+    maximum = 8;
+
+  /* Here are the conditions that must be all passed,
+     otherwise we have to FAIL this rtx generation:
+       1. The number of consecutive registers must be integer.
+       2. Maximum 4 or 8 registers for smw.bi instruction
+          (based on this nds32.multiple.md design).
+       3. Minimum 2 registers for smw.bi instruction
+          (based on this nds32.multiple.md design).
+       4. operands[0] must be memory for sure.
+       5. operands[1] must be register for sure.
+       6. Do not cross $r15 register because it is not allocatable.  */
+  if (GET_CODE (operands[2]) != CONST_INT
+      || INTVAL (operands[2]) > maximum
+      || INTVAL (operands[2]) < 2
+      || GET_CODE (operands[0]) != MEM
+      || GET_CODE (operands[1]) != REG
+      || REGNO (operands[1]) + INTVAL (operands[2]) > TA_REGNUM)
+    FAIL;
+
+  /* For (mem addr), we force_reg on addr here,
+     so that nds32_expand_store_multiple can easily use it.  */
+  operands[3] = nds32_expand_store_multiple (REGNO (operands[1]),
+					     INTVAL (operands[2]),
+					     force_reg (SImode,
+							XEXP (operands[0], 0)),
+					     operands[0]);
+})
+
+;; Ordinary Store Multiple.
+
+(define_insn "*stmsi8"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+	  (match_operand:SI 4 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+	  (match_operand:SI 5 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+	  (match_operand:SI 6 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+	  (match_operand:SI 7 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+	  (match_operand:SI 8 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 28)))
+	  (match_operand:SI 9 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 8)"
+  "smw.bi\t%2, [%1], %9, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+(define_insn "*stmsi7"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+	  (match_operand:SI 4 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+	  (match_operand:SI 5 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+	  (match_operand:SI 6 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+	  (match_operand:SI 7 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 24)))
+	  (match_operand:SI 8 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 7)"
+  "smw.bi\t%2, [%1], %8, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+(define_insn "*stmsi6"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+	  (match_operand:SI 4 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+	  (match_operand:SI 5 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+	  (match_operand:SI 6 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 20)))
+	  (match_operand:SI 7 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 6)"
+  "smw.bi\t%2, [%1], %7, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+(define_insn "*stmsi5"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+	  (match_operand:SI 4 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+	  (match_operand:SI 5 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
+	  (match_operand:SI 6 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 5)"
+  "smw.bi\t%2, [%1], %6, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+(define_insn "*stmsi4"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+	  (match_operand:SI 4 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
+	  (match_operand:SI 5 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 4)"
+  "smw.bi\t%2, [%1], %5, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+(define_insn "*stmsi3"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
+	  (match_operand:SI 4 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 3)"
+  "smw.bi\t%2, [%1], %4, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+(define_insn "*stmsi2"
+  [(match_parallel 0 "nds32_store_multiple_operation"
+    [(set (mem:SI (match_operand:SI 1 "register_operand" "r"))
+	  (match_operand:SI 2 "register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
+	  (match_operand:SI 3 "register_operand" ""))])]
+  "(XVECLEN (operands[0], 0) == 2)"
+  "smw.bi\t%2, [%1], %3, 0x0"
+  [(set_attr "type"   "store")
+   (set_attr "length"     "4")]
+)
+
+;; Move a block of memory if it is word aligned and MORE than 2 words long.
+;; We could let this apply for blocks of less than this, but it clobbers so
+;; many registers that there is then probably a better way.
+;;
+;; operands[0] is the destination block of memory.
+;; operands[1] is the source block of memory.
+;; operands[2] is the number of bytes to move.
+;; operands[3] is the known shared alignment.
+
+(define_expand "movmemqi"
+  [(match_operand:BLK 0 "general_operand" "")
+   (match_operand:BLK 1 "general_operand" "")
+   (match_operand:SI 2 "const_int_operand" "")
+   (match_operand:SI 3 "const_int_operand" "")]
+  ""
+{
+  if (nds32_expand_movmemqi (operands[0],
+			     operands[1],
+			     operands[2],
+			     operands[3]))
+    DONE;
+
+  FAIL;
+})
+
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/nds32.opt gcc/config/nds32/nds32.opt
new file mode 100644
index 0000000..b7303e3
--- /dev/null
+++ gcc/config/nds32/nds32.opt
@@ -0,0 +1,98 @@ 
+; Options of Andes NDS32 cpu for GNU compiler
+; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+; Contributed by Andes Technology Corporation.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published
+; by the Free Software Foundation; either version 3, or (at your
+; option) any later version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT
+; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+; License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3.  If not see
+; <http://www.gnu.org/licenses/>.
+
+HeaderInclude
+config/nds32/nds32-opts.h
+
+mbig-endian
+Target Report RejectNegative Negative(mlittle-endian) Mask(BIG_ENDIAN)
+Generate code in big-endian mode.
+
+mlittle-endian
+Target Report RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN)
+Generate code in little-endian mode.
+
+mreduced-regs
+Target Report RejectNegative Negative(mfull-regs) Mask(REDUCED_REGS)
+Use reduced-set registers for register allocation.
+
+mfull-regs
+Target Report RejectNegative Negative(mreduced-regs) InverseMask(REDUCED_REGS)
+Use full-set registers for register allocation.
+
+mcmov
+Target Report Mask(CMOV)
+Generate conditional move instructions.
+
+mperf-ext
+Target Report Mask(PERF_EXT)
+Generate performance extension instructions.
+
+mv3push
+Target Report Mask(V3PUSH)
+Generate v3 push25/pop25 instructions.
+
+m16-bit
+Target Report Mask(16_BIT)
+Generate 16-bit instructions.
+
+mgp-direct
+Target Report Mask(GP_DIRECT)
+Generate GP base instructions directly.
+
+misr-vector-size=
+Target Report RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE)
+Specify the size of each vector for interrupt handler.  The valid value is 4 or 16.
+
+mcache-block-size=
+Target Report RejectNegative Joined UInteger Var(nds32_cache_block_size) Init(NDS32_DEFAULT_CACHE_BLOCK_SIZE)
+Specify the size of each cache block.  The size is the power of 2 in bytes.  The valid value is: 4, 8, 16, 32, 64, 128, 256, or 512.
+
+march=
+Target RejectNegative Joined Enum(nds32_arch_type) Var(nds32_arch_option) Init(ARCH_V3)
+Specify the name of the target architecture.  The valid value is: v2, v3, or v3m.
+
+Enum
+Name(nds32_arch_type) Type(enum nds32_arch_type)
+
+EnumValue
+Enum(nds32_arch_type) String(v2) Value(ARCH_V2)
+
+EnumValue
+Enum(nds32_arch_type) String(v3) Value(ARCH_V3)
+
+EnumValue
+Enum(nds32_arch_type) String(v3m) Value(ARCH_V3M)
+
+mforce-fp-as-gp
+Target Report RejectNegative Mask(FORCE_FP_AS_GP)
+Prevent $fp being allocated during register allocation so that compiler is able to force using $fp to access static and global variables for code-size reduction.  Then compiler will use special directives and code generation to guide linker doing fp-as-gp optimization (NOTE: This is link time optimization so make sure you pass '--relax' option to linker at linking stage).
+
+mforbid-fp-as-gp
+Target Report RejectNegative Mask(FORBID_FP_AS_GP)
+Forbid using $fp to access static and global variables.  This option strictly forbids fp-as-gp optimization regardless of '-mforce-fp-as-gp'.
+
+mex9
+Target Report RejectNegative Mask(EX9)
+Use special directives to guide linker doing ex9 optimization (NOTE: This is link time optimization so make sure you pass '--relax' and '--mex9' option to linker at linking stage).
+
+mno-ctor-dtor
+Target Report RejectNegative
+Disable constructor/destructor feature.
diff --git gcc/config/nds32/nds32.peephole2.md gcc/config/nds32/nds32.peephole2.md
new file mode 100644
index 0000000..c1f1f1f
--- /dev/null
+++ gcc/config/nds32/nds32.peephole2.md
@@ -0,0 +1,160 @@ 
+;; define_peephole2 optimization patterns of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; Merge single move to sign_extend load.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "register_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
+	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
+					     (match_operand:SI 3 "immediate_operand")))))]
+  "peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 2)
+	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
+					     (match_dup 3)))))]
+)
+
+;; Merge single move to zero_extend load.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "register_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
+	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
+					     (match_operand:SI 3 "immediate_operand")))))]
+  "peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 2)
+	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
+					     (match_dup 3)))))]
+)
+
+;; Merge single move to load.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "register_operand" ""))
+   (set (match_operand:QIHISI 2 "register_operand" "")
+	(mem:QIHISI (plus:SI (match_dup 0)
+			     (match_operand:SI 3 "immediate_operand"))))]
+  "peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 2)
+	(mem:QIHISI (plus:SI (match_dup 1)
+			     (match_dup 3))))]
+)
+
+;; Merge single move to store.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "register_operand" ""))
+   (set (mem:QIHISI (plus:SI (match_dup 0)
+			     (match_operand:SI 3 "immediate_operand")))
+	(match_operand:QIHISI 2 "register_operand" ""))]
+  "peep2_reg_dead_p (2, operands[0])"
+  [(set (mem:QIHISI (plus:SI (match_dup 1)
+			     (match_dup 3)))
+	(match_dup 2))]
+)
+
+;; ------------------------------------------------------------------------------------
+
+;; Merge single addi to sign_extend load.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(plus:SI (match_operand:SI 1 "register_operand" "")
+		 (match_operand:SI 4 "immediate_operand" "")))
+   (set (match_operand:SI 2 "register_operand" "")
+	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
+					     (match_operand:SI 3 "immediate_operand")))))]
+  "peep2_reg_dead_p (2, operands[0])
+   && CONST_INT_P (operands[4])
+   && CONST_INT_P (operands[3])
+   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
+   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
+  [(set (match_dup 2)
+	(sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
+					     (match_dup 3)))))]
+{
+  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
+			      SImode);
+})
+
+;; Merge single addi to zero_extend load.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(plus:SI (match_operand:SI 1 "register_operand" "")
+		 (match_operand:SI 4 "immediate_operand" "")))
+   (set (match_operand:SI 2 "register_operand" "")
+	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0)
+					     (match_operand:SI 3 "immediate_operand")))))]
+  "peep2_reg_dead_p (2, operands[0])
+   && CONST_INT_P (operands[4])
+   && CONST_INT_P (operands[3])
+   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
+   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
+  [(set (match_dup 2)
+	(zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1)
+					     (match_dup 3)))))]
+{
+  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
+			      SImode);
+})
+
+;; Merge single addi to load.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(plus:SI (match_operand:SI 1 "register_operand" "")
+		 (match_operand:SI 4 "immediate_operand" "")))
+   (set (match_operand:QIHISI 2 "register_operand" "")
+	(mem:QIHISI (plus:SI (match_dup 0)
+			     (match_operand:SI 3 "immediate_operand"))))]
+  "peep2_reg_dead_p (2, operands[0])
+   && CONST_INT_P (operands[4])
+   && CONST_INT_P (operands[3])
+   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
+   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
+  [(set (match_dup 2)
+	(mem:QIHISI (plus:SI (match_dup 1)
+			     (match_dup 3))))]
+{
+  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
+			      SImode);
+})
+
+;; Merge single addi to store.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+	(plus:SI (match_operand:SI 1 "register_operand" "")
+		 (match_operand:SI 4 "immediate_operand" "")))
+   (set (mem:QIHISI (plus:SI (match_dup 0)
+			     (match_operand:SI 3 "immediate_operand")))
+	(match_operand:QIHISI 2 "register_operand" ""))]
+  "peep2_reg_dead_p (2, operands[0])
+   && CONST_INT_P (operands[4])
+   && CONST_INT_P (operands[3])
+   && ((INTVAL (operands[3]) + INTVAL (operands[4])) % <byte> == 0)
+   && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))"
+  [(set (mem:QIHISI (plus:SI (match_dup 1)
+			     (match_dup 3)))
+	(match_dup 2))]
+{
+  operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]),
+			      SImode);
+})
+
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/nds32_intrinsic.h gcc/config/nds32/nds32_intrinsic.h
new file mode 100644
index 0000000..33064a9
--- /dev/null
+++ gcc/config/nds32/nds32_intrinsic.h
@@ -0,0 +1,37 @@ 
+/* Intrinsic definitions of Andes NDS32 cpu for GNU compiler
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Andes Technology Corporation.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _NDS32_INTRINSIC_H
+#define _NDS32_INTRINSIC_H
+
+enum nds32_intrinsic_registers
+{
+  __NDS32_REG_PSW__ = 1024,
+  __NDS32_REG_IPSW__,
+  __NDS32_REG_ITYPE__,
+  __NDS32_REG_IPC__
+};
+
+#endif /* nds32_intrinsic.h */
diff --git gcc/config/nds32/pipelines.md gcc/config/nds32/pipelines.md
new file mode 100644
index 0000000..9c8c56b
--- /dev/null
+++ gcc/config/nds32/pipelines.md
@@ -0,0 +1,29 @@ 
+;; Pipeline descriptions of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_automaton "nds32_machine")
+
+(define_cpu_unit "general_unit" "nds32_machine")
+
+(define_insn_reservation "simple_insn" 1
+			 (eq_attr "type" "unknown,load,store,move,alu,compare,branch,call,misc")
+			 "general_unit")
+
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/predicates.md gcc/config/nds32/predicates.md
new file mode 100644
index 0000000..12f7e68
--- /dev/null
+++ gcc/config/nds32/predicates.md
@@ -0,0 +1,179 @@ 
+;; Predicate definitions of Andes NDS32 cpu for GNU compiler
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Andes Technology Corporation.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_predicate "nds32_equality_comparison_operator"
+  (match_code "eq,ne"))
+
+(define_predicate "nds32_greater_less_comparison_operator"
+  (match_code "gt,ge,lt,le"))
+
+(define_special_predicate "nds32_logical_binary_operator"
+  (match_code "and,ior,xor"))
+
+;; Reg, subreg(reg) or const_int.
+(define_predicate "nds32_reg_or_int_operand"
+  (ior (match_operand 0 "immediate_operand")
+       (match_operand 0 "register_operand"))
+{
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  if (REG_P (op))
+    return true;
+
+  if (GET_CODE (op) == CONST_INT)
+    return true;
+  return false;
+})
+
+(define_predicate "nds32_rimm15s_operand"
+  (match_operand 0 "general_operand")
+{
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    return true;
+  if (GET_CODE (op) != CONST_INT)
+    return false;
+
+  return satisfies_constraint_Is15 (op);
+})
+
+(define_predicate "nds32_nonmemory_nonsymbol_operand"
+  (match_operand 0 "nonmemory_operand")
+{
+  switch (GET_CODE (op))
+    {
+      case SYMBOL_REF:
+      case LABEL_REF:
+      case CONST:
+        return false;
+      default:
+        return true;
+    }
+})
+
+(define_predicate "nds32_symbolic_operand"
+  (match_code "const,symbol_ref,label_ref"))
+
+(define_predicate "nds32_reg_constant_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "const_int_operand")))
+
+(define_predicate "nds32_imm5u_operand"
+  (match_operand 0 "immediate_operand")
+{
+  return satisfies_constraint_Iu05 (op);
+})
+
+(define_special_predicate "nds32_load_multiple_operation"
+  (match_code "parallel")
+{
+  HOST_WIDE_INT count;
+  int dest_regno;
+  rtx src_addr;
+
+  int i;
+  rtx elt;
+
+  /* Get the counts of elements in the parallel rtx.  */
+  count = XVECLEN (op, 0);
+
+  /* Pick up the first element.  */
+  elt = XVECEXP (op, 0, 0);
+
+  /* Perform some quick check for the first element in the parallel rtx.  */
+  if (GET_CODE (elt) != SET
+      || count <= 1
+      || count > 8
+      || GET_CODE (SET_DEST (elt)) != REG
+      || GET_CODE (SET_SRC  (elt)) != MEM)
+    return false;
+
+  dest_regno = REGNO (SET_DEST (elt));
+  src_addr   = XEXP (SET_SRC (elt), 0);
+
+  /* Perform detail check for each element.  */
+  for (i = 0; i < count; i++)
+    {
+      elt = XVECEXP (op, 0, i);
+
+      /* Refer to nds32.multiple.md for more information
+         about following checking.  */
+      if (GET_CODE (elt) != SET
+          || GET_CODE (SET_DEST (elt)) != REG
+          || GET_MODE (SET_DEST (elt)) != SImode
+          || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i)
+          || GET_CODE (SET_SRC (elt)) != MEM
+          || GET_MODE (SET_SRC (elt)) != SImode
+          || (GET_CODE (src_addr) != REG && GET_CODE (src_addr) != PLUS))
+        return false;
+    }
+
+  return true;
+})
+
+(define_special_predicate "nds32_store_multiple_operation"
+  (match_code "parallel")
+{
+  HOST_WIDE_INT count;
+  int src_regno;
+  rtx dest_addr;
+
+  int i;
+  rtx elt;
+
+  /* Get the counts of elements in the parallel rtx.  */
+  count = XVECLEN (op, 0);
+
+  /* Pick up the first element.  */
+  elt = XVECEXP (op, 0, 0);
+
+  /* Perform some quick check for the first element in the parallel rtx.  */
+  if (GET_CODE (elt) != SET
+      || count <= 1
+      || count > 8
+      || GET_CODE (SET_SRC  (elt)) != REG
+      || GET_CODE (SET_DEST (elt)) != MEM)
+    return false;
+
+  src_regno = REGNO (SET_SRC (elt));
+  dest_addr = XEXP (SET_DEST (elt), 0);
+
+  /* Perform detail check for each element.  */
+  for (i = 0; i < count; i++)
+    {
+      elt = XVECEXP (op, 0, i);
+
+      /* Refer to nds32.multiple.md for more information
+         about following checking.  */
+      if (GET_CODE (elt) != SET
+          || GET_CODE (SET_SRC (elt)) != REG
+          || GET_MODE (SET_SRC (elt)) != SImode
+          || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i)
+          || GET_CODE (SET_DEST (elt)) != MEM
+          || GET_MODE (SET_DEST (elt)) != SImode
+          || (GET_CODE (dest_addr) != REG && GET_CODE (dest_addr) != PLUS))
+        return false;
+    }
+
+  return true;
+})
+;; ------------------------------------------------------------------------
diff --git gcc/config/nds32/t-mlibs gcc/config/nds32/t-mlibs
new file mode 100644
index 0000000..d770824
--- /dev/null
+++ gcc/config/nds32/t-mlibs
@@ -0,0 +1,30 @@ 
+# The multilib settings of Andes NDS32 cpu for GNU compiler
+# Copyright (C) 2012-2013 Free Software Foundation, Inc.
+# Contributed by Andes Technology Corporation.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 3, or (at your
+# option) any later version.
+#
+# GCC is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+# License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# We need to build following multilibs:
+#   -mlittle-endian
+#   -mbig-endian
+#
+# We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the
+# driver program which options are defaults for this target and thus
+# do not need to be handled specially.
+MULTILIB_OPTIONS = mlittle-endian/mbig-endian
+
+# ------------------------------------------------------------------------