diff mbox

[1/3] Re-submission of Altera Nios II port, gcc parts

Message ID 5287425C.6040207@codesourcery.com
State New
Headers show

Commit Message

Chung-Lin Tang Nov. 16, 2013, 10:01 a.m. UTC
Hi Bernd,
My response to the various issues you raised are below. The new patch
has been re-tested. Please see if you can approve for committing now.

Thanks,
Chung-Lin

On 13/10/17 10:13 PM, Bernd Schmidt wrote:
> On 07/14/2013 09:54 AM, Chung-Lin Tang wrote:
>> Hi, the last ping of the Nios II patches was:
>> http://gcc.gnu.org/ml/gcc-patches/2013-06/msg01416.html
>>
>> After assessing the state, we feel it would be better to post a
>> re-submission of the newest patches.
> 
> Since this hasn't attracted attention for months I'll have a go at a
> review. I was not involved in this project and haven't seen this code
> before.
> 
>> @@ -4196,6 +4203,7 @@ esac
>>  # version to the per-target configury.
>>  case "$cpu_type" in
>>    alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze | mips \
>> +  | nios2 \
>>    | pa | rs6000 | score | sparc | spu | tilegx | tilepro | xstormy16 | xtensa)
>>      insn="nop"
> 
> Could maybe format this nicer to fill up all but the last line.

Fixed after merge with latest trunk.

>> +;; These are documented for use in inline asm.
>> +(define_register_constraint "D00" "D00_REG" "Hard register 0.")
>> +(define_register_constraint "D01" "D01_REG" "Hard register 1.")
>> +(define_register_constraint "D02" "D02_REG" "Hard register 2.")
> [...]
> 
> This doesn't strike me as a good idea. To really make this work for
> cases where people write things like "D28D13" you'd have to provide all
> the union classes as well which is obviously infeasible. There are
> alternative mechanisms to get assembly to use the registers you want,
> and I'll note that libgcc seems to be using those instead of these
> constraints.
> 
> This probably also slows down the compiler, and it might be worth an
> experiment to see whether deleting these has any effect on register
> allocation.

These constraints/regclasses have been removed.

>> +;; We use the following constraint letters for constants
>> +;;
>> +;;  I: -32768 to -32767
>> +;;  J: 0 to 65535
> 
>> +(define_insn "movhi_internal"
>> +  [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r")
>> +        (match_operand:HI 1 "general_operand"       "rM,m,rM,I,J"))]
> 
> The J alternative is unnecessary. The range 32768...65535 doesn't give a
> valid HImode constant, the RTL representation of integer constants
> always sign extends. Probably you can just use "i" here and in
> movqi_internal.

I'm not sure that 'i' here serves the needed constraint, but I removed
'J' here.

>> +(define_insn "movsi_internal"
>> +  [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r,r")
>> +        (match_operand:SI 1 "general_operand"       "rM,m,rM,I,J,K,S,i"))]
> 
> Not required, but as an experiment you might want to reorder the
> alternatives and sprinkle extra "r"s to get optional reloads and see
> whether that improves code generation. You'd have
> 
> (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r ,r ,r ,r ,r ,r")
> (match_operand:SI 1 "general_operand"      "rM,rM,rm,rI,rJ,rK,rS,ri"))]
> 
> with the register-register move first. It might not make a difference.

Tried experimenting a bit, so far haven't seen any improvements. I'll
keep this as is for now.

>> +;; Split patterns for register alternative cases.
>> +(define_split
>> +  [(set (match_operand:SI 0 "register_operand" "")
>> +        (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
> 
> Could merge into a define_insn_and_split?

This is a post-reload split that only applies to the "r = r"
alternative. ARM also has similar patterns (although they have multiple
such splitters for the various arch-levels)

>> +  "reload_completed"
>> +  [(set (match_dup 0)
>> +        (and:SI (match_dup 1) (const_int 65535)))
>> +   (set (match_dup 0)
>> +        (xor:SI (match_dup 0) (const_int 32768)))
>> +   (set (match_dup 0)
>> +        (plus:SI (match_dup 0) (const_int -32768)))]
>> +  "operands[1] = gen_lowpart (SImode, operands[1]);")
> 
> Is this really faster than two shifts (either as expander or splitter)?

As the scheduler descriptions indicate, shifts have a long latency.
Anyways, this was inherited from the old Altera code.

>> +;; Arithmetic Operations
>> +
>> +(define_insn "addsi3"
>> +  [(set (match_operand:SI 0 "register_operand"          "=r")
>> +        (plus:SI (match_operand:SI 1 "register_operand" "%r")
>> +                 (match_operand:SI 2 "arith_operand"   "rIT")))]
>> +  ""
>> +  "add%i2\\t%0, %1, %z2"
>> +  [(set_attr "type" "alu")])
> 
> [...]
> 
>> +(define_insn "mulsi3"
>> +  [(set (match_operand:SI 0 "register_operand"          "=r")
>> +        (mult:SI (match_operand:SI 1 "register_operand" "%r")
>> +                 (match_operand:SI 2 "arith_operand"    "rI")))]
>> +  "TARGET_HAS_MUL"
>> +  "mul%i2\\t%0, %1, %z2"
>> +  [(set_attr "type" "mul")])
> 
> There seems to be a slight mismatch here between arith_operand and the
> constraints. Unlike in addsi3, "T" (which calls nios2_unspec_reloc_p)
> isn't allowed here and in the other uses of arith_operand. That suggests
> that arith_operand should be split into two different predicates, one
> for addsi3 and one for all the other uses.

I have added a new 'add_regimm_operand' and used it for this case. Note
that this change has somewhat effects on generated code under -fpic,
although the overall code quality appears to be the same.

>> +(define_expand "divsi3"
>> +  [(set (match_operand:SI 0 "register_operand"          "=r")
>> +        (div:SI (match_operand:SI 1 "register_operand"   "r")
>> +                (match_operand:SI 2 "register_operand"   "r")))]
>> +  ""
>> +{
>> +  if (!TARGET_HAS_DIV)
>> +    {
>> +      if (!TARGET_FAST_SW_DIV)
>> +        FAIL;
>> +      else
>> +        {
>> +          if (nios2_emit_expensive_div (operands, SImode))
>> +            DONE;
>> +        }
>> +    }
>> +})
> 
> Shouldn't this FAIL if !nios2_emit_expensive_div (ok so that function
> never returns 0 but still...)?

Fixed, nios2_emit_expensive_div() doesn't need a return value.

>> +;;  Integer logical Operations
>> +
>> +(define_code_iterator LOGICAL [and ior xor])
>> +(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
>> +
>> +(define_insn "<code>si3"
>> +  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
>> +        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
>> +                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
>> +  ""
>> +  "@
>> +    <logical_asm>\\t%0, %1, %z2
>> +    <logical_asm>%i2\\t%0, %1, %2
>> +    <logical_asm>h%i2\\t%0, %1, %U2"
>> +  [(set_attr "type" "alu")])
>> +
>> +(define_insn "*norsi3"
>> +  [(set (match_operand:SI 0 "register_operand"                  "=r")
>> +        (and:SI (not:SI (match_operand:SI 1 "register_operand"  "%r"))
>> +                (not:SI (match_operand:SI 2 "reg_or_0_operand"  "rM"))))]
>> +  ""
>> +  "nor\\t%0, %1, %z2"
>> +  [(set_attr "type" "alu")])
> 
> M constraints (for const0_rtx) and reg_or_0 seem unnecessary, no such
> RTL should make it to this point.

Such RTL does appear under -O0. Removing the 'M' will also
require a bit of re-working the operand printing mechanics; not a lot of
work, but I'd rather keep it as is. The behavior of using the zero
register for a 0-value is also more expected in nios2, I think.

>> +;; Floating point instructions
> 
> Ok, all this stuff is scary, but it seems to be dictated by the hardware.
> 
>> +  "* return nios2_fpu_insn_asm (n2fpu_f<fop3><f>);"
> 
> Minor point - that's an older form, personally I prefer
> {
>   return nios2_fpu_insn_asm (n2fpu_f<fop3><f>);
> }
> over C-in-a-string, but I'm not sure there's any sort of consensus that
> we shouldn't be doing the former.

I originally used the "* ..." form because I wanted to shorten this part
to within a single line, and looks like { ... } works as well. I have
changed those to use the brace form now.

>> +(define_insn "return"
>> +  [(return)]
>> +  "nios2_can_use_return_insn ()"
>> +  "ret"
>> +)
> 
> Could try to also define "simple_return" to get shrink-wrapping. Move
> closing paren to previous line, here and elsewhere. Define a type?

Shrink wrap implemented. My experience was that the dwarf2 generation
pass often borked if shrink-wrap was enabled while epilogue unwinding
wasn't implemented, so the latter was done as well.

>> +(define_expand "call"
>> +  [(parallel [(call (match_operand 0 "" "")
>> +                    (match_operand 1 "" ""))
>> +              (clobber (reg:SI 31))])]
>> +  ""
>> +  "nios2_adjust_call_address (&operands[0]);"
>> +)
> 
> Weird. Why isn't r31 (return address) in CALL_USED_REGS? Should do that
> and lose the clobber unless there's a very good reason.

I now have added r31 to CALL_USED_REGS, which somewhat improved the code
a bit, thanks for catching that.

As for whether the call insn pattern should clobber the RA register,
looking around I see several other targets with this practice; if it
wasn't clobbered, then RA would actually not show up in
df_regs_ever_live_p(), although a workaround would be to add a check of
crtl->is_leaf, like I see in the c6x port.

If you don't object, I'll keep the clobbers there for now.

>> +  [(set_attr "type" "control,control")])
> 
> I think just "control" would be better for the type. Multiple instances.

Done.

>> +;; Integer comparisons
>> +
>> +(define_code_iterator EQNE [eq ne])
>> +(define_insn "nios2_cmp<code>"
>> +  [(set (match_operand:SI 0 "register_operand"           "=r")
>> +        (EQNE:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
>> +                 (match_operand:SI 2 "arith_operand"     "rI")))]
>> +  ""
>> +  "cmp<code>%i2\\t%0, %z1, %z2"
>> +  [(set_attr "type" "alu")])
> 
> Once again, using reg_or_0 and "M" seems pointless.

The compares don't support all operations, with only the second operand
capable of an immediate. Using 'rM' should theoretically allow more
commutative swapping.

>> +(define_insn "trap"
>> +  [(unspec_volatile [(const_int 0)] UNSPECV_TRAP)]
> 
> There's a trap_if rtl code.

Changed to use a trap_if pattern now.

>> +(define_insn "stack_overflow_detect_and_trap"
>> +  [(unspec_volatile [(const_int 0)] UNSPECV_STACK_OVERFLOW_DETECT_AND_TRAP)]
> 
> Likewise. Might even be able to represent the condition.

Done. Changed the stack limit checking to use a ctrap pattern.

>> +/* Local prototypes.  */
> 
> I'd much prefer not to have any of those. Achieve this by putting
>> +struct gcc_target targetm = TARGET_INITIALIZER;
> along with all the necessary definitions at the end of the file (and
> reordering some other functions).

I would rather keep it that way. The ARM backend is another example of this.

>> +/* ??? Might want to redefine TARGET_RETURN_IN_MSB here to handle
>> +   big-endian case; depends on what ABI we choose.  */
> 
> This comment needs to be addressed and deleted.

Comment deleted. Nios2 doesn't yet officially support big-endian, though
we did keep any bits of past attempted BE support code intact.

>> +/* Stack Layout and Calling Conventions */
> 
> Slightly Too Many Caps I Think. Period and two spaces to end comment.
> Elsewhere too for these kinds of section comments.
> 
>> +#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1))
> 
> Nitpicky, but I don't like the name. I'd rather have a
> VALID_ADD_OFFSET_P macro and use its negation.

I am now using !SMALL_INT instead.

>> +static void
>> +save_reg (int regno, unsigned offset)
> 
> Strictly speaking these functions should all have comments describing
> their args and such.

Done.

>> +void
>> +expand_prologue (void)
> 
> This and other globally-visible functions need renaming to have a nios2_
> prefix to avoid confusion.

Done.

>> +{
>> +  int ix;
>> +  HOST_WIDE_INT total_frame_size = compute_frame_size ();
> 
>> +  total_frame_size = compute_frame_size ();
> 
> Done twice. Maybe nios2_compute_frame_layout would be a better name
> since it does more than compute the size.

Done.

>> +  for (ix = 32; ix--;)
>> +    if (save_mask & ((unsigned HOST_WIDE_INT)1 << ix))
> 
> You shouldn't need to cast to HOST_WIDE_INT, just 1u will do (and
> save_mask can be unsigned int).

Reorganized this.

>> +      emit_insn
>> +	(gen_rtx_SET (Pmode, tmp,
>> +		      gen_int_mode (cfun->machine->save_regs_offset,
>> +				    Pmode)));
> 
> Shouldn't have a mode on the SET, but really should just call
> emit_move_insn. Similar cases elsewhere, search for "gen_rtx_SET (Pmode".

I've removed the modes on SET, though I prefer the more bare generation
of the insns in some contexts; emit_move_insn() seems to have a lot
under the hood.

>> +nios2_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
> 
> There's now an ARG_UNUSED macro; I'm not sure whether we're supposed to
> use that or just omit the arg name now that we're using C++.

Grepping around, I see ARG_UNUSED() rarely used currently. I guess
ATTRIBUTE_UNUSED is okay.

>> +/* Return true if REGNO should be saved in a prologue.  */
> 
> "the" prologue?

For the record, I didn't write this comment :)

>> +/* Return the bytes needed to compute the frame pointer from the current
>> +   stack pointer.  */
>> +static HOST_WIDE_INT
>> +compute_frame_size (void)
> 
> Needs renaming to at least prepend nios2_; see above. Comment needs
> expanding since the function does more than what it says.
> 
>> +  HOST_WIDE_INT var_size;       /* # of var. bytes allocated.  */
> 
> Not the first time they occur in this file, but I suppose I should
> mention that these in-line comments are probably just outside our coding
> guidelines.

Deleted the comments outside the struct defs.

>> +  /* Calculate space needed for gp registers.  */
>> +  for (regno = 0; GP_REGNO_P (regno); regno++)
>> +    if (save_reg_p (regno))
>> +      {
>> +	save_mask |= (unsigned HOST_WIDE_INT)1 << regno;
>> +	save_reg_size += 4;
>> +      }
> 
> Not sure I like GP_REGNO_P (regno) as the loop exit condition here.

Changed a bit, see if you like it now :)

>> +  /* If we call eh_return, we need to save the EH data registers.  */
>> +  if (crtl->calls_eh_return)
> 
> Fold this case into save_reg_p maybe? Doesn't matter too much.

Keeping as is...

>> +/* Return nonzero if this function is known to have a null epilogue.
>> +   This allows the optimizer to omit jumps to jumps if no stack
>> +   was created.  */
>> +int
>> +nios2_can_use_return_insn (void)
>> +{
>> +  if (!reload_completed)
>> +    return 0;
>> +
>> +  if (df_regs_ever_live_p (RA_REGNO) || crtl->profile)
>> +    return 0;
>> +
>> +  if (cfun->machine->initialized)
> 
> I think this could be an assert and the if branch unconditional.
> 
>> +    return cfun->machine->total_size == 0;

I simply deleted the "if (cfun->machine->initialized)" clause. An
equivalent check is already in the compute frame routine. The
df_regs_ever_live_p(RA) check here seems unneeded as well.

>> +static void
>> +nios2_set_fpu_custom_code (enum n2fpu_code code, int N, bool override_p)
> 
> Again, add comments for all these. I haven't looked too hard at the
> custom code stuff since it seems unavoidably horrid but doesn't really
> affect anything outside it.
> 
> Parameter N should be lowercase.
> 
>> +  if (!strncasecmp (cfg, "60-1", 4))
> 
> strcmp, several times. At least judging by the docs allowing "60-1fish"
> is unintentional?

I changed them to use strncmp instead. This routine has to work on a
possibly longer target attribute string, hence the 'n' variants.

>> +  /* Check for unsupported options.  */
>> +  if (flag_pic && !TARGET_LINUX_ABI)
>> +    error ("position-independent code requires the Linux ABI");
> 
> Use sorry instead?

Any guidelines on error() vs. sorry()? I don't feel a strong need to
change...

>> +/* Return true if CST is a constant within range of movi/movui/movhi.  */
>> +static bool
>> +nios2_simple_const_p (const_rtx cst)
>> +{
>> +  HOST_WIDE_INT val = INTVAL (cst);
>> +  return (SMALL_INT (val) || SMALL_INT_UNSIGNED (val) || UPPER16_INT (val));
>> +}
> 
> Unnecessary parens around return value. Several cases in this file.

Grepping across the backends, I see numerous such parens around return
value, so I'm leaning on keeping that...

>> +      case CONST_INT:
>> +        if (INTVAL (x) == 0)
>> +          {
>> +            *total = COSTS_N_INSNS (0);
>> +            return true;
>> +          }
>> +        else if (nios2_simple_const_p (x))
>> +          {
>> +            *total = COSTS_N_INSNS (2);
>> +            return true;
> 
> Hmm, really? What about insns that accept a constant as operand,
> shouldn't it be zero cost for those?
> 
>> +      case MULT:
>> +        {
>> +          *total = COSTS_N_INSNS (1);
>> +          return false;
>> +        }
> 
> Really?

This was not really re-worked since the inherited Altera code, so some
are probably sort of weird, but I'd like to work on this cost tuning later.

>> +static rtx
>> +nios2_call_tls_get_addr (rtx ti)
>> +{
>> +  rtx arg = gen_rtx_REG (Pmode, FIRST_ARG_REGNO);
>> +  rtx ret = gen_rtx_REG (Pmode, FIRST_RETVAL_REGNO);
>> +  rtx fn, insn;
>> +  
>> +  if (!nios2_tls_symbol)
>> +    nios2_tls_symbol = init_one_libfunc ("__tls_get_addr");
>> +
>> +  emit_insn (gen_rtx_SET (Pmode, arg, ti));
>> +  fn = gen_rtx_MEM (QImode, nios2_tls_symbol);
>> +  insn = emit_call_insn (gen_call_value (ret, fn, const0_rtx));
>> +  RTL_CONST_CALL_P (insn) = 1;
>> +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), ret);
>> +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg);
>> +
>> +  return ret;
>> +}
> 
> No special relocs to mark such a call?

I don't quite understand what you mean here? The "call_value" pattern
should handle everything correctly.

>> +int
>> +nios2_emit_move_sequence (rtx *operands, enum machine_mode mode)
> 
> Hmm, I would have guessed that most targets would call this
> nios2_expand_move, but grep shows that the two variants are about
> equally common.
> 
>> +/* Divide Support */
>> +
>> +/*
>> +  If -O3 is used, we want to output a table lookup for
> 
> Watch comment formatting.
> 
>> +  divides between small numbers (both num and den >= 0
>> +  and < 0x10).  The overhead of this method in the worse
>> +  case is 40 bytes in the text section (10 insns) and
> 
> "worst case", everywhere.
> 
>> +  256 bytes in the data section.  Additional divides do
>> +  not incur additional penalties in the data section.
>> +
>> +  Code speed is improved for small divides by about 5x
>> +  when using this method in the worse case (~9 cycles
>> +  vs ~45).  And in the worse case divides not within the
>> +  table are penalized by about 10% (~5 cycles vs ~45).
>> +  However in the typical case the penalty is not as bad
>> +  because doing the long divide in only 45 cycles is
>> +  quite optimistic.
>> +
>> +  ??? It would be nice to have some benchmarks other
>> +  than Dhrystone to back this up.
> 
> Um, ok. This is an optimization for dhrystone? That's... interesting.
> 
>> +  ??? Ideally I would like the emit libcall block to contain
> 
> Lose "emit".

Shaped up the comment formatting a bit.

>> +void
>> +nios2_adjust_call_address (rtx *call_op)
>> +{
>> +  rtx addr;
>> +  gcc_assert (MEM_P (*call_op));
>> +  addr = XEXP (*call_op, 0);
>> +  if (flag_pic && CONSTANT_P (addr))
>> +    {
>> +      rtx reg = gen_reg_rtx (Pmode);
>> +      emit_move_insn (reg, nios2_load_pic_address (addr, UNSPEC_PIC_CALL_SYM));
>> +      XEXP (*call_op, 0) = reg;
>> +    }
>> +}
>> +
>> +
>> +
> 
> Some excess newlines here.
> 
>> +/* Branches/Compares.  */
>> +
>> +/* Return in *ALT_CODE and *ALT_OP, an alternate equivalent constant
>> +   comparision, e.g. >= 1 into > 0.  */
> 
> "comparison".
> 
>> +static void
>> +nios2_alternate_compare_const (enum rtx_code code, rtx op,
>> +			       enum rtx_code *alt_code, rtx *alt_op,
>> +			       enum machine_mode mode)
>> +{
>> +  HOST_WIDE_INT opval = INTVAL (op);
>> +  enum rtx_code scode = signed_condition (code);
>> +  *alt_code = ((code == EQ || code == NE) ? code
>> +	       /* The required conversion between [>,>=] and [<,<=] is captured
>> +		  by a reverse + swap of condition codes.  */
>> +	       : reverse_condition (swap_condition (code)));
>> +  *alt_op = ((scode == LT || scode == GE) ? gen_int_mode (opval - 1, mode)
>> +	     : (scode == LE || scode == GT) ? gen_int_mode (opval + 1, mode)
> 
> That's not really equivalent in all cases, right? I don't see anything
> dealing with boundary conditions. It might be that the cases where it
> would fail are already optimized to always-true or always-false, but
> still...
> Also, it doesn't look like this does the right thing for alt_op in the
> csae of unsigned comparisons?

The boundary conditions do seem to always be optimized into
always-true/false or EQ cases, even under -O0.  I have changed the code
to add an assertion to check over/underflows for INTVAL(op) +1/-1.
Supposedly, the code should never need to handle this.


>> +/* Checks if the FPU comparison in *CMP, *OP1, and *OP2 can be supported in
>> +   the current configuration. Perform modifications if MODIFY_P is true.
> 
> Double space. Multiple occurrences in this file.

Fixed across.

>> +/* Return true if register REGNO is a valid index register.
>> +   STRICT_P is true if REG_OK_STRICT is in effect.  */
> 
> It's a bit strange to have definitions for index registers given that
> MAX_REGS_PER_ADDRESS is defined to 1 for this port. One or the other
> must be wrong.

Thanks for catching this, I've made REGNO_OK_FOR_INDEX_P return 0, and
INDEX_REG_CLASS as NO_REGS now.

>> +    case LABEL_REF:
>> +    case CONST_INT:
>> +    case CONST:
>> +    case CONST_DOUBLE:
>> +      /* ??? In here I need to add gp addressing.  */
>> +      ret_val = false;
> 
> Address this comment.
> 
>> +  return ret_val;
> 
> Could really just return directly from the switch cases without the
> extra variable.

Done.

>> +      /* ??? these string names need moving into
>> +         an array in some header file */
> 
> Don't think so. Lose comment or fix it up to conform to coding style.
> 
>> +/* Implement TARGET_ENCODE_SECTION_INFO.  */
> 
> This function together with
> 
>> +/* Set if this has a weak declaration.  */
>> +#define SYMBOL_FLAG_WEAK_DECL   (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
>> +#define SYMBOL_REF_WEAK_DECL_P(RTX) \
>> +  ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0)
> 
> seems a little odd, can the latter not simply be
>   SYMBOL_REF_DECL (RTX) ? DECL_WEAK (SYMBOL_REF_DECL (RTX)) : 0
> rather than mucking about with symbol flags?

Refactored all related code; TARGET_ENCODE_SECTION_INFO is no longer
implemented.

>> +/* Print the operand OP to file stream
>> +   FILE modified by LETTER. LETTER
>> +   can be one of:
> 
> Strange line breaks.
> 
>> +      if (CONSTANT_P (op) && (op != const0_rtx))
> 
> Lose extra parens.
> 
>> +  fprintf (stderr, "Missing way to print (%c) ", letter);
>> +  debug_rtx (op);
>> +  gcc_unreachable ();
>> +}
> 
> and
> 
>> +  fprintf (stderr, "Missing way to print address\n");
>> +  debug_rtx (op);
>> +  gcc_unreachable ();
> 
> Should use output_operand_lossage since this can be caused by user error
> in asms.

Done.

>> +static const char*
> 
> Space. Multiple occurrences.

Fixed across.

>> +/* Instruction scheduler related.  */
>> +
>> +static int
>> +nios2_issue_rate (void)
>> +{
>> +#ifdef MAX_DFA_ISSUE_RATE
>> +  return MAX_DFA_ISSUE_RATE;
>> +#else
>> +  return 1;
>> +#endif
>> +}
> 
> Hmm. If it's just 1 in reality then the default definition is sufficient
> and we don't need this function.

I didn't notice that MAX_DFA_ISSUE_RATE has been deprecated for so long.
I have removed this function now.

>> +  if (mode == BLKmode)
>> +    {
>> +      param_size = int_size_in_bytes (type);
>> +      gcc_assert (param_size >= 0);
>> +      /*
>> +      if (param_size < 0)
>> +        internal_error
>> +          ("Do not know how to handle large structs or variable length types");
>> +      */
> 
> Deal with the problem if necessary then remove both copies of the
> commented-out code.

Argh, thanks for catching this.

>> +  return;
> 
> Lose this (in arg_advance).

Deleted.

>> +  /* ??? Do we need to treat floating point specially, ala MIPS?  */
> 
> Do you?

Comment deleted.

>> +  return (regno == FIRST_RETVAL_REGNO);
> 
> Parens.
> 
>> +/* ??? It may be possible to eliminate the copyback and implement
>> +   my own va_arg type, but that is more work for now.  */
> 
> Function could use a different comment.

Slightly modified the phrasing.

>> +  /* This way of constructing the function tree types will slightly 
>> +     overlap with the N2_FTYPES list used by other builtins.  */
> 
> What does that mean?

I use a looped description for constructing the function tree types used
by the XnXX builtins, where n is an int, and each X may be an int,
pointer, or float; the first X means the return type.

Some of these function types may overlap with the ones built for the
other "fixed" functions, which I believe shouldn't matter, but noting in
the comment. I'll try to re-phrase the wording a bit.

>> +	  if (!custom_insn_opcode (value, VOIDmode))
>> +	    error ("Custom instruction opcode must be compile time "
>> +		   "constant in the range 0-255 for __builtin_custom_%s",
>> +		   custom_builtin_name[index]);
> 
> I think errors should start with lower case.

Done.

>> +  emit_insn (insn);
>> +  return has_target_p ? target : const0_rtx;
>> +}
>> +
>> +
>> +
>> +
> 
> More excess newlines.
> 
>> +/* Implement TARGET_INIT_BUILTINS.  */
> 
> It looks like in this area we're missing a definition of
> TARGET_BUILTIN_DECL. AFAIR not defining that breaks LTO, do you see such
> a problem on this target?

Done adding a TARGET_BUILTIN_DECL implementation.

>> +nios2_expand_builtin_insn (const struct nios2_builtin_desc *d, int n,
>> +			   struct expand_operand* ops, bool has_target_p)
> 
> Again, space before "*", not after.
> 
>> +static rtx
>> +nios2_expand_ldstio_builtin  (tree exp, rtx target,
>> +			      const struct nios2_builtin_desc *d)
> 
> Excess space here.
> 
>> +      /* stxio  */
>> +      /* ldxio */
> 
> Comment style.
> 
>> +/* Implement TARGET_INIT_LIBFUNCS.  */
>> +static void
>> +nios2_init_libfuncs (void)
>> +{
>> +  /* For Linux, we have access to kernel support for atomic operations.  */
>> +  if (TARGET_LINUX_ABI)
>> +    init_sync_libfuncs (UNITS_PER_WORD);
>> +}
>> +
>> +
>> +
>> +
> 
> Newlines.

Done.

>> +	  /* Code conflicts between different __builtin_custom_xnxx calls
>> +	     do not seem to be checked. ???  */
> 
> Is that a problem?

It's just a note of the behavior, I've re-phrased it.

>> +/* Remember the last target of nios2_set_current_function.  */
>> +static GTY(()) tree nios2_previous_fndecl;
> 
> Ok, I don't know any of this stuff. It looks sufficiently similar to
> what i386 is doing that I guess it's ok.
> 
>> +
>> +/* Basic Characteristics of Registers:
>> +Register Number
> 
> Comment formatting.
> 
>> +#define SC_REGNO (12)
>> +#define STATIC_CHAIN_REGNUM SC_REGNO
> 
> There are a lot of these pairs, and it looks like unnecessary double
> indirection. Lose the former in all cases. No parens around constants.

I've reorganized a lot of this in nios2.h.

>> +  D00_REG,
>> +  D01_REG,
>> +  D02_REG,
> 
> See previous comment about these classes.
> 
>> +#define GP_REGNO_FIRST 0
>> +#define GP_REGNO_LAST RA_REGNO
>> +#define GP_NREGS (GP_REGNO_LAST - GP_REGNO_FIRST + 1)
>> +#define GP_REGNO_P(REGNO) ((unsigned) ((REGNO) - GP_REGNO_FIRST) < GP_NREGS)
> 
> Seems a little overly complex.

Simplified a bit.

>> +#define REGNO_REG_CLASS(REGNO) (GP_REGNO_P (REGNO) ? GP_REGS : ALL_REGS)
> 
> Well, if you do decide to keep the Dxx_REG classes... strictly speaking
> they should be returned, although it shouldn't really matter and this
> definition is probably better in practice.

>> +#define INDEX_REG_CLASS ALL_REGS
> 
> See previous comment about MAX_REGS_PER_ADDRESS.
> 
>> +#define SMALL_INT(X) ((X) >= -0x8000 && (X) < 0x8000)
>> +#define SMALL_INT_UNSIGNED(X) ((X) >= 0 && (X) < 0x10000)
>> +#define UPPER16_INT(X) (((X) & 0xffff) == 0)
>> +#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
>> +#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
>> +#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255)
> 
> Minor, but there's not really a consistent naming convention apparent
> for these.
> 
>> +/* Stack Layout and Calling Conventions.  */
>> +
>> +/* The downward variants are used by the compiler,
>> +   the upward ones serve as documentation.  */
>> +#define STACK_GROWS_DOWNWARD
>> +#define FRAME_GROWS_UPWARD
>> +#define ARGS_GROW_UPWARD
> 
> Ugh, no. If you must, #define FRAME_GROWS_DOWNWARD 0, but do not define
> bogus macros.

Cleaned this off.

>> +/* Treat LOC as a byte offset from the stack pointer and round it up
>> +   to the next fully-aligned offset.  */
>> +#define STACK_ALIGN(LOC)                                                \
>> +  (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1))			\
>> +   & ~((PREFERRED_STACK_BOUNDARY / 8) - 1))
> 
> Should move to nios2.c near where it is actually used.

Done.

>> +/* Calling convention definitions.  */
>> +typedef struct nios2_args
>> +{
>> +  int regs_used;
>> +} CUMULATIVE_ARGS;
> 
> Minor, but could be typedef int CUMULATIVE_ARGS if you want.
> 
>> +/* This is to initialize the above unused CUM data type.  */
>> +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
>> +  (nios2_init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS))
> 
> Could be done in-line since it only sets a single value.

I've changed INIT_CUMULATIVE_ARGS to in-line now.

>> +#define SLOW_BYTE_ACCESS 1
> 
> Is this intentional?

Another bit inherited from Altera code. As I noted earlier, we are not
really doing a lot of performance related tuning at this time.

>> +/* It is as good to call a constant function address as to call an address
>> +   kept in a register.
>> +   ??? Not true anymore really. Now that call cannot address full range
>> +   of memory callr may need to be used */
> 
> Hmm.

Sandra will be implementing indirect call trampolines in BFD, the
compiler will not really be involved in this. In any case, indirect
calls are indeed slightly slower. '???' part of comment deleted.

>> +@item T
>> +A @code{const} wrapped @code{UNSPEC} expression,
>> +representing a supported PIC or TLS relocation.
> 
> Might want to place this inside an @ifset INTERNALS, since there
> probably isn't a way for user code to make use of this.

Okay.

>> -The @code{target} attribute is not implemented in GCC versions earlier
>> -than 4.4 for the i386/x86_64 and 4.6 for the PowerPC back ends.  It is
>> -not currently implemented for other back ends.
> 
> I suppose the paragraph should be extended for nios (as it is in the
> pragma documentation) rather than lost.

It is now.

>> +or void if absent. The @code{n} represnts the first parameter
>> +The letters reprsent the following data types:
> 
> "represent", twice.

Fixed, thanks for catching.


Updated ChangeLog:

2013-11-16  Chung-Lin Tang  <cltang@codesourcery.com>
            Sandra Loosemore  <sandra@codesourcery.com>
            Based on patches from Altera Corporation

        * config.gcc (nios2-*-*): Add nios2 config targets.
        * configure.ac (TLS_SECTION_ASM_FLAG): Add nios2 case.
        ("$cpu_type"): Add nios2 as new cpu type.
        * configure: Regenerate.
        * config/nios2/nios2.c: New file.
        * config/nios2/nios2.h: New file.
        * config/nios2/nios2-opts.h: New file.
        * config/nios2/nios2-protos.h: New file.
        * config/nios2/elf.h: New file.
        * config/nios2/elf.opt: New file.
        * config/nios2/linux.h: New file.
        * config/nios2/nios2.opt: New file.
        * config/nios2/nios2.md: New file.
        * config/nios2/predicates.md: New file.
        * config/nios2/constraints.md: New file.
        * config/nios2/t-nios2: New file.
        * common/config/nios2/nios2-common.c: New file.
        * doc/invoke.texi (Nios II options): Document Nios II specific
        options.
        * doc/md.texi (Nios II family): Document Nios II specific
        constraints.
        * doc/extend.texi (Function Specific Option Pragmas): Document
        Nios II supported target pragma functionality.

Comments

Joseph Myers Nov. 16, 2013, 12:39 p.m. UTC | #1
On Sat, 16 Nov 2013, Chung-Lin Tang wrote:

> >> +/* Local prototypes.  */
> > 
> > I'd much prefer not to have any of those. Achieve this by putting
> >> +struct gcc_target targetm = TARGET_INITIALIZER;
> > along with all the necessary definitions at the end of the file (and
> > reordering some other functions).
> 
> I would rather keep it that way. The ARM backend is another example of this.

I agree with Bernd's preference of topologically sorting static functions 
/ variables so forward declarations are only needed in cases of recursion.

I sometimes think it should be possible to convert many target macros to 
hooks, including generating function definitions from the macro 
definitions in .h files, with a lot more automation than I think has been 
used for that before.  Some back ends using a style rather requires 
forward function declarations is a needless complication for that sort of 
thing (indeed, if anyone were working on automated target macro to hook 
conversion, I'd suggest an early automated change should be making all 
back ends define targetm at the end of the file and avoid forward static 
declarations where possible).
Richard Sandiford Nov. 19, 2013, 5:34 p.m. UTC | #2
Chung-Lin Tang <cltang@codesourcery.com> writes:
>>> +;;  Integer logical Operations
>>> +
>>> +(define_code_iterator LOGICAL [and ior xor])
>>> +(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
>>> +
>>> +(define_insn "<code>si3"
>>> +  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
>>> +        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
>>> +                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
>>> +  ""
>>> +  "@
>>> +    <logical_asm>\\t%0, %1, %z2
>>> +    <logical_asm>%i2\\t%0, %1, %2
>>> +    <logical_asm>h%i2\\t%0, %1, %U2"
>>> +  [(set_attr "type" "alu")])
>>> +
>>> +(define_insn "*norsi3"
>>> +  [(set (match_operand:SI 0 "register_operand"                  "=r")
>>> +        (and:SI (not:SI (match_operand:SI 1 "register_operand"  "%r"))
>>> +                (not:SI (match_operand:SI 2 "reg_or_0_operand"  "rM"))))]
>>> +  ""
>>> +  "nor\\t%0, %1, %z2"
>>> +  [(set_attr "type" "alu")])
>> 
>> M constraints (for const0_rtx) and reg_or_0 seem unnecessary, no such
>> RTL should make it to this point.
>
> Such RTL does appear under -O0. Removing the 'M' will also
> require a bit of re-working the operand printing mechanics; not a lot of
> work, but I'd rather keep it as is. The behavior of using the zero
> register for a 0-value is also more expected in nios2, I think.

Hmm, but if we get (not (const_int 0)) then that sounds like a bug,
since (and (not X) (not (const_int 0))) should reduce to (not X).
IMO target-independent code shouldn't try to create the nor-with-0
form and backends shouldn't match it.

Why would removing 'M' affect the printing mechanism?  Naively I'd
have expected:

(define_insn "*norsi3"
  [(set (match_operand:SI 0 "register_operand"                  "=r")
        (and:SI (not:SI (match_operand:SI 1 "register_operand"  "r"))
                (not:SI (match_operand:SI 2 "register_operand"  "r"))))]
  ""
  "nor\\t%0, %1, %2"
  [(set_attr "type" "alu")])

to just work.

>>> +;; Integer comparisons
>>> +
>>> +(define_code_iterator EQNE [eq ne])
>>> +(define_insn "nios2_cmp<code>"
>>> +  [(set (match_operand:SI 0 "register_operand"           "=r")
>>> +        (EQNE:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
>>> +                 (match_operand:SI 2 "arith_operand"     "rI")))]
>>> +  ""
>>> +  "cmp<code>%i2\\t%0, %z1, %z2"
>>> +  [(set_attr "type" "alu")])
>> 
>> Once again, using reg_or_0 and "M" seems pointless.
>
> The compares don't support all operations, with only the second operand
> capable of an immediate. Using 'rM' should theoretically allow more
> commutative swapping.

But rtl-wise, we should never generate an EQ or NE with two constants.
And if one operand is constant then it's supposed to be the second.

The "%" should give commutativity on its own, without the "M".

>>> +      emit_insn
>>> +	(gen_rtx_SET (Pmode, tmp,
>>> +		      gen_int_mode (cfun->machine->save_regs_offset,
>>> +				    Pmode)));
>> 
>> Shouldn't have a mode on the SET, but really should just call
>> emit_move_insn. Similar cases elsewhere, search for "gen_rtx_SET (Pmode".
>
> I've removed the modes on SET, though I prefer the more bare generation
> of the insns in some contexts; emit_move_insn() seems to have a lot
> under the hood.

There shouldn't be anything to be afraid of though.  Target-independent
code would use emit_move_insn for this though, so it needs to just work.

>>> +  HOST_WIDE_INT var_size;       /* # of var. bytes allocated.  */
>> 
>> Not the first time they occur in this file, but I suppose I should
>> mention that these in-line comments are probably just outside our coding
>> guidelines.
>
> Deleted the comments outside the struct defs.

FWIW, I think it was more that comments should be above the field rather
than tagged on the right.  (One of the big problems with right-column comments
is that people tend to make them too short.)

Thanks,
Richard
Chung-Lin Tang Nov. 20, 2013, 4:46 p.m. UTC | #3
On 13/11/20 1:34 AM, Richard Sandiford wrote:
> Chung-Lin Tang <cltang@codesourcery.com> writes:
>>>> +;;  Integer logical Operations
>>>> +
>>>> +(define_code_iterator LOGICAL [and ior xor])
>>>> +(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
>>>> +
>>>> +(define_insn "<code>si3"
>>>> +  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
>>>> +        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
>>>> +                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
>>>> +  ""
>>>> +  "@
>>>> +    <logical_asm>\\t%0, %1, %z2
>>>> +    <logical_asm>%i2\\t%0, %1, %2
>>>> +    <logical_asm>h%i2\\t%0, %1, %U2"
>>>> +  [(set_attr "type" "alu")])
>>>> +
>>>> +(define_insn "*norsi3"
>>>> +  [(set (match_operand:SI 0 "register_operand"                  "=r")
>>>> +        (and:SI (not:SI (match_operand:SI 1 "register_operand"  "%r"))
>>>> +                (not:SI (match_operand:SI 2 "reg_or_0_operand"  "rM"))))]
>>>> +  ""
>>>> +  "nor\\t%0, %1, %z2"
>>>> +  [(set_attr "type" "alu")])
>>>
>>> M constraints (for const0_rtx) and reg_or_0 seem unnecessary, no such
>>> RTL should make it to this point.
>>
>> Such RTL does appear under -O0. Removing the 'M' will also
>> require a bit of re-working the operand printing mechanics; not a lot of
>> work, but I'd rather keep it as is. The behavior of using the zero
>> register for a 0-value is also more expected in nios2, I think.

Will any RTL-level passes, say for example, propagate a zero-constant
into the pattern, without also simplifying it to a NOT pattern? (that's
a question, I don't really know)

Personally, I haven't really seen many cases optimizable to NOR, but I
think keeping the 'M' there is pretty harmless.

> Hmm, but if we get (not (const_int 0)) then that sounds like a bug,
> since (and (not X) (not (const_int 0))) should reduce to (not X).
> IMO target-independent code shouldn't try to create the nor-with-0
> form and backends shouldn't match it.
> 
> Why would removing 'M' affect the printing mechanism?  Naively I'd
> have expected:

The *norsi3 here is of course straightforward. I was referring to other
cases, like the AND/IOR/XOR pattern above, where I wanted to combine
them into a single alternative. That needs a bit more work to reorganize
the nios2_print_operand() cases.

> (define_insn "*norsi3"
>   [(set (match_operand:SI 0 "register_operand"                  "=r")
>         (and:SI (not:SI (match_operand:SI 1 "register_operand"  "r"))
>                 (not:SI (match_operand:SI 2 "register_operand"  "r"))))]
>   ""
>   "nor\\t%0, %1, %2"
>   [(set_attr "type" "alu")])
> 
> to just work.

That will definitely work, though I don't think the zero case does any harm.

>>>> +;; Integer comparisons
>>>> +
>>>> +(define_code_iterator EQNE [eq ne])
>>>> +(define_insn "nios2_cmp<code>"
>>>> +  [(set (match_operand:SI 0 "register_operand"           "=r")
>>>> +        (EQNE:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
>>>> +                 (match_operand:SI 2 "arith_operand"     "rI")))]
>>>> +  ""
>>>> +  "cmp<code>%i2\\t%0, %z1, %z2"
>>>> +  [(set_attr "type" "alu")])
>>>
>>> Once again, using reg_or_0 and "M" seems pointless.
>>
>> The compares don't support all operations, with only the second operand
>> capable of an immediate. Using 'rM' should theoretically allow more
>> commutative swapping.
> 
> But rtl-wise, we should never generate an EQ or NE with two constants.
> And if one operand is constant then it's supposed to be the second.
> 
> The "%" should give commutativity on its own, without the "M".

For EQ/NE I guess that's the case, for the other comparisons I'm not so
sure; I'm not familiar enough with the details of the expander machinery
to claim anything.

If this doesn't carry to other comparisons, I intend to keep it in line
with the other cmp patterns. I experimented a bit with the generated
code, nothing is affected.

>>>> +      emit_insn
>>>> +	(gen_rtx_SET (Pmode, tmp,
>>>> +		      gen_int_mode (cfun->machine->save_regs_offset,
>>>> +				    Pmode)));
>>>
>>> Shouldn't have a mode on the SET, but really should just call
>>> emit_move_insn. Similar cases elsewhere, search for "gen_rtx_SET (Pmode".
>>
>> I've removed the modes on SET, though I prefer the more bare generation
>> of the insns in some contexts; emit_move_insn() seems to have a lot
>> under the hood.
> 
> There shouldn't be anything to be afraid of though.  Target-independent
> code would use emit_move_insn for this though, so it needs to just work.

It will work, and I did use it in some places, though I did not
exhaustively search-and-replace.

For (subtle) performance reasons, emit_move_insn() really does too much
as a backend utility. Usually backend code is already very precise on
what we want to generate.

>>>> +  HOST_WIDE_INT var_size;       /* # of var. bytes allocated.  */
>>>
>>> Not the first time they occur in this file, but I suppose I should
>>> mention that these in-line comments are probably just outside our coding
>>> guidelines.
>>
>> Deleted the comments outside the struct defs.
> 
> FWIW, I think it was more that comments should be above the field rather
> than tagged on the right.  (One of the big problems with right-column comments
> is that people tend to make them too short.)

I will change to use the over-the-top style in the final patch.

Thanks,
Chung-Lin
Richard Sandiford Nov. 20, 2013, 11:21 p.m. UTC | #4
Chung-Lin Tang <cltang@codesourcery.com> writes:
> On 13/11/20 1:34 AM, Richard Sandiford wrote:
>> Chung-Lin Tang <cltang@codesourcery.com> writes:
>>>>> +;;  Integer logical Operations
>>>>> +
>>>>> +(define_code_iterator LOGICAL [and ior xor])
>>>>> +(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
>>>>> +
>>>>> +(define_insn "<code>si3"
>>>>> +  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
>>>>> +        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
>>>>> +                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
>>>>> +  ""
>>>>> +  "@
>>>>> +    <logical_asm>\\t%0, %1, %z2
>>>>> +    <logical_asm>%i2\\t%0, %1, %2
>>>>> +    <logical_asm>h%i2\\t%0, %1, %U2"
>>>>> +  [(set_attr "type" "alu")])
>>>>> +
>>>>> +(define_insn "*norsi3"
>>>>> +  [(set (match_operand:SI 0 "register_operand"                  "=r")
>>>>> +        (and:SI (not:SI (match_operand:SI 1 "register_operand"  "%r"))
>>>>> +                (not:SI (match_operand:SI 2 "reg_or_0_operand"  "rM"))))]
>>>>> +  ""
>>>>> +  "nor\\t%0, %1, %z2"
>>>>> +  [(set_attr "type" "alu")])
>>>>
>>>> M constraints (for const0_rtx) and reg_or_0 seem unnecessary, no such
>>>> RTL should make it to this point.
>>>
>>> Such RTL does appear under -O0. Removing the 'M' will also
>>> require a bit of re-working the operand printing mechanics; not a lot of
>>> work, but I'd rather keep it as is. The behavior of using the zero
>>> register for a 0-value is also more expected in nios2, I think.
>
> Will any RTL-level passes, say for example, propagate a zero-constant
> into the pattern, without also simplifying it to a NOT pattern? (that's
> a question, I don't really know)

No, they shouldn't, because only the simplified form is expected to match.
E.g. forwprop goes to some lengths to do this properly.

> Personally, I haven't really seen many cases optimizable to NOR, but I
> think keeping the 'M' there is pretty harmless.

That's not the way to look at it though.  There should be no
unsimplified rtl in the instruction stream, just like there should
be no non-canonical rtl.  We don't have rules for canonical rtl
because the other forms are "harmful" (in the sense of generating wrong
code or whatever).  We have them so that there aren't too many possible
representations of the same thing, and so that code dealing with existing
rtl patterns can validly expect one "shape" over another.  If we see
something that's generating the wrong rtl form, we should fix it rather
than pander to it.

IMO having (and (not (const_int 0)) (not X)) as an alternative
representation of (not X) falls directly into that category.

>>>>> +;; Integer comparisons
>>>>> +
>>>>> +(define_code_iterator EQNE [eq ne])
>>>>> +(define_insn "nios2_cmp<code>"
>>>>> +  [(set (match_operand:SI 0 "register_operand"           "=r")
>>>>> +        (EQNE:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
>>>>> +                 (match_operand:SI 2 "arith_operand"     "rI")))]
>>>>> +  ""
>>>>> +  "cmp<code>%i2\\t%0, %z1, %z2"
>>>>> +  [(set_attr "type" "alu")])
>>>>
>>>> Once again, using reg_or_0 and "M" seems pointless.
>>>
>>> The compares don't support all operations, with only the second operand
>>> capable of an immediate. Using 'rM' should theoretically allow more
>>> commutative swapping.
>> 
>> But rtl-wise, we should never generate an EQ or NE with two constants.
>> And if one operand is constant then it's supposed to be the second.
>> 
>> The "%" should give commutativity on its own, without the "M".
>
> For EQ/NE I guess that's the case, for the other comparisons I'm not so
> sure; I'm not familiar enough with the details of the expander machinery
> to claim anything.

Sure, but the point is that EQ and NE _are_ commutative, and rtl.texi
says that:

  For commutative binary operations, constants should be placed in the
  second operand.

So...

> If this doesn't carry to other comparisons, I intend to keep it in line
> with the other cmp patterns. I experimented a bit with the generated
> code, nothing is affected.

...no, it doesn't carry over to other comparisons, but it's not supposed to.
Just like you can't add "%" to the other comparisons.

The patterns are including constraints whose only purpose is to match
non-canonical rtl.  That shouldn't happen.

>>>>> +      emit_insn
>>>>> +	(gen_rtx_SET (Pmode, tmp,
>>>>> +		      gen_int_mode (cfun->machine->save_regs_offset,
>>>>> +				    Pmode)));
>>>>
>>>> Shouldn't have a mode on the SET, but really should just call
>>>> emit_move_insn. Similar cases elsewhere, search for "gen_rtx_SET (Pmode".
>>>
>>> I've removed the modes on SET, though I prefer the more bare generation
>>> of the insns in some contexts; emit_move_insn() seems to have a lot
>>> under the hood.
>> 
>> There shouldn't be anything to be afraid of though.  Target-independent
>> code would use emit_move_insn for this though, so it needs to just work.
>
> It will work, and I did use it in some places, though I did not
> exhaustively search-and-replace.
>
> For (subtle) performance reasons, emit_move_insn() really does too much
> as a backend utility. Usually backend code is already very precise on
> what we want to generate.

Hmm, this sounds a bit FUDish.  What subtle reasons do you mean?

If moving a constant into a register is valid as a simple SET
then that's what emit_move_insn should do.

>>>>> +  HOST_WIDE_INT var_size;       /* # of var. bytes allocated.  */
>>>>
>>>> Not the first time they occur in this file, but I suppose I should
>>>> mention that these in-line comments are probably just outside our coding
>>>> guidelines.
>>>
>>> Deleted the comments outside the struct defs.
>> 
>> FWIW, I think it was more that comments should be above the field rather
>> than tagged on the right.  (One of the big problems with right-column comments
>> is that people tend to make them too short.)
>
> I will change to use the over-the-top style in the final patch.

Thanks,
Richard
Chung-Lin Tang Nov. 21, 2013, 4:41 a.m. UTC | #5
On 13/11/21 7:21 AM, Richard Sandiford wrote:
> Chung-Lin Tang <cltang@codesourcery.com> writes:
>> On 13/11/20 1:34 AM, Richard Sandiford wrote:
>>> Chung-Lin Tang <cltang@codesourcery.com> writes:
>>>>>> +;;  Integer logical Operations
>>>>>> +
>>>>>> +(define_code_iterator LOGICAL [and ior xor])
>>>>>> +(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
>>>>>> +
>>>>>> +(define_insn "<code>si3"
>>>>>> +  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
>>>>>> +        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
>>>>>> +                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
>>>>>> +  ""
>>>>>> +  "@
>>>>>> +    <logical_asm>\\t%0, %1, %z2
>>>>>> +    <logical_asm>%i2\\t%0, %1, %2
>>>>>> +    <logical_asm>h%i2\\t%0, %1, %U2"
>>>>>> +  [(set_attr "type" "alu")])
>>>>>> +
>>>>>> +(define_insn "*norsi3"
>>>>>> +  [(set (match_operand:SI 0 "register_operand"                  "=r")
>>>>>> +        (and:SI (not:SI (match_operand:SI 1 "register_operand"  "%r"))
>>>>>> +                (not:SI (match_operand:SI 2 "reg_or_0_operand"  "rM"))))]
>>>>>> +  ""
>>>>>> +  "nor\\t%0, %1, %z2"
>>>>>> +  [(set_attr "type" "alu")])
>>>>>
>>>>> M constraints (for const0_rtx) and reg_or_0 seem unnecessary, no such
>>>>> RTL should make it to this point.
>>>>
>>>> Such RTL does appear under -O0. Removing the 'M' will also
>>>> require a bit of re-working the operand printing mechanics; not a lot of
>>>> work, but I'd rather keep it as is. The behavior of using the zero
>>>> register for a 0-value is also more expected in nios2, I think.
>>
>> Will any RTL-level passes, say for example, propagate a zero-constant
>> into the pattern, without also simplifying it to a NOT pattern? (that's
>> a question, I don't really know)
> 
> No, they shouldn't, because only the simplified form is expected to match.
> E.g. forwprop goes to some lengths to do this properly.
> 
>> Personally, I haven't really seen many cases optimizable to NOR, but I
>> think keeping the 'M' there is pretty harmless.
> 
> That's not the way to look at it though.  There should be no
> unsimplified rtl in the instruction stream, just like there should
> be no non-canonical rtl.  We don't have rules for canonical rtl
> because the other forms are "harmful" (in the sense of generating wrong
> code or whatever).  We have them so that there aren't too many possible
> representations of the same thing, and so that code dealing with existing
> rtl patterns can validly expect one "shape" over another.  If we see
> something that's generating the wrong rtl form, we should fix it rather
> than pander to it.
> IMO having (and (not (const_int 0)) (not X)) as an alternative
> representation of (not X) falls directly into that category.

I'm not saying we tolerate "wrong" RTL form, but rather that, it should
be an issue of the RTL passes, not the backend. The backend should just
be as much as possible, a  "machine description".

Saying you don't need to describe a particular thing in the backend
because "GCC doesn't need that" sounds like a spill-over of internal
details. In theory, a backend writer shouldn't need to care for such things.

>>>>>> +;; Integer comparisons
>>>>>> +
>>>>>> +(define_code_iterator EQNE [eq ne])
>>>>>> +(define_insn "nios2_cmp<code>"
>>>>>> +  [(set (match_operand:SI 0 "register_operand"           "=r")
>>>>>> +        (EQNE:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
>>>>>> +                 (match_operand:SI 2 "arith_operand"     "rI")))]
>>>>>> +  ""
>>>>>> +  "cmp<code>%i2\\t%0, %z1, %z2"
>>>>>> +  [(set_attr "type" "alu")])
>>>>>
>>>>> Once again, using reg_or_0 and "M" seems pointless.
>>>>
>>>> The compares don't support all operations, with only the second operand
>>>> capable of an immediate. Using 'rM' should theoretically allow more
>>>> commutative swapping.
>>>
>>> But rtl-wise, we should never generate an EQ or NE with two constants.
>>> And if one operand is constant then it's supposed to be the second.
>>>
>>> The "%" should give commutativity on its own, without the "M".
>>
>> For EQ/NE I guess that's the case, for the other comparisons I'm not so
>> sure; I'm not familiar enough with the details of the expander machinery
>> to claim anything.
> 
> Sure, but the point is that EQ and NE _are_ commutative, and rtl.texi
> says that:
> 
>   For commutative binary operations, constants should be placed in the
>   second operand.
> 
> So...
> 
>> If this doesn't carry to other comparisons, I intend to keep it in line
>> with the other cmp patterns. I experimented a bit with the generated
>> code, nothing is affected.
> 
> ...no, it doesn't carry over to other comparisons, but it's not supposed to.
> Just like you can't add "%" to the other comparisons.
> 
> The patterns are including constraints whose only purpose is to match
> non-canonical rtl.  That shouldn't happen.

My argument is the same as above.


Having that said, I'll edit the *norsi3 and EQNE patterns to remove the
'M' like you suggested in the final patch. This is too trivial an issue
to get postponed by.

>>>>>> +      emit_insn
>>>>>> +	(gen_rtx_SET (Pmode, tmp,
>>>>>> +		      gen_int_mode (cfun->machine->save_regs_offset,
>>>>>> +				    Pmode)));
>>>>>
>>>>> Shouldn't have a mode on the SET, but really should just call
>>>>> emit_move_insn. Similar cases elsewhere, search for "gen_rtx_SET (Pmode".
>>>>
>>>> I've removed the modes on SET, though I prefer the more bare generation
>>>> of the insns in some contexts; emit_move_insn() seems to have a lot
>>>> under the hood.
>>>
>>> There shouldn't be anything to be afraid of though.  Target-independent
>>> code would use emit_move_insn for this though, so it needs to just work.
>>
>> It will work, and I did use it in some places, though I did not
>> exhaustively search-and-replace.
>>
>> For (subtle) performance reasons, emit_move_insn() really does too much
>> as a backend utility. Usually backend code is already very precise on
>> what we want to generate.
> 
> Hmm, this sounds a bit FUDish.  What subtle reasons do you mean?
> 
> If moving a constant into a register is valid as a simple SET
> then that's what emit_move_insn should do.

"FUDish" sounds too serious. I'm just saying that, when a backend emits
a constant/const-address move (unlike the machine-independent code which
is abstracted away from target details) it probably doesn't intend to
have it also passed through the constant/address legitmat(e_p|ize)
hooks. All I want is a simple SET generated.

Thanks,
Chung-Lin

>>>>>> +  HOST_WIDE_INT var_size;       /* # of var. bytes allocated.  */
>>>>>
>>>>> Not the first time they occur in this file, but I suppose I should
>>>>> mention that these in-line comments are probably just outside our coding
>>>>> guidelines.
>>>>
>>>> Deleted the comments outside the struct defs.
>>>
>>> FWIW, I think it was more that comments should be above the field rather
>>> than tagged on the right.  (One of the big problems with right-column comments
>>> is that people tend to make them too short.)
>>
>> I will change to use the over-the-top style in the final patch.
> 
> Thanks,
> Richard
>
Richard Henderson Nov. 21, 2013, 7:25 a.m. UTC | #6
On 11/21/2013 02:41 PM, Chung-Lin Tang wrote:
> I'm not saying we tolerate "wrong" RTL form, but rather that, it should
> be an issue of the RTL passes, not the backend. The backend should just
> be as much as possible, a  "machine description".

Matching non-canonical rtl does nothing but slow down the compiler and cause
confusion for the poor person that has to maintain the code later.

I'm with Richard S on this one.


r~
Chung-Lin Tang Nov. 21, 2013, 1:18 p.m. UTC | #7
On 2013/11/21 03:25 PM, Richard Henderson wrote:
> On 11/21/2013 02:41 PM, Chung-Lin Tang wrote:
>> I'm not saying we tolerate "wrong" RTL form, but rather that, it should
>> be an issue of the RTL passes, not the backend. The backend should just
>> be as much as possible, a  "machine description".
> 
> Matching non-canonical rtl does nothing but slow down the compiler and cause
> confusion for the poor person that has to maintain the code later.

As I mentioned in the last mail, I will modify the constraints as
suggested for the *norsi3 and EQ/NE cmp patterns in the final patch.

Chung-Lin
Bernd Schmidt Nov. 22, 2013, 2:31 p.m. UTC | #8
On 11/16/2013 11:01 AM, Chung-Lin Tang wrote:
> My response to the various issues you raised are below. The new patch
> has been re-tested. Please see if you can approve for committing now.

I agree with all the comments Richard has been making, so I'll just add
a few other points.

> If you don't object, I'll keep the clobbers there for now.

If they serve no purpose (and I think they don't), they should go.

>>> >> +      emit_insn
>>> >> +	(gen_rtx_SET (Pmode, tmp,
>>> >> +		      gen_int_mode (cfun->machine->save_regs_offset,
>>> >> +				    Pmode)));
>> > 
>> > Shouldn't have a mode on the SET, but really should just call
>> > emit_move_insn. Similar cases elsewhere, search for "gen_rtx_SET (Pmode".
> I've removed the modes on SET, though I prefer the more bare generation
> of the insns in some contexts; emit_move_insn() seems to have a lot
> under the hood.

emit_move_insn is the right interface for this. It's the clearest way to
write what you want to do.

>>> >> +  if (!strncasecmp (cfg, "60-1", 4))
>> > 
>> > strcmp, several times. At least judging by the docs allowing "60-1fish"
>> > is unintentional?
> I changed them to use strncmp instead. This routine has to work on a
> possibly longer target attribute string, hence the 'n' variants.

I don't understand this. Using strncmp matches "60-1" and any other
string beginning with that prefix, but doesn't distinguish between them.
If that really is the desired behaviour, it needs a comment, but it
still looks to me as if this is just lacking proper error checking.

>>> >> +  /* Check for unsupported options.  */
>>> >> +  if (flag_pic && !TARGET_LINUX_ABI)
>>> >> +    error ("position-independent code requires the Linux ABI");
>> > 
>> > Use sorry instead?
> Any guidelines on error() vs. sorry()? I don't feel a strong need to
> change...

sorry is for unimplemented features, so I think it's the right function
to use.

>>> >> +/* Return true if CST is a constant within range of movi/movui/movhi.  */
>>> >> +static bool
>>> >> +nios2_simple_const_p (const_rtx cst)
>>> >> +{
>>> >> +  HOST_WIDE_INT val = INTVAL (cst);
>>> >> +  return (SMALL_INT (val) || SMALL_INT_UNSIGNED (val) || UPPER16_INT (val));
>>> >> +}
>> > 
>> > Unnecessary parens around return value. Several cases in this file.
> Grepping across the backends, I see numerous such parens around return
> value, so I'm leaning on keeping that...

It's just poor C style, and occurrences in other backends don't change
that. We do use parens like this if the expression spans multiple lines
to help the editor, but that's the only case where they should be used.

>>> >> +static rtx
>>> >> +nios2_call_tls_get_addr (rtx ti)
>> > 
>> > No special relocs to mark such a call?
> I don't quite understand what you mean here? The "call_value" pattern
> should handle everything correctly.

I was wondering whether such a call needs to be marked with a special
reloc for the linker to be able to eliminate it in some cases. ISTR some
targets do that, but if nios2 doesn't, then no need to change anything.

>>> >> +#define SC_REGNO (12)
>>> >> +#define STATIC_CHAIN_REGNUM SC_REGNO
>> > 
>> > There are a lot of these pairs, and it looks like unnecessary double
>> > indirection. Lose the former in all cases. No parens around constants.
> I've reorganized a lot of this in nios2.h.

I'd prefer the new #if 0 blocks there to go away.


Bernd
Chung-Lin Tang Nov. 22, 2013, 3:53 p.m. UTC | #9
On 13/11/22 10:31 PM, Bernd Schmidt wrote:
>> If you don't object, I'll keep the clobbers there for now.
> 
> If they serve no purpose (and I think they don't), they should go.

I'll check again, but I remember df_regs_ever_live_p doesn't include the
RA reg if the call pattern doesn't have the clobber.

I see c6x doesn't have that clobber either, but checks crtl->is_leaf
instead in the frame layout. Looking across the backends, adding a
clobber appears to be the more usual style.

>>>>>> +  if (!strncasecmp (cfg, "60-1", 4))
>>>>
>>>> strcmp, several times. At least judging by the docs allowing "60-1fish"
>>>> is unintentional?
>> I changed them to use strncmp instead. This routine has to work on a
>> possibly longer target attribute string, hence the 'n' variants.
> 
> I don't understand this. Using strncmp matches "60-1" and any other
> string beginning with that prefix, but doesn't distinguish between them.
> If that really is the desired behaviour, it needs a comment, but it
> still looks to me as if this is just lacking proper error checking.

This has to work on target attribute strings, which it may be in the
middle of the string. But your right that the single option form may
allow the extended suffix, I'll fix this next.

>>>>>> +#define SC_REGNO (12)
>>>>>> +#define STATIC_CHAIN_REGNUM SC_REGNO
>>>>
>>>> There are a lot of these pairs, and it looks like unnecessary double
>>>> indirection. Lose the former in all cases. No parens around constants.
>> I've reorganized a lot of this in nios2.h.
> 
> I'd prefer the new #if 0 blocks there to go away.

Argh, forgot to delete that. Thanks for catching.

I'll address the rest in the next revision.

Thanks,
Chung-Lin
diff mbox

Patch

Index: contrib/config-list.mk
===================================================================
--- contrib/config-list.mk	(revision 204897)
+++ contrib/config-list.mk	(working copy)
@@ -45,9 +45,11 @@  LIST = aarch64-elf aarch64-linux-gnu \
   mipsisa64-elfoabi mipsisa64r2el-elf mipsisa64sr71k-elf mipsisa64sb1-elf \
   mipsel-elf mips64-elf mips64vr-elf mips64orion-elf mips-rtems \
   mips-wrs-vxworks mipstx39-elf mmix-knuth-mmixware mn10300-elf moxie-elf \
-  moxie-uclinux moxie-rtems pdp11-aout picochip-elfOPT-enable-obsolete \
+  moxie-uclinux moxie-rtems \
   msp430-elf \
   nds32le-elf nds32be-elf \
+  nios2-elf nios2-linux-gnu \
+  pdp11-aout picochip-elfOPT-enable-obsolete \
   powerpc-darwin8 \
   powerpc-darwin7 powerpc64-darwin powerpc-freebsd6 powerpc-netbsd \
   powerpc-eabispe powerpc-eabisimaltivec powerpc-eabisim ppc-elf \
Index: gcc/config/nios2/nios2.h
===================================================================
--- gcc/config/nios2/nios2.h	(revision 0)
+++ gcc/config/nios2/nios2.h	(revision 0)
@@ -0,0 +1,532 @@ 
+/* Definitions of target machine for Altera Nios II.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Jonah Graham (jgraham@altera.com), 
+   Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   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 GCC_NIOS2_H
+#define GCC_NIOS2_H
+
+/* FPU insn codes declared here.  */
+#include "config/nios2/nios2-opts.h"
+
+/* Define built-in preprocessor macros.  */
+#define TARGET_CPU_CPP_BUILTINS()                   \
+  do                                                \
+    {                                               \
+      builtin_define_std ("NIOS2");                 \
+      builtin_define_std ("nios2");                 \
+      if (TARGET_BIG_ENDIAN)                        \
+        builtin_define_std ("nios2_big_endian");    \
+      else                                          \
+        builtin_define_std ("nios2_little_endian"); \
+    }                                               \
+  while (0)
+
+/* We're little endian, unless otherwise specified by defining
+   BIG_ENDIAN_FLAG.  */
+#ifndef TARGET_ENDIAN_DEFAULT
+# define TARGET_ENDIAN_DEFAULT 0
+#endif
+
+/* Default target_flags if no switches specified.  */
+#ifndef TARGET_DEFAULT
+# define TARGET_DEFAULT (MASK_HAS_MUL | TARGET_ENDIAN_DEFAULT)
+#endif
+
+#define CC1_SPEC "%{G*}"
+
+#if TARGET_ENDIAN_DEFAULT == 0
+# define ASM_SPEC "%{!meb:-EL} %{meb:-EB}"
+# define LINK_SPEC_ENDIAN "%{!meb:-EL} %{meb:-EB}"
+# define MULTILIB_DEFAULTS { "EL" }
+#else
+# define ASM_SPEC "%{!mel:-EB} %{mel:-EL}"
+# define LINK_SPEC_ENDIAN "%{!mel:-EB} %{mel:-EL}"
+# define MULTILIB_DEFAULTS { "EB" }
+#endif
+
+#define LINK_SPEC LINK_SPEC_ENDIAN \
+  " %{shared:-shared} \
+    %{static:-Bstatic}"
+
+
+/* Storage layout.  */
+
+#define DEFAULT_SIGNED_CHAR 1
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+#define BITS_PER_UNIT 8
+#define BITS_PER_WORD 32
+#define UNITS_PER_WORD 4
+#define POINTER_SIZE 32
+#define BIGGEST_ALIGNMENT 32
+#define STRICT_ALIGNMENT 1
+#define FUNCTION_BOUNDARY 32
+#define PARM_BOUNDARY 32
+#define STACK_BOUNDARY 32
+#define PREFERRED_STACK_BOUNDARY 32
+#define MAX_FIXED_MODE_SIZE 64
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN)                          \
+  ((TREE_CODE (EXP) == STRING_CST)                              \
+   && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* Layout of source language data types.  */
+
+#define INT_TYPE_SIZE 32
+#define SHORT_TYPE_SIZE 16
+#define LONG_TYPE_SIZE 32
+#define LONG_LONG_TYPE_SIZE 64
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+
+/* Basic characteristics of Nios II registers:
+
+   Regno  Name
+   0      r0       zero    always zero
+   1      r1       at      Assembler Temporary
+   2-3    r2-r3            Return Location
+   4-7    r4-r7            Register Arguments
+   8-15   r8-r15           Caller Saved Registers
+   16-22  r16-r22          Callee Saved Registers
+   22     r22              Global Offset Table pointer (Linux ABI only)
+   23     r23              Thread pointer (Linux ABI only)
+   24     r24      et      Exception Temporary
+   25     r25      bt      Breakpoint Temporary
+   26     r26      gp      Global Pointer
+   27     r27      sp      Stack Pointer
+   28     r28      fp      Frame Pointer
+   29     r29      ea      Exception Return Address
+   30     r30      ba      Breakpoint Return Address
+   31     r31      ra      Return Address
+			   
+   32     ctl0     status
+   33     ctl1     estatus STATUS saved by exception
+   34     ctl2     bstatus STATUS saved by break
+   35     ctl3     ipri    Interrupt Priority Mask
+   36     ctl4     ecause  Exception Cause
+
+   37     pc               Not an actual register
+
+   38     fake_fp          Fake Frame Pointer (always eliminated)
+   39     fake_ap          Fake Argument Pointer (always eliminated)
+   40                      First Pseudo Register
+
+   In addition, r12 is used as the static chain register and r13, r14, and r15
+   are clobbered by PLT code sequences.  
+
+   The definitions for all the hard register numbers are located in nios2.md.
+*/
+#if 0
+#define FIRST_RETVAL_REGNO        2
+#define LAST_RETVAL_REGNO         3
+#define FIRST_ARG_REGNO           4
+#define LAST_ARG_REGNO            7
+
+#define TP_REGNO                  23 /* Thread pointer.  */
+#define GP_REGNO                  26 /* Global pointer.  */
+#define FP_REGNO                  28 /* Frame pointer.  */
+#define EA_REGNO                  29 /* Exception return address.  */
+#define RA_REGNO                  31 /* Return address.  */
+
+#define LAST_GP_REG RA_REGNO
+#endif
+
+/* Target register definitions.  */
+#if 0
+#define STACK_POINTER_REGNUM      27
+#define HARD_FRAME_POINTER_REGNUM FP_REGNO
+#define STATIC_CHAIN_REGNUM       12
+#define PC_REGNUM                 37
+#define FRAME_POINTER_REGNUM      38
+#define ARG_POINTER_REGNUM        39
+
+#define FIRST_PSEUDO_REGISTER     40
+#endif
+#define FIXED_REGISTERS                      \
+  {					     \
+/*        +0  1  2  3  4  5  6  7  8  9 */   \
+/*   0 */  1, 1, 0, 0, 0, 0, 0, 0, 0, 0,     \
+/*  10 */  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     \
+/*  20 */  0, 0, TARGET_LINUX_ABI, TARGET_LINUX_ABI, 1, 1, 1, 1, 0, 1,     \
+/*  30 */  1, 0, 1, 1, 1, 1, 1, 1, 1, 1,     \
+  }
+
+/* Call used == caller saved + fixed regs + args + ret vals.   */
+#define CALL_USED_REGISTERS                  \
+  {					     \
+/*        +0  1  2  3  4  5  6  7  8  9 */   \
+/*   0 */  1, 1, 1, 1, 1, 1, 1, 1, 1, 1,     \
+/*  10 */  1, 1, 1, 1, 1, 1, 0, 0, 0, 0,     \
+/*  20 */  0, 0, TARGET_LINUX_ABI, TARGET_LINUX_ABI, 1, 1, 1, 1, 0, 1,     \
+/*  30 */  1, 1, 1, 1, 1, 1, 1, 1, 1, 1,     \
+  }
+
+#define MODES_TIEABLE_P(MODE1, MODE2) 1
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+#define HARD_REGNO_NREGS(REGNO, MODE)            \
+  ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Register Classes.  */
+
+enum reg_class
+{
+  NO_REGS,
+  SIB_REGS,
+  GP_REGS,
+  ALL_REGS,
+  LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES   \
+  {  "NO_REGS",		  \
+     "SIB_REGS",	  \
+     "GP_REGS",           \
+     "ALL_REGS" }
+
+#define GENERAL_REGS ALL_REGS
+
+#define REG_CLASS_CONTENTS			\
+  {						\
+    /* NO_REGS  */ { 0, 0},			\
+    /* SIB_REGS */ { 0xfe0c, 0},		\
+    /* GP_REGS  */ {~0, 0},			\
+    /* ALL_REGS */ {~0,~0}			\
+  }
+
+
+#define GP_REG_P(REGNO) ((unsigned)(REGNO) <= LAST_GP_REG)
+#define REGNO_REG_CLASS(REGNO) (GP_REG_P (REGNO) ? GP_REGS : ALL_REGS)
+#define CLASS_MAX_NREGS(CLASS, MODE)					\
+  ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Tests for various kinds of constants used in the Nios II port.  */
+
+#define SMALL_INT(X) ((unsigned HOST_WIDE_INT)(X) + 0x8000 < 0x10000)
+#define SMALL_INT_UNSIGNED(X) ((X) >= 0 && (X) < 0x10000)
+#define UPPER16_INT(X) (((X) & 0xffff) == 0)
+#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
+#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
+#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255)
+
+/* Say that the epilogue uses the return address register.  Note that
+   in the case of sibcalls, the values "used by the epilogue" are
+   considered live at the start of the called function.  */
+#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO)
+
+/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
+   the stack pointer does not matter.  The value is tested only in
+   functions that have frame pointers.
+   No definition is equivalent to always zero.  */
+
+#define EXIT_IGNORE_STACK 1
+
+/* Trampolines use a 5-instruction sequence.  */
+#define TRAMPOLINE_SIZE 20
+
+/* Stack layout.  */
+#define STACK_GROWS_DOWNWARD
+#define STARTING_FRAME_OFFSET 0
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+
+/* Before the prologue, RA lives in r31.  */
+#define INCOMING_RETURN_ADDR_RTX  gen_rtx_REG (VOIDmode, RA_REGNO)
+#define RETURN_ADDR_RTX(C,F) nios2_get_return_address (C)
+
+#define DWARF_FRAME_RETURN_COLUMN RA_REGNO
+
+/* The CFA includes the pretend args.  */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) \
+  (gcc_assert ((FNDECL) == current_function_decl), \
+   FIRST_PARM_OFFSET (FNDECL) + crtl->args.pretend_args_size)
+
+/* Frame/arg pointer elimination settings.  */
+#define ELIMINABLE_REGS                                                 \
+{{ ARG_POINTER_REGNUM,   STACK_POINTER_REGNUM},                         \
+ { ARG_POINTER_REGNUM,   HARD_FRAME_POINTER_REGNUM},                    \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},                         \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+  (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO))
+
+/* Calling convention definitions.  */
+typedef struct nios2_args
+{
+  int regs_used;
+} CUMULATIVE_ARGS;
+
+#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1)
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
+  do { (CUM).regs_used = 0; } while (0)
+
+#define FUNCTION_ARG_PADDING(MODE, TYPE) \
+  (nios2_function_arg_padding ((MODE), (TYPE)))
+
+#define PAD_VARARGS_DOWN \
+  (FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward)
+
+#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
+  (nios2_block_reg_padding ((MODE), (TYPE), (FIRST)))
+
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+  ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO)
+
+/* Passing function arguments on stack.  */
+#define PUSH_ARGS 0
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/* We define TARGET_RETURN_IN_MEMORY, so set to zero.  */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* Profiling.  */
+#define PROFILE_BEFORE_PROLOGUE
+#define NO_PROFILE_COUNTERS 1
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+  nios2_function_profiler ((FILE), (LABELNO))
+
+/* Addressing modes.  */
+
+#define CONSTANT_ADDRESS_P(X) \
+  (CONSTANT_P (X) && memory_address_p (SImode, X))
+
+#define MAX_REGS_PER_ADDRESS 1
+#define BASE_REG_CLASS ALL_REGS
+#define INDEX_REG_CLASS NO_REGS
+
+#define REGNO_OK_FOR_BASE_P(REGNO) nios2_regno_ok_for_base_p ((REGNO), true)
+#define REGNO_OK_FOR_INDEX_P(REGNO) 0
+/*  nios2_regno_ok_for_index_p ((REGNO), true)*/
+/* Set if this has a weak declaration.  */
+/*
+#define SYMBOL_FLAG_WEAK_DECL   (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
+#define SYMBOL_REF_WEAK_DECL_P(RTX) \
+  ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0)
+*/
+
+/* Describing Relative Costs of Operations.  */
+#define MOVE_MAX 4
+#define SLOW_BYTE_ACCESS 1
+
+/* It is as good to call a constant function address as to call an address
+   kept in a register.  */
+#define NO_FUNCTION_CSE
+
+/* Position independent code.  */
+
+#define PIC_OFFSET_TABLE_REGNUM 22
+#define LEGITIMATE_PIC_OPERAND_P(X) nios2_legitimate_pic_operand_p (X)
+
+/* Define output assembler language.  */
+
+#define ASM_APP_ON "#APP\n"
+#define ASM_APP_OFF "#NO_APP\n"
+
+#define ASM_COMMENT_START "# "
+
+#define GLOBAL_ASM_OP "\t.global\t"
+
+#define REGISTER_NAMES \
+  {		       \
+    "zero", \
+    "at", \
+    "r2", \
+    "r3", \
+    "r4", \
+    "r5", \
+    "r6", \
+    "r7", \
+    "r8", \
+    "r9", \
+    "r10", \
+    "r11", \
+    "r12", \
+    "r13", \
+    "r14", \
+    "r15", \
+    "r16", \
+    "r17", \
+    "r18", \
+    "r19", \
+    "r20", \
+    "r21", \
+    "r22", \
+    "r23", \
+    "et", \
+    "bt", \
+    "gp", \
+    "sp", \
+    "fp", \
+    "ta", \
+    "ba", \
+    "ra", \
+    "status", \
+    "estatus", \
+    "bstatus", \
+    "ipri", \
+    "ecause", \
+    "pc", \
+    "fake_fp", \
+    "fake_ap", \
+}
+
+#define ADDITIONAL_REGISTER_NAMES       \
+{					\
+  {"r0", 0},				\
+  {"r1", 1},				\
+  {"r24", 24},                          \
+  {"r25", 25},                          \
+  {"r26", 26},                          \
+  {"r27", 27},                          \
+  {"r28", 28},                          \
+  {"r29", 29},                          \
+  {"r30", 30},                          \
+  {"r31", 31}                           \
+}
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)  \
+  do									\
+    {									\
+      fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \
+      fprintf (FILE, ".L%u\n", (unsigned) (VALUE));			\
+    }									\
+  while (0)
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)\
+  do									\
+    {									\
+      fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), STREAM); \
+      fprintf (STREAM, ".L%u-.L%u\n", (unsigned) (VALUE), (unsigned) (REL)); \
+    }									\
+  while (0)
+
+/* Section directives.  */
+
+/* Output before read-only data.  */
+#define TEXT_SECTION_ASM_OP "\t.section\t.text"
+
+/* Output before writable data.  */
+#define DATA_SECTION_ASM_OP "\t.section\t.data"
+
+/* Output before uninitialized data.  */
+#define BSS_SECTION_ASM_OP "\t.section\t.bss"
+
+/* Output before 'small' uninitialized data.  */
+#define SBSS_SECTION_ASM_OP "\t.section\t.sbss"
+
+#ifndef IN_LIBGCC2
+/* Default the definition of "small data" to 8 bytes.  */
+extern unsigned HOST_WIDE_INT nios2_section_threshold;
+#endif
+
+#define NIOS2_DEFAULT_GVALUE 8
+
+/* This says how to output assembler code to declare an
+   uninitialized external linkage data object.  Under SVR4,
+   the linker seems to want the alignment of data objects
+   to depend on their types.  We do exactly that here.  */
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP   "\t.comm\t"
+
+#define ASM_OUTPUT_ALIGN(FILE, LOG)		     \
+  do {						     \
+    fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \
+  } while (0)
+
+#undef  ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN)              \
+do                                                                      \
+  {									\
+    fprintf ((FILE), "%s", COMMON_ASM_OP);				\
+    assemble_name ((FILE), (NAME));					\
+    fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE),	\
+	     (ALIGN) / BITS_PER_UNIT);					\
+  }									\
+while (0)
+
+
+/* This says how to output assembler code to declare an
+   uninitialized internal linkage data object.  Under SVR4,
+   the linker seems to want the alignment of data objects
+   to depend on their types.  We do exactly that here.  */
+
+#undef  ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN)               \
+do {                                                                    \
+  if ((SIZE) <= nios2_section_threshold)                                \
+    switch_to_section (sbss_section);					\
+  else                                                                  \
+    switch_to_section (bss_section);					\
+  ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object");                     \
+  if (!flag_inhibit_size_directive)                                     \
+    ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE);                       \
+  ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT));       \
+  ASM_OUTPUT_LABEL(FILE, NAME);                                         \
+  ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1);                         \
+} while (0)
+
+/* Put the jump tables in .text because when using position-independent code,
+   Nios II elf has no relocation that can represent arbitrary differences
+   between symbols in different sections.  */
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+
+/* Exception handling.  */
+
+/* Describe __builtin_eh_return.  */
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, LAST_RETVAL_REGNO)
+#define EH_RETURN_DATA_REGNO(N) ((N) <= (LAST_ARG_REGNO - FIRST_ARG_REGNO) \
+				 ? (N) + FIRST_ARG_REGNO : INVALID_REGNUM)
+
+/* Nios II has no appropriate relocations for a 32-bit PC-relative or
+   section-relative pointer encoding.  This therefore always chooses an
+   absolute representation for pointers.  An unfortunate consequence of
+   this is that ld complains about the absolute fde encoding when linking
+   with -shared or -fpie, but the warning is harmless and there seems to
+   be no good way to suppress it.  */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL)		\
+  (flag_pic ? DW_EH_PE_aligned : DW_EH_PE_sdata4)
+
+/* Misc. parameters.  */
+
+#define STORE_FLAG_VALUE 1
+#define Pmode SImode
+#define FUNCTION_MODE QImode
+
+#define CASE_VECTOR_MODE Pmode
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND)
+
+#define WORD_REGISTER_OPERATIONS
+
+#endif /* GCC_NIOS2_H */
Index: gcc/config/nios2/predicates.md
===================================================================
--- gcc/config/nios2/predicates.md	(revision 0)
+++ gcc/config/nios2/predicates.md	(revision 0)
@@ -0,0 +1,85 @@ 
+;; Predicate definitions for Altera Nios II.
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Chung-Lin Tang <cltang@codesourcery.com>
+;;
+;; 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 "const_0_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op == CONST0_RTX (GET_MODE (op))")))
+
+(define_predicate "reg_or_0_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "register_operand")))
+
+(define_predicate "const_uns_arith_operand"
+  (and (match_code "const_int")
+       (match_test "SMALL_INT_UNSIGNED (INTVAL (op))")))
+
+(define_predicate "uns_arith_operand"
+  (ior (match_operand 0 "const_uns_arith_operand")
+       (match_operand 0 "register_operand")))
+
+(define_predicate "const_arith_operand"
+  (and (match_code "const_int")
+       (match_test "SMALL_INT (INTVAL (op))")))
+
+(define_predicate "arith_operand"
+  (ior (match_operand 0 "const_arith_operand")
+       (match_operand 0 "register_operand")))
+
+(define_predicate "add_regimm_operand"
+  (ior (match_operand 0 "arith_operand")
+       (match_test "nios2_unspec_reloc_p (op)")))
+
+(define_predicate "const_logical_operand"
+  (and (match_code "const_int")
+       (match_test "(INTVAL (op) & 0xffff) == 0
+                    || (INTVAL (op) & 0xffff0000) == 0")))
+
+(define_predicate "logical_operand"
+  (ior (match_operand 0 "const_logical_operand")
+       (match_operand 0 "register_operand")))
+
+(define_predicate "const_shift_operand"
+  (and (match_code "const_int")
+       (match_test "SHIFT_INT (INTVAL (op))")))
+
+(define_predicate "shift_operand"
+  (ior (match_operand 0 "const_shift_operand")
+       (match_operand 0 "register_operand")))
+
+(define_predicate "call_operand"
+  (ior (match_operand 0 "immediate_operand")
+       (match_operand 0 "register_operand")))
+
+(define_predicate "rdwrctl_operand"
+  (and (match_code "const_int")
+       (match_test "RDWRCTL_INT (INTVAL (op))")))
+
+(define_predicate "custom_insn_opcode"
+  (and (match_code "const_int")
+       (match_test "CUSTOM_INSN_OPCODE (INTVAL (op))")))
+
+(define_special_predicate "expandable_comparison_operator"
+  (match_operand 0 "ordered_comparison_operator")
+{
+  return (GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) != MODE_FLOAT
+          || nios2_validate_fpu_compare (GET_MODE (XEXP (op, 0)), &op,
+                                         &XEXP (op, 0), &XEXP (op, 1),
+                                         false));
+})
Index: gcc/config/nios2/nios2-opts.h
===================================================================
--- gcc/config/nios2/nios2-opts.h	(revision 0)
+++ gcc/config/nios2/nios2-opts.h	(revision 0)
@@ -0,0 +1,69 @@ 
+/* Definitions for option handling for Nios II.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+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 NIOS2_OPTS_H
+#define NIOS2_OPTS_H
+
+/* Enumeration of all FPU insn codes.  */
+#define N2FPU_ALL_CODES							\
+  N2FPU_CODE(fadds) N2FPU_CODE(fsubs) N2FPU_CODE(fmuls) N2FPU_CODE(fdivs) \
+  N2FPU_CODE(fmins) N2FPU_CODE(fmaxs)					\
+  N2FPU_CODE(fnegs) N2FPU_CODE(fabss) N2FPU_CODE(fsqrts)		\
+  N2FPU_CODE(fsins) N2FPU_CODE(fcoss) N2FPU_CODE(ftans) N2FPU_CODE(fatans) \
+  N2FPU_CODE(fexps) N2FPU_CODE(flogs)					\
+  N2FPU_CODE(fcmpeqs) N2FPU_CODE(fcmpnes)				\
+  N2FPU_CODE(fcmplts) N2FPU_CODE(fcmples)				\
+  N2FPU_CODE(fcmpgts) N2FPU_CODE(fcmpges)				\
+  									\
+  N2FPU_CODE(faddd) N2FPU_CODE(fsubd) N2FPU_CODE(fmuld) N2FPU_CODE(fdivd) \
+  N2FPU_CODE(fmind) N2FPU_CODE(fmaxd)					\
+  N2FPU_CODE(fnegd) N2FPU_CODE(fabsd) N2FPU_CODE(fsqrtd)		\
+  N2FPU_CODE(fsind) N2FPU_CODE(fcosd) N2FPU_CODE(ftand) N2FPU_CODE(fatand) \
+  N2FPU_CODE(fexpd) N2FPU_CODE(flogd)					\
+  N2FPU_CODE(fcmpeqd) N2FPU_CODE(fcmpned)				\
+  N2FPU_CODE(fcmpltd) N2FPU_CODE(fcmpled)				\
+  N2FPU_CODE(fcmpgtd) N2FPU_CODE(fcmpged)				\
+  									\
+  N2FPU_CODE(floatis) N2FPU_CODE(floatus)				\
+  N2FPU_CODE(floatid) N2FPU_CODE(floatud)				\
+  N2FPU_CODE(fixsi) N2FPU_CODE(fixsu)					\
+  N2FPU_CODE(fixdi) N2FPU_CODE(fixdu)					\
+  N2FPU_CODE(fextsd) N2FPU_CODE(ftruncds)				\
+									\
+  N2FPU_CODE(fwrx) N2FPU_CODE(fwry)					\
+  N2FPU_CODE(frdxlo) N2FPU_CODE(frdxhi) N2FPU_CODE(frdy)
+
+enum n2fpu_code {
+#define N2FPU_CODE(name) n2fpu_ ## name,
+  N2FPU_ALL_CODES
+#undef N2FPU_CODE
+  n2fpu_code_num
+};
+
+/* An enumeration to indicate the custom code status; if values within 0--255
+   are registered to an FPU insn, or custom insn.  */
+enum nios2_ccs_code
+{
+  CCS_UNUSED,
+  CCS_FPU,
+  CCS_BUILTIN_CALL
+};
+
+#endif
+
Index: gcc/config/nios2/nios2-protos.h
===================================================================
--- gcc/config/nios2/nios2-protos.h	(revision 0)
+++ gcc/config/nios2/nios2-protos.h	(revision 0)
@@ -0,0 +1,61 @@ 
+/* Subroutine declarations for Altera Nios II target support.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Jonah Graham (jgraham@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   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 GCC_NIOS2_PROTOS_H
+#define GCC_NIOS2_PROTOS_H
+
+extern int nios2_initial_elimination_offset (int, int);
+extern int nios2_can_use_return_insn (void);
+extern void nios2_expand_prologue (void);
+extern void nios2_expand_epilogue (bool);
+extern void nios2_function_profiler (FILE *, int);
+
+#ifdef RTX_CODE
+extern int nios2_emit_move_sequence (rtx *, enum machine_mode);
+extern void nios2_emit_expensive_div (rtx *, enum machine_mode);
+extern void nios2_adjust_call_address (rtx *);
+
+extern rtx nios2_get_return_address (int);
+extern void nios2_set_return_address (rtx, rtx);
+
+extern bool nios2_validate_compare (enum machine_mode, rtx *, rtx *, rtx *);
+extern bool nios2_validate_fpu_compare (enum machine_mode, rtx *, rtx *, rtx *,
+					bool);
+
+extern bool nios2_fpu_insn_enabled (enum n2fpu_code);
+extern const char * nios2_fpu_insn_asm (enum n2fpu_code);
+
+extern bool nios2_legitimate_pic_operand_p (rtx);
+extern bool nios2_symbol_ref_in_small_data_p (rtx);
+extern bool nios2_regno_ok_for_base_p (int, bool);
+extern bool nios2_unspec_reloc_p (rtx);
+
+#ifdef TREE_CODE
+#ifdef ARGS_SIZE_RTX
+/* expr.h defines both ARGS_SIZE_RTX and `enum direction' */
+extern enum direction nios2_function_arg_padding (enum machine_mode, const_tree);
+extern enum direction nios2_block_reg_padding (enum machine_mode, tree, int);
+#endif /* ARGS_SIZE_RTX */
+
+#endif /* TREE_CODE */
+#endif /* RTX_CODE */
+
+#endif /* GCC_NIOS2_PROTOS_H */
Index: gcc/config/nios2/linux.h
===================================================================
--- gcc/config/nios2/linux.h	(revision 0)
+++ gcc/config/nios2/linux.h	(revision 0)
@@ -0,0 +1,38 @@ 
+/* Definitions of target support for Altera Nios II systems
+   running GNU/Linux with ELF format.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Mentor Graphics, Inc.
+
+   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 TARGET_OS_CPP_BUILTINS()                \
+  do                                            \
+    {                                           \
+      GNU_USER_TARGET_OS_CPP_BUILTINS();           \
+    }                                           \
+  while (0)
+
+#undef LINK_SPEC
+#define LINK_SPEC LINK_SPEC_ENDIAN \
+  " %{shared:-shared} \
+    %{static:-Bstatic} \
+    %{rdynamic:-export-dynamic}"
+
+/* This toolchain implements the ABI for Linux Systems documented in the
+   Nios II Processor Reference Handbook.  */
+#define TARGET_LINUX_ABI 1
+
Index: gcc/config/nios2/constraints.md
===================================================================
--- gcc/config/nios2/constraints.md	(revision 0)
+++ gcc/config/nios2/constraints.md	(revision 0)
@@ -0,0 +1,89 @@ 
+;; Constraint definitions for Altera Nios II.
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Chung-Lin Tang <cltang@codesourcery.com>
+;;
+;; 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 use the following constraint letters for constants
+;;
+;;  I: -32768 to -32767
+;;  J: 0 to 65535
+;;  K: $nnnn0000 for some nnnn
+;;  L: 0 to 31 (for shift counts)
+;;  M: 0
+;;  N: 0 to 255 (for custom instruction numbers)
+;;  O: 0 to 31 (for control register numbers)
+;;
+;; We use the following built-in register classes:
+;;
+;;  r: general purpose register (r0..r31)
+;;  m: memory operand
+;;
+;; Plus, we define the following constraint strings:
+;;
+;;  S: symbol that is in the "small data" area
+
+;; Register constraints
+
+(define_register_constraint "j" "SIB_REGS"
+  "A register suitable for an indirect sibcall.")
+
+;; Integer constraints
+
+(define_constraint "I"
+  "A signed 16-bit constant (for arithmetic instructions)."
+  (and (match_code "const_int")
+       (match_test "SMALL_INT (ival)")))
+
+(define_constraint "J"
+  "An unsigned 16-bit constant (for logical instructions)."
+  (and (match_code "const_int")
+       (match_test "SMALL_INT_UNSIGNED (ival)")))
+
+(define_constraint "K"
+  "An unsigned 16-bit high constant (for logical instructions)."
+  (and (match_code "const_int")
+       (match_test "UPPER16_INT (ival)")))
+
+(define_constraint "L"
+  "An unsigned 5-bit constant (for shift counts)."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 31")))
+
+(define_constraint "M"
+  "Integer zero."
+  (and (match_code "const_int")
+       (match_test "ival == 0")))
+
+(define_constraint "N"
+  "An unsigned 8-bit constant (for custom instruction codes)."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 255")))
+
+(define_constraint "O"
+  "An unsigned 5-bit constant (for control register numbers)."
+  (and (match_code "const_int")
+       (match_test "ival >= 0 && ival <= 31")))
+
+(define_constraint "S"
+  "An immediate stored in small data, accessible by GP."
+  (and (match_code "symbol_ref")
+       (match_test "nios2_symbol_ref_in_small_data_p (op)")))
+
+(define_constraint "T"
+  "A constant unspec offset representing a relocation."
+  (match_test "nios2_unspec_reloc_p (op)"))
Index: gcc/config/nios2/elf.opt
===================================================================
--- gcc/config/nios2/elf.opt	(revision 0)
+++ gcc/config/nios2/elf.opt	(revision 0)
@@ -0,0 +1,38 @@ 
+; Options for the Altera Nios II port of the compiler.
+; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+; Contributed by Altera and Mentor Graphics, Inc.
+;
+; 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/>.
+
+; These additional options are supported for ELF (bare-metal) Nios II
+; toolchains.
+
+msmallc
+Target Report RejectNegative
+Link with a limited version of the C library
+
+msys-lib=
+Target RejectNegative Joined Var(nios2_sys_lib_string)
+Name of system library to link against
+
+msys-crt0=
+Target RejectNegative Joined Var(nios2_sys_crt0_string)
+Name of the startfile
+
+mhal
+Target Report RejectNegative
+Link with HAL BSP
Index: gcc/config/nios2/nios2.md
===================================================================
--- gcc/config/nios2/nios2.md	(revision 0)
+++ gcc/config/nios2/nios2.md	(revision 0)
@@ -0,0 +1,1030 @@ 
+;; Machine Description for Altera Nios II.
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Contributed by Jonah Graham (jgraham@altera.com) and 
+;; Will Reece (wreece@altera.com).
+;; Contributed by Mentor Graphics, Inc.
+;;
+;; 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
+  [
+   (FIRST_RETVAL_REGNO     2)	; Return value registers
+   (LAST_RETVAL_REGNO      3)	;
+   (FIRST_ARG_REGNO        4)	; Argument registers
+   (LAST_ARG_REGNO         7)	;
+
+   (TP_REGNO              23)	; Thread pointer register
+   (GP_REGNO	          26)	; Global pointer register
+   (FP_REGNO	          28)	; Frame pointer register
+   (EA_REGNO	          29)	; Exception return address register
+   (RA_REGNO              31)	; Return address register
+   (LAST_GP_REG           31)	; Last general purpose register
+
+   ;; Target register definitions
+   (STATIC_CHAIN_REGNUM        12)
+   (STACK_POINTER_REGNUM       27)
+   (HARD_FRAME_POINTER_REGNUM  28)
+   (PC_REGNUM                  37)
+   (FRAME_POINTER_REGNUM       38)
+   (ARG_POINTER_REGNUM         39)
+   (FIRST_PSEUDO_REGISTER      40)
+  ]
+)
+
+;; Enumeration of UNSPECs
+
+(define_c_enum "unspecv" [
+  UNSPECV_BLOCKAGE
+  UNSPECV_WRCTL
+  UNSPECV_RDCTL
+  UNSPECV_FWRX
+  UNSPECV_FWRY
+  UNSPECV_FRDXLO
+  UNSPECV_FRDXHI
+  UNSPECV_FRDY
+  UNSPECV_CUSTOM_NXX
+  UNSPECV_CUSTOM_XNXX
+  UNSPECV_LDXIO
+  UNSPECV_STXIO
+])
+
+(define_c_enum "unspec" [
+  UNSPEC_FCOS
+  UNSPEC_FSIN
+  UNSPEC_FTAN
+  UNSPEC_FATAN
+  UNSPEC_FEXP
+  UNSPEC_FLOG
+  UNSPEC_LOAD_GOT_REGISTER
+  UNSPEC_PIC_SYM
+  UNSPEC_PIC_CALL_SYM
+  UNSPEC_TLS
+  UNSPEC_TLS_LDM
+  UNSPEC_LOAD_TLS_IE
+  UNSPEC_ADD_TLS_LE
+  UNSPEC_ADD_TLS_GD
+  UNSPEC_ADD_TLS_LDM
+  UNSPEC_ADD_TLS_LDO
+  UNSPEC_EH_RETURN
+  UNSPEC_SYNC
+])
+
+
+;;  Instruction scheduler
+
+; No schedule info is currently available, using an assumption that no
+; instruction can use the results of the previous instruction without
+; incuring a stall.
+
+; length of an instruction (in bytes)
+(define_attr "length" "" (const_int 4))
+(define_attr "type" 
+  "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" 
+  (const_string "complex"))
+
+(define_asm_attributes
+ [(set_attr "length" "4")
+  (set_attr "type" "complex")])
+
+(define_automaton "nios2")
+(automata_option "v")
+;(automata_option "no-minimization")
+(automata_option "ndfa")
+
+; The nios2 pipeline is fairly straightforward for the fast model.
+; Every alu operation is pipelined so that an instruction can
+; be issued every cycle.  However, there are still potential
+; stalls which this description tries to deal with.
+
+(define_cpu_unit "cpu" "nios2")
+
+(define_insn_reservation "complex" 1
+  (eq_attr "type" "complex")
+  "cpu")
+
+(define_insn_reservation "control" 1
+  (eq_attr "type" "control")
+  "cpu")
+
+(define_insn_reservation "alu" 1
+  (eq_attr "type" "alu")
+  "cpu")
+
+(define_insn_reservation "cond_alu" 1
+  (eq_attr "type" "cond_alu")
+  "cpu")
+
+(define_insn_reservation "st" 1
+  (eq_attr "type" "st")
+  "cpu")
+  
+(define_insn_reservation "custom" 1
+  (eq_attr "type" "custom")
+  "cpu")
+
+; shifts, muls and lds have three cycle latency
+(define_insn_reservation "ld" 3
+  (eq_attr "type" "ld")
+  "cpu")
+
+(define_insn_reservation "shift" 3
+  (eq_attr "type" "shift")
+  "cpu")
+
+(define_insn_reservation "mul" 3
+  (eq_attr "type" "mul")
+  "cpu")
+
+(define_insn_reservation "div" 1
+  (eq_attr "type" "div")
+  "cpu")
+
+(include "predicates.md")
+(include "constraints.md")
+
+
+;; Move instructions
+
+(define_mode_iterator M [QI HI SI])
+
+(define_expand "mov<mode>"
+  [(set (match_operand:M 0 "nonimmediate_operand" "")
+        (match_operand:M 1 "general_operand" ""))]
+  ""
+{
+  if (nios2_emit_move_sequence (operands, <MODE>mode))
+    DONE;
+})
+
+(define_insn "movqi_internal"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r")
+        (match_operand:QI 1 "general_operand"       "rM,m,rM,I"))]
+  "(register_operand (operands[0], QImode)
+    || reg_or_0_operand (operands[1], QImode))"
+  "@
+    stb%o0\\t%z1, %0
+    ldbu%o1\\t%0, %1
+    mov\\t%0, %z1
+    movi\\t%0, %1"
+  [(set_attr "type" "st,ld,alu,alu")])
+
+(define_insn "movhi_internal"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r")
+        (match_operand:HI 1 "general_operand"       "rM,m,rM,I,J"))]
+  "(register_operand (operands[0], HImode)
+    || reg_or_0_operand (operands[1], HImode))"
+  "@
+    sth%o0\\t%z1, %0
+    ldhu%o1\\t%0, %1
+    mov\\t%0, %z1
+    movi\\t%0, %1
+    movui\\t%0, %1"
+  [(set_attr "type" "st,ld,alu,alu,alu")])
+
+(define_insn "movsi_internal"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r,r")
+        (match_operand:SI 1 "general_operand"       "rM,m,rM,I,J,K,S,i"))]
+  "(register_operand (operands[0], SImode)
+    || reg_or_0_operand (operands[1], SImode))"
+  "@
+    stw%o0\\t%z1, %0
+    ldw%o1\\t%0, %1
+    mov\\t%0, %z1
+    movi\\t%0, %1
+    movui\\t%0, %1
+    movhi\\t%0, %H1
+    addi\\t%0, gp, %%gprel(%1)
+    movhi\\t%0, %H1\;addi\\t%0, %0, %L1"
+  [(set_attr "type" "st,ld,alu,alu,alu,alu,alu,alu")
+   (set_attr "length" "4,4,4,4,4,4,4,8")])
+
+(define_mode_iterator BH [QI HI])
+(define_mode_iterator BHW [QI HI SI])
+(define_mode_attr bh [(QI "b") (HI "h")])
+(define_mode_attr bhw [(QI "b") (HI "h") (SI "w")])
+(define_mode_attr bhw_uns [(QI "bu") (HI "hu") (SI "w")])
+
+(define_insn "ld<bhw_uns>io"
+  [(set (match_operand:BHW 0 "register_operand" "=r")
+        (unspec_volatile:BHW
+          [(match_operand:BHW 1 "memory_operand" "m")] UNSPECV_LDXIO))]
+  ""
+  "ld<bhw_uns>io\\t%0, %1"
+  [(set_attr "type" "ld")])
+
+(define_expand "ld<bh>io"
+  [(set (match_operand:BH 0 "register_operand" "=r")
+        (match_operand:BH 1 "memory_operand" "m"))]
+  ""
+{
+  rtx tmp = gen_reg_rtx (SImode);
+  emit_insn (gen_ld<bh>io_signed (tmp, operands[1]));
+  emit_insn (gen_mov<mode> (operands[0], gen_lowpart (<MODE>mode, tmp)));
+  DONE;
+})
+
+(define_insn "ld<bh>io_signed"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (sign_extend:SI
+          (unspec_volatile:BH
+            [(match_operand:BH 1 "memory_operand" "m")] UNSPECV_LDXIO)))]
+  ""
+  "ld<bh>io\\t%0, %1"
+  [(set_attr "type" "ld")])
+
+(define_insn "st<bhw>io"
+  [(set (match_operand:BHW 0 "memory_operand" "=m")
+        (unspec_volatile:BHW
+          [(match_operand:BHW 1 "reg_or_0_operand" "rM")] UNSPECV_STXIO))]
+  ""
+  "st<bhw>io\\t%z1, %0"
+  [(set_attr "type" "st")])
+
+
+;; QI to [HI, SI] extension patterns are collected together
+(define_mode_iterator QX [HI SI])
+
+;; Zero extension patterns
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+        (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+  ""
+  "@
+    andi\\t%0, %1, 0xffff
+    ldhu%o1\\t%0, %1"
+  [(set_attr "type"     "alu,ld")])
+
+(define_insn "zero_extendqi<mode>2"
+  [(set (match_operand:QX 0 "register_operand" "=r,r")
+        (zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+  ""
+  "@
+    andi\\t%0, %1, 0xff
+    ldbu%o1\\t%0, %1"
+  [(set_attr "type"     "alu,ld")])
+
+;; Sign extension patterns
+
+(define_insn "extendhisi2"
+  [(set (match_operand:SI 0 "register_operand"                     "=r,r")
+        (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand"  "r,m")))]
+  ""
+  "@
+   #
+   ldh%o1\\t%0, %1"
+  [(set_attr "type" "alu,ld")])
+
+(define_insn "extendqi<mode>2"
+  [(set (match_operand:QX 0 "register_operand"                     "=r,r")
+        (sign_extend:QX (match_operand:QI 1 "nonimmediate_operand"  "r,m")))]
+  ""
+  "@
+   #
+   ldb%o1\\t%0, %1"
+  [(set_attr "type" "alu,ld")])
+
+;; Split patterns for register alternative cases.
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+        (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
+  "reload_completed"
+  [(set (match_dup 0)
+        (and:SI (match_dup 1) (const_int 65535)))
+   (set (match_dup 0)
+        (xor:SI (match_dup 0) (const_int 32768)))
+   (set (match_dup 0)
+        (plus:SI (match_dup 0) (const_int -32768)))]
+  "operands[1] = gen_lowpart (SImode, operands[1]);")
+
+(define_split
+  [(set (match_operand:QX 0 "register_operand" "")
+        (sign_extend:QX (match_operand:QI 1 "register_operand" "")))]
+  "reload_completed"
+  [(set (match_dup 0)
+        (and:SI (match_dup 1) (const_int 255)))
+   (set (match_dup 0)
+        (xor:SI (match_dup 0) (const_int 128)))
+   (set (match_dup 0)
+        (plus:SI (match_dup 0) (const_int -128)))]
+  "operands[0] = gen_lowpart (SImode, operands[0]);
+   operands[1] = gen_lowpart (SImode, operands[1]);")
+
+
+;; Arithmetic Operations
+
+(define_insn "addsi3"
+  [(set (match_operand:SI 0 "register_operand"            "=r")
+        (plus:SI (match_operand:SI 1 "register_operand"   "%r")
+                 (match_operand:SI 2 "add_regimm_operand" "rIT")))]
+  ""
+  "add%i2\\t%0, %1, %z2"
+  [(set_attr "type" "alu")])
+
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "register_operand"           "=r")
+        (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+                  (match_operand:SI 2 "register_operand" "r")))]
+  ""
+  "sub\\t%0, %z1, %2"
+  [(set_attr "type" "alu")])
+
+(define_insn "mulsi3"
+  [(set (match_operand:SI 0 "register_operand"          "=r")
+        (mult:SI (match_operand:SI 1 "register_operand" "%r")
+                 (match_operand:SI 2 "arith_operand"    "rI")))]
+  "TARGET_HAS_MUL"
+  "mul%i2\\t%0, %1, %z2"
+  [(set_attr "type" "mul")])
+
+(define_expand "divsi3"
+  [(set (match_operand:SI 0 "register_operand"          "=r")
+        (div:SI (match_operand:SI 1 "register_operand"   "r")
+                (match_operand:SI 2 "register_operand"   "r")))]
+  ""
+{
+  if (!TARGET_HAS_DIV)
+    {
+      if (TARGET_FAST_SW_DIV)
+        {
+          nios2_emit_expensive_div (operands, SImode);
+          DONE;
+        }
+      else
+        FAIL;
+    }
+})
+
+(define_insn "divsi3_insn"
+  [(set (match_operand:SI 0 "register_operand"            "=r")
+        (div:SI (match_operand:SI 1 "register_operand"     "r")
+                (match_operand:SI 2 "register_operand"     "r")))]
+  "TARGET_HAS_DIV"
+  "div\\t%0, %1, %2"
+  [(set_attr "type" "div")])
+
+(define_insn "udivsi3"
+  [(set (match_operand:SI 0 "register_operand"            "=r")
+        (udiv:SI (match_operand:SI 1 "register_operand"    "r")
+                 (match_operand:SI 2 "register_operand"    "r")))]
+  "TARGET_HAS_DIV"
+  "divu\\t%0, %1, %2"
+  [(set_attr "type" "div")])
+
+(define_code_iterator EXTEND [sign_extend zero_extend])
+(define_code_attr us [(sign_extend "s") (zero_extend "u")])
+(define_code_attr mul [(sign_extend "mul") (zero_extend "umul")])
+
+(define_insn "<us>mulsi3_highpart"
+  [(set (match_operand:SI 0 "register_operand"                       "=r")
+        (truncate:SI
+         (lshiftrt:DI
+          (mult:DI (EXTEND:DI (match_operand:SI 1 "register_operand"  "r"))
+                   (EXTEND:DI (match_operand:SI 2 "register_operand"  "r")))
+          (const_int 32))))]
+  "TARGET_HAS_MULX"
+  "mulx<us><us>\\t%0, %1, %2"
+  [(set_attr "type" "mul")])
+
+(define_expand "<mul>sidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(mult:DI (EXTEND:DI (match_operand:SI 1 "register_operand" ""))
+		 (EXTEND:DI (match_operand:SI 2 "register_operand" ""))))]
+  "TARGET_HAS_MULX"
+{
+  rtx hi = gen_reg_rtx (SImode);
+  rtx lo = gen_reg_rtx (SImode);
+
+  emit_insn (gen_<us>mulsi3_highpart (hi, operands[1], operands[2]));
+  emit_insn (gen_mulsi3 (lo, operands[1], operands[2]));
+  emit_move_insn (gen_lowpart (SImode, operands[0]), lo);
+  emit_move_insn (gen_highpart (SImode, operands[0]), hi);
+  DONE;
+})
+
+
+;;  Negate and ones complement
+
+(define_insn "negsi2"
+  [(set (match_operand:SI 0 "register_operand"        "=r")
+        (neg:SI (match_operand:SI 1 "register_operand" "r")))]
+  ""
+  "sub\\t%0, zero, %1"
+  [(set_attr "type" "alu")])
+
+(define_insn "one_cmplsi2"
+  [(set (match_operand:SI 0 "register_operand"        "=r")
+        (not:SI (match_operand:SI 1 "register_operand" "r")))]
+  ""
+  "nor\\t%0, zero, %1"
+  [(set_attr "type" "alu")])
+
+
+;;  Integer logical Operations
+
+(define_code_iterator LOGICAL [and ior xor])
+(define_code_attr logical_asm [(and "and") (ior "or") (xor "xor")])
+
+(define_insn "<code>si3"
+  [(set (match_operand:SI 0 "register_operand"             "=r,r,r")
+        (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r,r,r")
+                    (match_operand:SI 2 "logical_operand"  "rM,J,K")))]
+  ""
+  "@
+    <logical_asm>\\t%0, %1, %z2
+    <logical_asm>%i2\\t%0, %1, %2
+    <logical_asm>h%i2\\t%0, %1, %U2"
+  [(set_attr "type" "alu")])
+
+(define_insn "*norsi3"
+  [(set (match_operand:SI 0 "register_operand"                 "=r")
+        (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
+                (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))]
+  ""
+  "nor\\t%0, %1, %z2"
+  [(set_attr "type" "alu")])
+
+
+;;  Shift instructions
+
+(define_code_iterator SHIFT  [ashift ashiftrt lshiftrt rotate])
+(define_code_attr shift_op   [(ashift "ashl") (ashiftrt "ashr")
+                              (lshiftrt "lshr") (rotate "rotl")])
+(define_code_attr shift_asm  [(ashift "sll") (ashiftrt "sra")
+                              (lshiftrt "srl") (rotate "rol")])
+
+(define_insn "<shift_op>si3"
+  [(set (match_operand:SI 0 "register_operand"          "=r")
+        (SHIFT:SI (match_operand:SI 1 "register_operand" "r")
+                  (match_operand:SI 2 "shift_operand"    "rL")))]
+  ""
+  "<shift_asm>%i2\\t%0, %1, %z2"
+  [(set_attr "type" "shift")])
+
+(define_insn "rotrsi3"
+  [(set (match_operand:SI 0 "register_operand"             "=r")
+        (rotatert:SI (match_operand:SI 1 "register_operand" "r")
+                     (match_operand:SI 2 "register_operand" "r")))]
+  ""
+  "ror\\t%0, %1, %2"
+  [(set_attr "type" "shift")])
+
+
+;; Floating point instructions
+
+;; Mode iterator for single/double float
+(define_mode_iterator F [SF DF])
+(define_mode_attr f [(SF "s") (DF "d")])
+
+;; Basic arithmetic instructions
+(define_code_iterator FOP3 [plus minus mult div])
+(define_code_attr fop3 [(plus "add") (minus "sub") (mult "mul") (div "div")])
+
+(define_insn "<fop3><mode>3"
+  [(set (match_operand:F 0 "register_operand"        "=r")
+        (FOP3:F (match_operand:F 1 "register_operand" "r")
+                (match_operand:F 2 "register_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_f<fop3><f>)"
+  { return nios2_fpu_insn_asm (n2fpu_f<fop3><f>); }
+  [(set_attr "type" "custom")])
+
+;; Floating point min/max operations
+(define_code_iterator SMINMAX [smin smax])
+(define_code_attr minmax [(smin "min") (smax "max")])
+(define_insn "<code><mode>3"
+  [(set (match_operand:F 0 "register_operand" "=r")
+        (SMINMAX:F (match_operand:F 1 "register_operand" "r")
+                   (match_operand:F 2 "register_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_f<minmax><f>)"
+  { return nios2_fpu_insn_asm (n2fpu_f<minmax><f>); }
+  [(set_attr "type" "custom")])
+
+;; These 2-operand FP operations can be collected together
+(define_code_iterator FOP2 [abs neg sqrt])
+(define_insn "<code><mode>2"
+  [(set (match_operand:F 0 "register_operand" "=r")
+        (FOP2:F (match_operand:F 1 "register_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_f<code><f>)"
+  { return nios2_fpu_insn_asm (n2fpu_f<code><f>); }
+  [(set_attr "type" "custom")])
+
+;; X, Y register access instructions
+(define_insn "nios2_fwrx"
+  [(unspec_volatile [(match_operand:DF 0 "register_operand" "r")] UNSPECV_FWRX)]
+  "nios2_fpu_insn_enabled (n2fpu_fwrx)"
+  { return nios2_fpu_insn_asm (n2fpu_fwrx); }
+  [(set_attr "type" "custom")])
+
+(define_insn "nios2_fwry"
+  [(unspec_volatile [(match_operand:SF 0 "register_operand" "r")] UNSPECV_FWRY)]
+  "nios2_fpu_insn_enabled (n2fpu_fwry)"
+  { return nios2_fpu_insn_asm (n2fpu_fwry); }
+  [(set_attr "type" "custom")])
+
+;; The X, Y read insns uses an int iterator
+(define_int_iterator UNSPEC_READ_XY [UNSPECV_FRDXLO UNSPECV_FRDXHI
+                                     UNSPECV_FRDY])
+(define_int_attr read_xy [(UNSPECV_FRDXLO "frdxlo") (UNSPECV_FRDXHI "frdxhi")
+                          (UNSPECV_FRDY "frdy")])
+(define_insn "nios2_<read_xy>"
+  [(set (match_operand:SF 0 "register_operand" "=r")
+        (unspec_volatile:SF [(const_int 0)] UNSPEC_READ_XY))]
+  "nios2_fpu_insn_enabled (n2fpu_<read_xy>)"
+  { return nios2_fpu_insn_asm (n2fpu_<read_xy>); }
+  [(set_attr "type" "custom")])
+
+;; Various math functions
+(define_int_iterator MATHFUNC
+  [UNSPEC_FCOS UNSPEC_FSIN UNSPEC_FTAN UNSPEC_FATAN UNSPEC_FEXP UNSPEC_FLOG])
+(define_int_attr mathfunc [(UNSPEC_FCOS "cos") (UNSPEC_FSIN "sin")
+                           (UNSPEC_FTAN "tan") (UNSPEC_FATAN "atan")
+                           (UNSPEC_FEXP "exp") (UNSPEC_FLOG "log")])
+
+(define_insn "<mathfunc><mode>2"
+  [(set (match_operand:F 0 "register_operand" "=r")
+        (unspec:F [(match_operand:F 1 "register_operand" "r")] MATHFUNC))]
+  "nios2_fpu_insn_enabled (n2fpu_f<mathfunc><f>)"
+  { return nios2_fpu_insn_asm (n2fpu_f<mathfunc><f>); }
+  [(set_attr "type" "custom")])
+
+;; Converting between floating point and fixed point
+
+(define_code_iterator FLOAT [float unsigned_float])
+(define_code_iterator FIX [fix unsigned_fix])
+
+(define_code_attr conv_op [(float "float") (unsigned_float "floatuns")
+                           (fix "fix") (unsigned_fix "fixuns")])
+(define_code_attr i [(float "i") (unsigned_float "u")
+                     (fix "i") (unsigned_fix "u")])
+
+;; Integer to float conversions
+(define_insn "<conv_op>si<mode>2"
+  [(set (match_operand:F 0 "register_operand" "=r")
+        (FLOAT:F (match_operand:SI 1 "register_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_float<i><f>)"
+  { return nios2_fpu_insn_asm (n2fpu_float<i><f>); }
+  [(set_attr "type" "custom")])
+
+;; Float to integer conversions
+(define_insn "<conv_op>_trunc<mode>si2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (FIX:SI (match_operand:F 1 "general_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_fix<f><i>)"
+  { return nios2_fpu_insn_asm (n2fpu_fix<f><i>); }
+  [(set_attr "type" "custom")])
+
+(define_insn "extendsfdf2"
+  [(set (match_operand:DF 0 "register_operand" "=r")
+        (float_extend:DF (match_operand:SF 1 "general_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_fextsd)"
+  { return nios2_fpu_insn_asm (n2fpu_fextsd); }
+  [(set_attr "type" "custom")])
+
+(define_insn "truncdfsf2"
+  [(set (match_operand:SF 0 "register_operand" "=r")
+        (float_truncate:SF (match_operand:DF 1 "general_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_ftruncds)"
+  { return nios2_fpu_insn_asm (n2fpu_ftruncds); }
+  [(set_attr "type" "custom")])
+
+
+
+;; Prologue, Epilogue and Return
+
+(define_expand "prologue"
+  [(const_int 1)]
+  ""
+{
+  nios2_expand_prologue ();
+  DONE;
+})
+
+(define_expand "epilogue"
+  [(return)]
+  ""
+{
+  nios2_expand_epilogue (false);
+  DONE;
+})
+
+(define_expand "sibcall_epilogue"
+  [(return)]
+  ""
+{
+  nios2_expand_epilogue (true);
+  DONE;
+})
+
+(define_insn "return"
+  [(simple_return)]
+  "nios2_can_use_return_insn ()"
+  "ret")
+
+(define_insn "simple_return"
+  [(simple_return)]
+  ""
+  "ret")
+
+;; Block any insns from being moved before this point, since the
+;; profiling call to mcount can use various registers that aren't
+;; saved or used to pass arguments.
+
+(define_insn "blockage"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
+  ""
+  ""
+  [(set_attr "type" "unknown")
+   (set_attr "length" "0")])
+
+;; This is used in compiling the unwind routines.
+(define_expand "eh_return"
+  [(use (match_operand 0 "general_operand"))]
+  ""
+{
+  if (GET_MODE (operands[0]) != Pmode)
+    operands[0] = convert_to_mode (Pmode, operands[0], 0);
+  emit_insn (gen_eh_set_ra (operands[0]));
+  DONE;
+})
+
+;; Modify the return address for EH return.  We can't expand this
+;; until we know where it will be put in the stack frame.
+
+(define_insn_and_split "eh_set_ra"
+  [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
+   (clobber (match_scratch:SI 1 "=&r"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  nios2_set_return_address (operands[0], operands[1]);
+  DONE;
+})
+
+
+;;  Jumps and calls
+
+; Note that the assembler fixes up any out-of-range branch instructions not
+; caught by the compiler branch shortening code.  The sequence emitted by
+; the assembler can be very inefficient, but it is correct for PIC code.
+; For non-PIC we are better off converting to an absolute JMPI.
+;
+; Direct calls and sibcalls use the CALL and JMPI instructions, respectively.
+; These instructions have an immediate operand that specifies the low 28 bits
+; of the PC, effectively allowing direct calls within a 256MB memory segment.
+; Per the Nios II Processor Reference Handbook, the linker is not required to
+; check or adjust for overflow.
+
+(define_insn "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
+  ""
+  "jmp\\t%0"
+  [(set_attr "type" "control")])
+
+(define_insn "jump"
+  [(set (pc)
+        (label_ref (match_operand 0 "" "")))]
+  ""
+  {
+    if (flag_pic || get_attr_length (insn) == 4)
+      return "br\\t%0";
+    else
+      return "jmpi\\t%0";
+  }
+  [(set_attr "type" "control")
+   (set (attr "length") 
+        (if_then_else
+	    (and (ge (minus (match_dup 0) (pc)) (const_int -32768))
+	         (le (minus (match_dup 0) (pc)) (const_int 32764)))
+	    (const_int 4)
+	    (const_int 8)))])
+
+
+(define_expand "call"
+  [(parallel [(call (match_operand 0 "" "")
+                    (match_operand 1 "" ""))
+              (clobber (reg:SI RA_REGNO))])]
+  ""
+  "nios2_adjust_call_address (&operands[0]);")
+
+(define_expand "call_value"
+  [(parallel [(set (match_operand 0 "" "")
+                   (call (match_operand 1 "" "")
+                         (match_operand 2 "" "")))
+              (clobber (reg:SI RA_REGNO))])]
+  ""
+  "nios2_adjust_call_address (&operands[1]);")
+
+(define_insn "*call"
+  [(call (mem:QI (match_operand:SI 0 "call_operand" "i,r"))
+         (match_operand 1 "" ""))
+   (clobber (reg:SI RA_REGNO))]
+  ""
+  "@
+   call\\t%0
+   callr\\t%0"
+  [(set_attr "type" "control")])
+
+(define_insn "*call_value"
+  [(set (match_operand 0 "" "")
+        (call (mem:QI (match_operand:SI 1 "call_operand" "i,r"))
+              (match_operand 2 "" "")))
+   (clobber (reg:SI RA_REGNO))]
+  ""
+  "@
+   call\\t%1
+   callr\\t%1"
+  [(set_attr "type" "control")])
+
+(define_expand "sibcall"
+  [(parallel [(call (match_operand 0 "" "")
+                    (match_operand 1 "" ""))
+              (return)])]
+  ""
+  "nios2_adjust_call_address (&operands[0]);")
+
+(define_expand "sibcall_value"
+  [(parallel [(set (match_operand 0 "" "")
+                   (call (match_operand 1 "" "")
+                         (match_operand 2 "" "")))
+              (return)])]
+  ""
+  "nios2_adjust_call_address (&operands[1]);")
+
+(define_insn "*sibcall"
+ [(call (mem:QI (match_operand:SI 0 "call_operand" "i,j"))
+        (match_operand 1 "" ""))
+  (return)]
+  ""
+  "@
+   jmpi\\t%0
+   jmp\\t%0"
+  [(set_attr "type" "control")])
+
+(define_insn "*sibcall_value"
+ [(set (match_operand 0 "register_operand" "")
+       (call (mem:QI (match_operand:SI 1 "call_operand" "i,j"))
+             (match_operand 2 "" "")))
+  (return)]
+  ""
+  "@
+   jmpi\\t%1
+   jmp\\t%1"
+  [(set_attr "type" "control")])
+
+(define_expand "tablejump"
+  [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
+              (use (label_ref (match_operand 1 "" "")))])]
+  ""
+{
+  if (flag_pic)
+    {
+      /* Hopefully, CSE will eliminate this copy.  */
+      rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1]));
+      rtx reg2 = gen_reg_rtx (SImode);
+
+      emit_insn (gen_addsi3 (reg2, operands[0], reg1));
+      operands[0] = reg2;
+    }
+})
+
+(define_insn "*tablejump"
+  [(set (pc)
+        (match_operand:SI 0 "register_operand" "r"))
+   (use (label_ref (match_operand 1 "" "")))]
+  ""
+  "jmp\\t%0"
+  [(set_attr "type" "control")])
+
+
+;; cstore, cbranch patterns
+
+(define_mode_iterator CM [SI SF DF])
+
+(define_expand "cstore<mode>4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (match_operator:SI 1 "expandable_comparison_operator"
+	  [(match_operand:CM 2 "register_operand")
+	   (match_operand:CM 3 "nonmemory_operand")]))]
+  ""
+{
+  if (!nios2_validate_compare (<MODE>mode, &operands[1], &operands[2],
+                               &operands[3]))
+    FAIL;
+})
+
+(define_expand "cbranch<mode>4"
+  [(set (pc)
+     (if_then_else
+       (match_operator 0 "expandable_comparison_operator"
+         [(match_operand:CM 1 "register_operand")
+          (match_operand:CM 2 "nonmemory_operand")])
+       (label_ref (match_operand 3 ""))
+       (pc)))]
+  ""
+{
+  if (!nios2_validate_compare (<MODE>mode, &operands[0], &operands[1],
+                               &operands[2]))
+    FAIL;
+  if (GET_MODE_CLASS (<MODE>mode) == MODE_FLOAT
+      || !reg_or_0_operand (operands[2], <MODE>mode))
+    {
+      rtx condreg = gen_reg_rtx (SImode);
+      emit_insn (gen_cstore<mode>4
+                  (condreg, operands[0], operands[1], operands[2]));
+      operands[1] = condreg;
+      operands[2] = const0_rtx;
+      operands[0] = gen_rtx_fmt_ee (NE, VOIDmode, condreg, const0_rtx);
+    }
+})
+
+(define_insn "nios2_cbranch"
+  [(set (pc)
+     (if_then_else
+       (match_operator 0 "ordered_comparison_operator"
+         [(match_operand:SI 1 "reg_or_0_operand" "rM")
+          (match_operand:SI 2 "reg_or_0_operand" "rM")])
+       (label_ref (match_operand 3 "" ""))
+       (pc)))]
+  ""
+  {
+    if (flag_pic || get_attr_length (insn) == 4)
+      return "b%0\t%z1, %z2, %l3";
+    else
+      return "b%R0\t%z1, %z2, .+8;jmpi\t%l3";
+  }
+  [(set_attr "type" "control")
+   (set (attr "length") 
+        (if_then_else
+	    (and (ge (minus (match_dup 1) (pc)) (const_int -32768))
+	         (le (minus (match_dup 1) (pc)) (const_int 32764)))
+	    (const_int 4) (const_int 8)))])
+
+;; Floating point comparisons
+(define_code_iterator FCMP [eq ne gt ge le lt])
+(define_insn "nios2_s<code><mode>"
+  [(set (match_operand:SI 0 "register_operand"        "=r")
+        (FCMP:SI (match_operand:F 1 "register_operand" "r")
+                 (match_operand:F 2 "register_operand" "r")))]
+  "nios2_fpu_insn_enabled (n2fpu_fcmp<code><f>)"
+  { return nios2_fpu_insn_asm (n2fpu_fcmp<code><f>); }
+  [(set_attr "type" "custom")])
+
+;; Integer comparisons
+
+(define_code_iterator EQNE [eq ne])
+(define_insn "nios2_cmp<code>"
+  [(set (match_operand:SI 0 "register_operand"           "=r")
+        (EQNE:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
+                 (match_operand:SI 2 "arith_operand"     "rI")))]
+  ""
+  "cmp<code>%i2\\t%0, %z1, %z2"
+  [(set_attr "type" "alu")])
+
+(define_code_iterator SCMP [ge lt])
+(define_insn "nios2_cmp<code>"
+  [(set (match_operand:SI 0 "register_operand"           "=r")
+        (SCMP:SI (match_operand:SI 1 "reg_or_0_operand"  "rM")
+                 (match_operand:SI 2 "arith_operand"     "rI")))]
+  ""
+  "cmp<code>%i2\\t%0, %z1, %z2"
+  [(set_attr "type" "alu")])
+
+(define_code_iterator UCMP [geu ltu])
+(define_insn "nios2_cmp<code>"
+  [(set (match_operand:SI 0 "register_operand"           "=r")
+        (UCMP:SI (match_operand:SI 1 "reg_or_0_operand"  "rM")
+                 (match_operand:SI 2 "uns_arith_operand" "rJ")))]
+  ""
+  "cmp<code>%i2\\t%0, %z1, %z2"
+  [(set_attr "type" "alu")])
+
+
+
+;; Custom instruction patterns.  The operands are intentionally
+;; mode-less, to serve as generic carriers of all Altera defined
+;; built-in instruction/function types.
+
+(define_insn "custom_nxx"
+  [(unspec_volatile [(match_operand 0 "custom_insn_opcode" "N")
+                     (match_operand 1 "reg_or_0_operand"  "rM")
+                     (match_operand 2 "reg_or_0_operand"  "rM")]
+    UNSPECV_CUSTOM_NXX)]
+  ""
+  "custom\\t%0, zero, %z1, %z2"
+  [(set_attr "type" "custom")])
+
+(define_insn "custom_xnxx"
+  [(set (match_operand 0 "register_operand"   "=r")
+        (unspec_volatile [(match_operand 1 "custom_insn_opcode" "N")
+                          (match_operand 2 "reg_or_0_operand"  "rM")
+                          (match_operand 3 "reg_or_0_operand"  "rM")] 
+	 UNSPECV_CUSTOM_XNXX))]
+  ""
+  "custom\\t%1, %0, %z2, %z3"
+  [(set_attr "type" "custom")])
+
+
+;;  Misc. patterns
+
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop"
+  [(set_attr "type" "alu")])
+
+;; Connect 'sync' to 'memory_barrier' standard expand name
+(define_expand "memory_barrier"
+  [(const_int 0)]
+  ""
+{
+  emit_insn (gen_sync ());
+  DONE;
+})
+
+;; For the nios2 __builtin_sync built-in function
+(define_expand "sync"
+  [(set (match_dup 0)
+	(unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
+  ""
+{
+  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
+  MEM_VOLATILE_P (operands[0]) = 1;
+})
+
+(define_insn "*sync_insn"
+  [(set (match_operand:BLK 0 "" "")
+	(unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
+  ""
+  "sync"
+  [(set_attr "type" "control")])
+
+(define_insn "rdctl"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] 
+	 UNSPECV_RDCTL))]
+  ""
+  "rdctl\\t%0, ctl%1"
+  [(set_attr "type" "control")])
+
+(define_insn "wrctl"
+  [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand"  "O")
+                        (match_operand:SI 1 "reg_or_0_operand" "rM")] 
+    UNSPECV_WRCTL)]
+  ""
+  "wrctl\\tctl%0, %z1"
+  [(set_attr "type" "control")])
+
+;; Trap patterns
+(define_insn "trap"
+  [(trap_if (const_int 1) (const_int 3))]
+  ""
+  "break\\t3"
+  [(set_attr "type" "control")])
+
+(define_insn "ctrapsi4"
+  [(trap_if (match_operator 0 "ordered_comparison_operator"
+              [(match_operand:SI 1 "reg_or_0_operand" "rM")
+               (match_operand:SI 2 "reg_or_0_operand" "rM")])
+            (match_operand 3 "const_int_operand" "i"))]
+  ""
+  "b%R0\\t%z1, %z2, 1f\;break\\t%3\;1:"
+  [(set_attr "type" "control")
+   (set_attr "length" "8")])
+  
+;; Load the GOT register.
+(define_insn "load_got_register"
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+	 (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))
+   (set (match_operand:SI 1 "register_operand" "=r")
+	 (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))]
+  ""
+  "nextpc\\t%0
+\\t1:
+\\tmovhi\\t%1, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b)
+\\taddi\\t%1, %1, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)"
+  [(set_attr "length" "12")])
+
+;; Read thread pointer register
+(define_expand "get_thread_pointersi"
+  [(match_operand:SI 0 "register_operand" "=r")]
+  "TARGET_LINUX_ABI"
+{
+  emit_move_insn (operands[0], gen_rtx_REG (Pmode, TP_REGNO));
+  DONE;
+})
Index: gcc/config/nios2/nios2.c
===================================================================
--- gcc/config/nios2/nios2.c	(revision 0)
+++ gcc/config/nios2/nios2.c	(revision 0)
@@ -0,0 +1,3218 @@ 
+/* Target machine subroutines for Altera Nios II.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Jonah Graham (jgraham@altera.com), 
+   Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tree.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "expr.h"
+#include "optabs.h"
+#include "function.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
+#include "target.h"
+#include "target-def.h"
+#include "tm_p.h"
+#include "langhooks.h"
+#include "df.h"
+#include "debug.h"
+#include "real.h"
+#include "reload.h"
+
+/* Forward function declarations.  */
+static bool nios2_rtx_costs (rtx, int, int, int, int *, bool);
+static reg_class_t nios2_preferred_reload_class (rtx, reg_class_t);
+static void nios2_print_operand (FILE *, rtx, int);
+static void nios2_print_operand_address (FILE *, rtx);
+static bool nios2_output_addr_const_extra (FILE *, rtx);
+static const char *nios2_unspec_reloc_name (int);
+static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT);
+static struct machine_function *nios2_init_machine_status (void);
+static bool nios2_in_small_data_p (const_tree);
+static void nios2_dump_frame_layout (FILE *);
+static int nios2_compute_frame_layout (void);
+static bool prologue_saved_reg_p (unsigned);
+static void save_reg (int, unsigned);
+static void restore_reg (int, unsigned);
+static unsigned int nios2_section_type_flags (tree, const char *, int);
+static bool nios2_can_eliminate (const int, const int);
+static void nios2_load_pic_register (void);
+static rtx nios2_load_pic_address (rtx, int);
+static bool nios2_cannot_force_const_mem (enum machine_mode, rtx);
+static rtx nios2_legitimize_constant_address (rtx);
+static bool nios2_legitimate_constant_p (enum machine_mode, rtx);
+static rtx nios2_legitimize_address (rtx, rtx, enum machine_mode);
+static bool nios2_legitimate_address_p (enum machine_mode, rtx, bool);
+static bool nios2_tls_symbol_p (rtx);
+static void nios2_init_builtins (void);
+static tree nios2_builtin_decl (unsigned, bool);
+static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static void nios2_init_libfuncs (void);
+static rtx nios2_function_arg (cumulative_args_t, enum machine_mode,
+			       const_tree, bool);
+static void nios2_function_arg_advance (cumulative_args_t, enum machine_mode,
+					const_tree, bool);
+static void nios2_setup_incoming_varargs (cumulative_args_t, enum machine_mode, 
+					  tree, int *, int);
+static int nios2_arg_partial_bytes (cumulative_args_t,
+				    enum machine_mode, tree, bool);
+static void nios2_trampoline_init (rtx, tree, rtx);
+static rtx nios2_function_value (const_tree, const_tree, bool);
+static rtx nios2_libcall_value (enum machine_mode, const_rtx);
+static bool nios2_function_value_regno_p (const unsigned int);
+static bool nios2_return_in_memory (const_tree, const_tree);
+static void nios2_output_dwarf_dtprel (FILE *, int, rtx);
+static void nios2_option_override (void);
+static void nios2_option_save (struct cl_target_option *, struct gcc_options *);
+static void nios2_option_restore (struct gcc_options *, struct cl_target_option *);
+static void nios2_set_current_function (tree);
+static bool nios2_valid_target_attribute_p (tree, tree, tree, int);
+static bool nios2_pragma_target_parse (tree, tree);
+static tree nios2_merge_decl_attributes (tree, tree);
+static void nios2_custom_check_insns (void);
+static void nios2_handle_custom_fpu_cfg (const char *, bool);
+static void nios2_handle_custom_fpu_insn_option (int);
+static void nios2_register_custom_code (unsigned int, enum nios2_ccs_code, int);
+static void nios2_deregister_custom_code (unsigned int);
+static void nios2_register_builtin_fndecl (unsigned, tree);
+
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
+
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p
+
+#undef  TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS  nios2_section_type_flags
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS nios2_init_builtins
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN nios2_expand_builtin
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL nios2_builtin_decl
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS nios2_init_libfuncs
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_true
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE nios2_can_eliminate
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG nios2_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE nios2_function_arg_advance
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES nios2_arg_partial_bytes
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT nios2_trampoline_init
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE nios2_function_value
+
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE nios2_libcall_value
+
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P nios2_function_value_regno_p
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY nios2_return_in_memory
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS nios2_setup_incoming_varargs
+
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P nios2_legitimate_constant_p
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS nios2_legitimize_address
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P nios2_legitimate_address_p
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS nios2_preferred_reload_class
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS nios2_rtx_costs
+
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS TARGET_LINUX_ABI
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM nios2_cannot_force_const_mem
+
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND nios2_print_operand
+
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS nios2_print_operand_address
+
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nios2_output_addr_const_extra
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE nios2_option_override
+
+#undef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE nios2_option_save
+
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE nios2_option_restore
+
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION nios2_set_current_function
+
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P nios2_valid_target_attribute_p
+
+#undef TARGET_OPTION_PRAGMA_PARSE
+#define TARGET_OPTION_PRAGMA_PARSE nios2_pragma_target_parse
+
+#undef TARGET_MERGE_DECL_ATTRIBUTES
+#define TARGET_MERGE_DECL_ATTRIBUTES nios2_merge_decl_attributes
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+
+/* Threshold for data being put into the small data/bss area, instead
+   of the normal data area (references to the small data/bss area take
+   1 instruction, and use the global pointer, references to the normal
+   data area takes 2 instructions).  */
+unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE;
+
+struct GTY (()) machine_function
+{
+  /* Current frame information, to be filled in by nios2_compute_frame_layout
+     with register save masks, and offsets for the current function.  */
+
+  unsigned int save_mask; /* Mask of registers to save.  */
+  int total_size;         /* # bytes that the entire frame takes up.  */
+  int var_size;           /* # bytes that variables take up.  */
+  int args_size;          /* # bytes that outgoing arguments take up.  */
+  int save_reg_size;      /* # bytes needed to store gp regs.  */
+  int save_regs_offset;   /* Offset from new sp to store gp registers.  */
+  int initialized;        /* != 0 if frame size already calculated.  */
+};
+
+/* State to track the assignment of custom codes to FPU/custom builtins.  */
+static enum nios2_ccs_code custom_code_status[256];
+static int custom_code_index[256];
+/* Set to true if any conflicts (re-use of a code between 0-255) are found.  */
+static bool custom_code_conflict = false;
+
+
+
+/* Definition of builtin function types for nios2.  */
+
+#define N2_FTYPES				\
+  N2_FTYPE(1, (SF))				\
+  N2_FTYPE(1, (VOID))				\
+  N2_FTYPE(2, (DF, DF))				\
+  N2_FTYPE(3, (DF, DF, DF))			\
+  N2_FTYPE(2, (DF, SF))				\
+  N2_FTYPE(2, (DF, SI))				\
+  N2_FTYPE(2, (DF, UI))				\
+  N2_FTYPE(2, (SF, DF))				\
+  N2_FTYPE(2, (SF, SF))				\
+  N2_FTYPE(3, (SF, SF, SF))			\
+  N2_FTYPE(2, (SF, SI))				\
+  N2_FTYPE(2, (SF, UI))				\
+  N2_FTYPE(2, (SI, CVPTR))			\
+  N2_FTYPE(2, (SI, DF))				\
+  N2_FTYPE(3, (SI, DF, DF))			\
+  N2_FTYPE(2, (SI, SF))				\
+  N2_FTYPE(3, (SI, SF, SF))			\
+  N2_FTYPE(2, (SI, SI))				\
+  N2_FTYPE(2, (UI, CVPTR))			\
+  N2_FTYPE(2, (UI, DF))				\
+  N2_FTYPE(2, (UI, SF))				\
+  N2_FTYPE(2, (VOID, DF))			\
+  N2_FTYPE(2, (VOID, SF))			\
+  N2_FTYPE(3, (VOID, SI, SI))			\
+  N2_FTYPE(3, (VOID, VPTR, SI))
+
+#define N2_FTYPE_OP1(R)         N2_FTYPE_ ## R ## _VOID
+#define N2_FTYPE_OP2(R, A1)     N2_FTYPE_ ## R ## _ ## A1
+#define N2_FTYPE_OP3(R, A1, A2) N2_FTYPE_ ## R ## _ ## A1 ## _ ## A2
+
+/* Expand ftcode enumeration.  */
+enum nios2_ftcode {
+#define N2_FTYPE(N,ARGS) N2_FTYPE_OP ## N ARGS,
+N2_FTYPES
+#undef N2_FTYPE
+N2_FTYPE_MAX
+};
+
+/* Return the tree function type, based on the ftcode.  */
+static tree
+nios2_ftype (enum nios2_ftcode ftcode)
+{
+  static tree types[(int) N2_FTYPE_MAX];
+
+  tree N2_TYPE_SF = float_type_node;
+  tree N2_TYPE_DF = double_type_node;
+  tree N2_TYPE_SI = integer_type_node;
+  tree N2_TYPE_UI = unsigned_type_node;
+  tree N2_TYPE_VOID = void_type_node;
+
+  static const_tree N2_TYPE_CVPTR, N2_TYPE_VPTR;
+  if (!N2_TYPE_CVPTR)
+    {
+      /* const volatile void *.  */
+      N2_TYPE_CVPTR
+	= build_pointer_type (build_qualified_type (void_type_node,
+						    (TYPE_QUAL_CONST
+						     | TYPE_QUAL_VOLATILE)));
+      /* volatile void *.  */
+      N2_TYPE_VPTR
+	= build_pointer_type (build_qualified_type (void_type_node,
+						    TYPE_QUAL_VOLATILE));
+    }
+  if (types[(int) ftcode] == NULL_TREE)
+    switch (ftcode)
+      {
+#define N2_FTYPE_ARGS1(R) N2_TYPE_ ## R
+#define N2_FTYPE_ARGS2(R,A1) N2_TYPE_ ## R, N2_TYPE_ ## A1
+#define N2_FTYPE_ARGS3(R,A1,A2) N2_TYPE_ ## R, N2_TYPE_ ## A1, N2_TYPE_ ## A2
+#define N2_FTYPE(N,ARGS)						\
+  case N2_FTYPE_OP ## N ARGS:						\
+    types[(int) ftcode]							\
+      = build_function_type_list (N2_FTYPE_ARGS ## N ARGS, NULL_TREE); \
+    break;
+	N2_FTYPES
+#undef N2_FTYPE
+      default: gcc_unreachable ();
+      }
+  return types[(int) ftcode];
+}
+
+
+/* Definition of FPU instruction descriptions.  */
+
+struct nios2_fpu_insn_info
+{
+  const char *name;
+  int num_operands, *optvar;
+  int opt, no_opt;
+#define N2F_DF            0x1
+#define N2F_DFREQ         0x2
+#define N2F_UNSAFE        0x4
+#define N2F_FINITE        0x8
+  unsigned int flags;
+  enum insn_code icode;
+  enum nios2_ftcode ftcode;
+};
+
+/* Base macro for defining FPU instructions.  */
+#define N2FPU_INSN_DEF_BASE(insn, nop, flags, icode, args)	\
+  { #insn, nop, &nios2_custom_ ## insn, OPT_mcustom_##insn##_,	\
+    OPT_mno_custom_##insn, flags, CODE_FOR_ ## icode,		\
+    N2_FTYPE_OP ## nop args }
+
+/* Arithmetic and math functions; 2 or 3 operand FP operations.  */
+#define N2FPU_OP2(mode) (mode, mode)
+#define N2FPU_OP3(mode) (mode, mode, mode)
+#define N2FPU_INSN_DEF(code, icode, nop, flags, m, M)			\
+  N2FPU_INSN_DEF_BASE (f ## code ## m, nop, flags,			\
+		       icode ## m ## f ## nop, N2FPU_OP ## nop (M ## F))
+#define N2FPU_INSN_SF(code, nop, flags)		\
+  N2FPU_INSN_DEF (code, code, nop, flags, s, S)
+#define N2FPU_INSN_DF(code, nop, flags)		\
+  N2FPU_INSN_DEF (code, code, nop, flags | N2F_DF, d, D)
+
+/* Compare instructions, 3 operand FP operation with a SI result.  */
+#define N2FPU_CMP_DEF(code, flags, m, M)				\
+  N2FPU_INSN_DEF_BASE (fcmp ## code ## m, 3, flags,			\
+		       nios2_s ## code ## m ## f, (SI, M ## F, M ## F))
+#define N2FPU_CMP_SF(code) N2FPU_CMP_DEF (code, 0, s, S)
+#define N2FPU_CMP_DF(code) N2FPU_CMP_DEF (code, N2F_DF, d, D)
+
+/* The order of definition needs to be maintained consistent with
+   enum n2fpu_code in nios2-opts.h.  */
+struct nios2_fpu_insn_info nios2_fpu_insn[] =
+  {
+    /* Single precision instructions.  */
+    N2FPU_INSN_SF (add, 3, 0),
+    N2FPU_INSN_SF (sub, 3, 0),
+    N2FPU_INSN_SF (mul, 3, 0),
+    N2FPU_INSN_SF (div, 3, 0),
+    /* Due to textual difference between min/max and smin/smax.  */
+    N2FPU_INSN_DEF (min, smin, 3, N2F_FINITE, s, S),
+    N2FPU_INSN_DEF (max, smax, 3, N2F_FINITE, s, S),
+    N2FPU_INSN_SF (neg, 2, 0),
+    N2FPU_INSN_SF (abs, 2, 0),
+    N2FPU_INSN_SF (sqrt, 2, 0),
+    N2FPU_INSN_SF (sin, 2, N2F_UNSAFE),
+    N2FPU_INSN_SF (cos, 2, N2F_UNSAFE),
+    N2FPU_INSN_SF (tan, 2, N2F_UNSAFE),
+    N2FPU_INSN_SF (atan, 2, N2F_UNSAFE),
+    N2FPU_INSN_SF (exp, 2, N2F_UNSAFE),
+    N2FPU_INSN_SF (log, 2, N2F_UNSAFE),
+    /* Single precision compares.  */
+    N2FPU_CMP_SF (eq), N2FPU_CMP_SF (ne),
+    N2FPU_CMP_SF (lt), N2FPU_CMP_SF (le),
+    N2FPU_CMP_SF (gt), N2FPU_CMP_SF (ge),
+
+    /* Double precision instructions.  */
+    N2FPU_INSN_DF (add, 3, 0),
+    N2FPU_INSN_DF (sub, 3, 0),
+    N2FPU_INSN_DF (mul, 3, 0),
+    N2FPU_INSN_DF (div, 3, 0),
+    /* Due to textual difference between min/max and smin/smax.  */
+    N2FPU_INSN_DEF (min, smin, 3, N2F_FINITE, d, D),
+    N2FPU_INSN_DEF (max, smax, 3, N2F_FINITE, d, D),
+    N2FPU_INSN_DF (neg, 2, 0),
+    N2FPU_INSN_DF (abs, 2, 0),
+    N2FPU_INSN_DF (sqrt, 2, 0),
+    N2FPU_INSN_DF (sin, 2, N2F_UNSAFE),
+    N2FPU_INSN_DF (cos, 2, N2F_UNSAFE),
+    N2FPU_INSN_DF (tan, 2, N2F_UNSAFE),
+    N2FPU_INSN_DF (atan, 2, N2F_UNSAFE),
+    N2FPU_INSN_DF (exp, 2, N2F_UNSAFE),
+    N2FPU_INSN_DF (log, 2, N2F_UNSAFE),
+    /* Double precision compares.  */
+    N2FPU_CMP_DF (eq), N2FPU_CMP_DF (ne),
+    N2FPU_CMP_DF (lt), N2FPU_CMP_DF (le),
+    N2FPU_CMP_DF (gt), N2FPU_CMP_DF (ge),
+
+    /* Conversion instructions.  */
+    N2FPU_INSN_DEF_BASE (floatis,  2, 0, floatsisf2,    (SF, SI)),
+    N2FPU_INSN_DEF_BASE (floatus,  2, 0, floatunssisf2, (SF, UI)),
+    N2FPU_INSN_DEF_BASE (floatid,  2, 0, floatsidf2,    (DF, SI)),
+    N2FPU_INSN_DEF_BASE (floatud,  2, 0, floatunssidf2, (DF, UI)),
+    N2FPU_INSN_DEF_BASE (fixsi,    2, 0, fix_truncsfsi2,      (SI, SF)),
+    N2FPU_INSN_DEF_BASE (fixsu,    2, 0, fixuns_truncsfsi2,   (UI, SF)),
+    N2FPU_INSN_DEF_BASE (fixdi,    2, 0, fix_truncdfsi2,      (SI, DF)),
+    N2FPU_INSN_DEF_BASE (fixdu,    2, 0, fixuns_truncdfsi2,   (UI, DF)),
+    N2FPU_INSN_DEF_BASE (fextsd,   2, 0, extendsfdf2,   (DF, SF)),
+    N2FPU_INSN_DEF_BASE (ftruncds, 2, 0, truncdfsf2,    (SF, DF)),
+
+    /* X, Y access instructions.  */
+    N2FPU_INSN_DEF_BASE (fwrx,     2, N2F_DFREQ, nios2_fwrx,   (VOID, DF)),
+    N2FPU_INSN_DEF_BASE (fwry,     2, N2F_DFREQ, nios2_fwry,   (VOID, SF)),
+    N2FPU_INSN_DEF_BASE (frdxlo,   1, N2F_DFREQ, nios2_frdxlo, (SF)),
+    N2FPU_INSN_DEF_BASE (frdxhi,   1, N2F_DFREQ, nios2_frdxhi, (SF)),
+    N2FPU_INSN_DEF_BASE (frdy,     1, N2F_DFREQ, nios2_frdy,   (SF))
+  };
+
+/* Some macros for ease of access.  */
+#define N2FPU(code) nios2_fpu_insn[(int) code]
+#define N2FPU_ENABLED_P(code) (N2FPU_N(code) >= 0)
+#define N2FPU_N(code) (*N2FPU(code).optvar)
+#define N2FPU_NAME(code) (N2FPU(code).name)
+#define N2FPU_ICODE(code) (N2FPU(code).icode)
+#define N2FPU_FTCODE(code) (N2FPU(code).ftcode)
+#define N2FPU_FINITE_P(code) (N2FPU(code).flags & N2F_FINITE)
+#define N2FPU_UNSAFE_P(code) (N2FPU(code).flags & N2F_UNSAFE)
+#define N2FPU_DOUBLE_P(code) (N2FPU(code).flags & N2F_DF)
+#define N2FPU_DOUBLE_REQUIRED_P(code) (N2FPU(code).flags & N2F_DFREQ)
+
+/* Same as above, but for cases where using only the op part is shorter.  */
+#define N2FPU_OP(op) N2FPU(n2fpu_ ## op)
+#define N2FPU_OP_NAME(op) N2FPU_NAME(n2fpu_ ## op)
+#define N2FPU_OP_ENABLED_P(op) N2FPU_ENABLED_P(n2fpu_ ## op)
+
+/* Export the FPU insn enabled predicate to nios2.md.  */
+bool
+nios2_fpu_insn_enabled (enum n2fpu_code code)
+{
+  return N2FPU_ENABLED_P (code);
+}
+
+/* Return true if COND comparison for mode MODE is enabled under current
+   settings.  */
+
+static bool
+nios2_fpu_compare_enabled (enum rtx_code cond, enum machine_mode mode)
+{
+  if (mode == SFmode)
+    switch (cond) 
+      {
+      case EQ: return N2FPU_OP_ENABLED_P (fcmpeqs);
+      case NE: return N2FPU_OP_ENABLED_P (fcmpnes);
+      case GT: return N2FPU_OP_ENABLED_P (fcmpgts);
+      case GE: return N2FPU_OP_ENABLED_P (fcmpges);
+      case LT: return N2FPU_OP_ENABLED_P (fcmplts);
+      case LE: return N2FPU_OP_ENABLED_P (fcmples);
+      default: break;
+      }
+  else if (mode == DFmode)
+    switch (cond) 
+      {
+      case EQ: return N2FPU_OP_ENABLED_P (fcmpeqd);
+      case NE: return N2FPU_OP_ENABLED_P (fcmpned);
+      case GT: return N2FPU_OP_ENABLED_P (fcmpgtd);
+      case GE: return N2FPU_OP_ENABLED_P (fcmpged);
+      case LT: return N2FPU_OP_ENABLED_P (fcmpltd);
+      case LE: return N2FPU_OP_ENABLED_P (fcmpled);
+      default: break;
+      }
+  return false;
+}
+
+
+/* Stack layout and calling conventions.  */
+
+/* Generate save/restore of register REGNO at SP + OFFSET.  Used by the
+   prologue/epilogue expand routines.  */
+static void
+save_reg (int regno, unsigned offset)
+{
+  rtx reg = gen_rtx_REG (SImode, regno);
+  rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+			   gen_int_mode (offset, Pmode));
+
+  rtx pattern = gen_rtx_SET (VOIDmode, gen_frame_mem (Pmode, addr), reg);
+  rtx insn = emit_insn (pattern);
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
+static void
+restore_reg (int regno, unsigned offset)
+{
+  rtx reg = gen_rtx_REG (SImode, regno);
+  rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+			   gen_int_mode (offset, Pmode));
+
+  rtx pattern = gen_rtx_SET (VOIDmode, reg, gen_frame_mem (Pmode, addr));
+  /*emit_insn (pattern);*/
+  rtx insn = emit_insn (pattern);
+  /* Tag epilogue unwind note.  */
+  add_reg_note (insn, REG_CFA_RESTORE, reg);
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
+/* Emit conditional trap for checking stack limit.  */
+static void
+nios2_emit_stack_limit_check (void)
+{
+  if (REG_P (stack_limit_rtx))
+    emit_insn (gen_ctrapsi4 (gen_rtx_LTU (VOIDmode, stack_pointer_rtx,
+					  stack_limit_rtx),
+			     stack_pointer_rtx, stack_limit_rtx, GEN_INT (3)));
+  else
+    error ("only register based stack limit is supported");
+}
+
+/* Temp regno used inside prologue/epilogue.  */
+#define TEMP_REG_NUM 8
+
+void
+nios2_expand_prologue (void)
+{
+  unsigned int regno;
+  int total_frame_size, save_offset;
+  int sp_offset; /* offset from base_reg to final stack value.  */
+  int fp_offset; /* offset from base_reg to final fp value.  */
+  rtx insn;
+
+  total_frame_size = nios2_compute_frame_layout ();
+
+  if (flag_stack_usage_info)
+    current_function_static_stack_size = total_frame_size;
+
+  /* Decrement the stack pointer.  */
+  if (!SMALL_INT (total_frame_size))
+    {
+      /* We need an intermediary point, this will point at the spill block.  */
+      insn = emit_insn
+	(gen_add3_insn (stack_pointer_rtx,
+			stack_pointer_rtx,
+			gen_int_mode (cfun->machine->save_regs_offset
+				      - total_frame_size, Pmode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      fp_offset = 0;
+      sp_offset = -cfun->machine->save_regs_offset;
+    }
+  else if (total_frame_size)
+    {
+      insn = emit_insn (gen_add3_insn (stack_pointer_rtx,
+				       stack_pointer_rtx,
+				       gen_int_mode (-total_frame_size,
+						     Pmode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      fp_offset = cfun->machine->save_regs_offset;
+      sp_offset = 0;
+    }
+  else
+    fp_offset = sp_offset = 0;
+
+  if (crtl->limit_stack)
+    nios2_emit_stack_limit_check ();
+
+  save_offset = fp_offset + cfun->machine->save_reg_size;
+
+  for (regno = LAST_GP_REG; regno > 0; regno--)
+    if (cfun->machine->save_mask & (1 << regno))
+      {
+	save_offset -= 4;
+	save_reg (regno, save_offset);
+      }
+
+  if (frame_pointer_needed)
+    {
+      insn = emit_insn (gen_add3_insn (hard_frame_pointer_rtx,
+				       stack_pointer_rtx,
+				       gen_int_mode (fp_offset, Pmode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+
+  if (sp_offset)
+    {
+      rtx sp_adjust
+	= gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+		       gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+				     gen_int_mode (sp_offset, Pmode)));
+      if (SMALL_INT (sp_offset))
+	insn = emit_insn (sp_adjust);
+      else
+	{
+	  rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM);
+	  emit_insn (gen_rtx_SET (VOIDmode, tmp,
+				  gen_int_mode (sp_offset, Pmode)));
+	  insn = emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
+					   tmp));
+	  /* Attach the sp_adjust as a note indicating what happened.  */
+	  REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+					      sp_adjust, REG_NOTES (insn));
+	}
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      if (crtl->limit_stack)
+	nios2_emit_stack_limit_check ();
+    }
+
+  /* Load the PIC register if needed.  */
+  if (crtl->uses_pic_offset_table)
+    nios2_load_pic_register ();
+
+  /* If we are profiling, make sure no instructions are scheduled before
+     the call to mcount.  */
+  if (crtl->profile)
+    emit_insn (gen_blockage ());
+}
+
+void
+nios2_expand_epilogue (bool sibcall_p)
+{
+  rtx insn, cfa_adj;
+  int total_frame_size;
+  int sp_adjust, save_offset;
+  unsigned int regno;
+
+  if (!sibcall_p && nios2_can_use_return_insn ())
+    {
+      emit_jump_insn (gen_return ());
+      return;
+    }
+
+  emit_insn (gen_blockage ());
+
+  total_frame_size = nios2_compute_frame_layout ();
+  if (frame_pointer_needed)
+    {
+      /* Recover the stack pointer.  */
+      insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
+      cfa_adj = plus_constant (Pmode, stack_pointer_rtx,
+			       (total_frame_size
+				- cfun->machine->save_regs_offset));
+      add_reg_note (insn, REG_CFA_DEF_CFA, cfa_adj);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      save_offset = 0;
+      sp_adjust = total_frame_size - cfun->machine->save_regs_offset;
+    }
+  else if (!SMALL_INT (total_frame_size))
+    {
+      rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM);
+      emit_move_insn (tmp,
+		      gen_int_mode (cfun->machine->save_regs_offset, Pmode));
+      insn = emit_insn (gen_add3_insn (stack_pointer_rtx,
+				       stack_pointer_rtx, tmp));
+      cfa_adj = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+			     plus_constant (Pmode, stack_pointer_rtx,
+					    cfun->machine->save_regs_offset));
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, cfa_adj);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      save_offset = 0;
+      sp_adjust = total_frame_size - cfun->machine->save_regs_offset;
+    }
+  else
+    {
+      save_offset = cfun->machine->save_regs_offset;
+      sp_adjust = total_frame_size;
+    }
+  
+  save_offset += cfun->machine->save_reg_size;
+
+  for (regno = LAST_GP_REG; regno > 0; regno--)
+    if (cfun->machine->save_mask & (1 << regno))
+      {
+	save_offset -= 4;
+	restore_reg (regno, save_offset);
+      }
+
+  if (sp_adjust)
+    {
+      insn = emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
+				       gen_int_mode (sp_adjust, Pmode)));
+      cfa_adj = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+			     plus_constant (Pmode, stack_pointer_rtx,
+					    sp_adjust));
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, cfa_adj);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+
+  /* Add in the __builtin_eh_return stack adjustment.  */
+  if (crtl->calls_eh_return)
+    emit_insn (gen_add3_insn (stack_pointer_rtx,
+			      stack_pointer_rtx,
+			      EH_RETURN_STACKADJ_RTX));
+
+  if (!sibcall_p)
+    emit_jump_insn (gen_simple_return ());
+}
+
+/* Implement RETURN_ADDR_RTX.  Note, we do not support moving
+   back to a previous frame.  */
+rtx
+nios2_get_return_address (int count)
+{
+  if (count != 0)
+    return const0_rtx;
+
+  return get_hard_reg_initial_val (Pmode, RA_REGNO);
+}
+
+/* Emit code to change the current function's return address to
+   ADDRESS.  SCRATCH is available as a scratch register, if needed.
+   ADDRESS and SCRATCH are both word-mode GPRs.  */
+void
+nios2_set_return_address (rtx address, rtx scratch)
+{
+  nios2_compute_frame_layout ();
+  if (cfun->machine->save_mask & (1 << RA_REGNO))
+    {
+      unsigned offset = cfun->machine->save_reg_size - 4;
+      rtx base;
+      
+      if (frame_pointer_needed)
+	base = hard_frame_pointer_rtx;
+      else
+	{
+	  base = stack_pointer_rtx;
+	  offset += cfun->machine->save_regs_offset;
+
+	  if (!SMALL_INT (offset))
+	    {
+	      emit_insn (gen_rtx_SET (VOIDmode, scratch,
+				      gen_int_mode (offset, Pmode)));
+	      emit_insn (gen_add3_insn (scratch, scratch, base));
+	      base = scratch;
+	      offset = 0;
+	    }
+	}
+      if (offset)
+	base = gen_rtx_PLUS (Pmode, base, gen_int_mode (offset, Pmode));
+      emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (Pmode, base), address));
+    }
+  else
+    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (Pmode, RA_REGNO), address));
+}
+
+
+/* Implement FUNCTION_PROFILER macro.  */
+void
+nios2_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
+{
+  fprintf (file, "\tmov\tr8, ra\n");
+  if (flag_pic)
+    {
+      fprintf (file, "\tnextpc\tr2\n");
+      fprintf (file, "\t1: movhi\tr3, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b)\n");
+      fprintf (file, "\taddi\tr3, r3, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)\n");
+      fprintf (file, "\tadd\tr2, r2, r3\n");
+      fprintf (file, "\tldw\tr2, %%call(_mcount)(r2)\n");
+      fprintf (file, "\tcallr\tr2\n");
+    }
+  else
+    fprintf (file, "\tcall\t_mcount\n");
+  fprintf (file, "\tmov\tra, r8\n");
+}
+
+/* Dump stack layout.  */
+static void
+nios2_dump_frame_layout (FILE *file)
+{
+  fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START);
+  fprintf (file, "\t%s total_size = %d\n", ASM_COMMENT_START,
+           cfun->machine->total_size);
+  fprintf (file, "\t%s var_size = %d\n", ASM_COMMENT_START,
+           cfun->machine->var_size);
+  fprintf (file, "\t%s args_size = %d\n", ASM_COMMENT_START,
+           cfun->machine->args_size);
+  fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START,
+           cfun->machine->save_reg_size);
+  fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START,
+           cfun->machine->initialized);
+  fprintf (file, "\t%s save_regs_offset = %d\n", ASM_COMMENT_START,
+           cfun->machine->save_regs_offset);
+  fprintf (file, "\t%s is_leaf = %d\n", ASM_COMMENT_START,
+           crtl->is_leaf);
+  fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START,
+           frame_pointer_needed);
+  fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START,
+           crtl->args.pretend_args_size);
+}
+
+/* Return true if REGNO should be saved in the prologue.  */
+static bool
+prologue_saved_reg_p (unsigned regno)
+{
+  gcc_assert (GP_REG_P (regno));
+  
+  if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
+    return true;
+
+  if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
+    return true;
+
+  if (regno == PIC_OFFSET_TABLE_REGNUM && crtl->uses_pic_offset_table)
+    return true;
+
+  if (regno == RA_REGNO && df_regs_ever_live_p (RA_REGNO))
+    return true;
+
+  return false;
+}
+
+/* Return the bytes needed to compute the frame pointer from the current
+   stack pointer.  */
+
+#define NIOS2_STACK_ALIGN(LOC)						\
+  (((LOC) + ((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1))		\
+   & ~((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1))
+
+static int
+nios2_compute_frame_layout (void)
+{
+  unsigned int regno;
+  unsigned int save_mask = 0;
+  int total_size;
+  int var_size;
+  int out_args_size;
+  int save_reg_size;
+
+  if (cfun->machine->initialized)
+    return cfun->machine->total_size;
+  
+  var_size = NIOS2_STACK_ALIGN (get_frame_size ());
+  out_args_size = NIOS2_STACK_ALIGN (crtl->outgoing_args_size);
+  total_size = var_size + out_args_size;
+
+  /* Calculate space needed for gp registers.  */
+  save_reg_size = 0;
+  for (regno = 0; regno <= LAST_GP_REG; regno++)
+    if (prologue_saved_reg_p (regno))
+      {
+	save_mask |= 1 << regno;
+	save_reg_size += 4;
+      }
+
+  /* If we call eh_return, we need to save the EH data registers.  */
+  if (crtl->calls_eh_return)
+    {
+      unsigned i;
+      unsigned r;
+      
+      for (i = 0; (r = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++)
+	if (!(save_mask & (1 << r)))
+	  {
+	    save_mask |= 1 << r;
+	    save_reg_size += 4;
+	  }
+    }
+
+  save_reg_size = NIOS2_STACK_ALIGN (save_reg_size);
+  total_size += save_reg_size;
+  total_size += NIOS2_STACK_ALIGN (crtl->args.pretend_args_size);
+
+  /* Save other computed information.  */
+  cfun->machine->save_mask = save_mask;
+  cfun->machine->total_size = total_size;
+  cfun->machine->var_size = var_size;
+  cfun->machine->args_size = out_args_size;
+  cfun->machine->save_reg_size = save_reg_size;
+  cfun->machine->initialized = reload_completed;
+  cfun->machine->save_regs_offset = out_args_size + var_size;
+
+  return total_size;
+}
+
+/* Implement TARGET_CAN_ELIMINATE.  */
+static bool
+nios2_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+  if (to == STACK_POINTER_REGNUM)
+    return !frame_pointer_needed;
+  return true;
+}
+
+/* Implement INITIAL_ELIMINATION_OFFSET macro.  */
+int
+nios2_initial_elimination_offset (int from, int to)
+{
+  int offset;
+
+  nios2_compute_frame_layout ();
+
+  /* Set OFFSET to the offset from the stack pointer.  */
+  switch (from)
+    {
+    case FRAME_POINTER_REGNUM:
+      offset = cfun->machine->args_size;
+      break;
+
+    case ARG_POINTER_REGNUM:
+      offset = cfun->machine->total_size;
+      offset -= crtl->args.pretend_args_size;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+    /* If we are asked for the frame pointer offset, then adjust OFFSET
+       by the offset from the frame pointer to the stack pointer.  */
+  if (to == HARD_FRAME_POINTER_REGNUM)
+    offset -= cfun->machine->save_regs_offset;
+
+  return offset;
+}
+
+/* Return nonzero if this function is known to have a null epilogue.
+   This allows the optimizer to omit jumps to jumps if no stack
+   was created.  */
+int
+nios2_can_use_return_insn (void)
+{
+  if (!reload_completed || crtl->profile)
+    return 0;
+
+  return nios2_compute_frame_layout () == 0;
+}
+
+
+/* Check and signal some warnings/errors on FPU insn options.  */
+static void
+nios2_custom_check_insns (void)
+{
+  unsigned int i, j;
+  bool errors = false;
+
+  for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+    if (N2FPU_ENABLED_P (i) && N2FPU_DOUBLE_P (i))
+      {
+	for (j = 0; j < ARRAY_SIZE (nios2_fpu_insn); j++)
+	  if (N2FPU_DOUBLE_REQUIRED_P (j) && ! N2FPU_ENABLED_P (j))
+	    {
+	      error ("switch %<-mcustom-%s%> is required for double precision "
+		     "floating point", N2FPU_NAME (j));
+	      errors = true;
+	    }
+	break;
+      }
+
+  /* Warn if the user has certain exotic operations that won't get used
+     without -funsafe-math-optimizations.  See expand_builtin () in
+     builtins.c.  */
+  if (!flag_unsafe_math_optimizations)
+    for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+      if (N2FPU_ENABLED_P (i) && N2FPU_UNSAFE_P (i))
+	warning (0, "switch %<-mcustom-%s%> has no effect unless "
+		 "-funsafe-math-optimizations is specified", N2FPU_NAME (i));
+
+  /* Warn if the user is trying to use -mcustom-fmins et. al, that won't
+     get used without -ffinite-math-only.  See fold_builtin_fmin_fmax ()
+     in builtins.c.  */
+  if (!flag_finite_math_only)
+    for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+      if (N2FPU_ENABLED_P (i) && N2FPU_FINITE_P (i))
+	warning (0, "switch %<-mcustom-%s%> has no effect unless "
+		 "-ffinite-math-only is specified", N2FPU_NAME (i));
+
+  if (errors || custom_code_conflict)
+    fatal_error ("conflicting use of -mcustom switches, target attributes, "
+		 "and/or __builtin_custom_ functions");
+}
+
+static void
+nios2_set_fpu_custom_code (enum n2fpu_code code, int n, bool override_p)
+{
+  if (override_p || N2FPU_N (code) == -1)
+    N2FPU_N (code) = n;
+  nios2_register_custom_code (n, CCS_FPU, (int) code);
+}
+
+static void
+nios2_handle_custom_fpu_cfg (const char *cfg, bool override_p)
+{
+  if (!strncmp (cfg, "60-1", 4))
+    {
+      nios2_set_fpu_custom_code (n2fpu_fmuls, 252, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fadds, 253, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fsubs, 254, override_p);
+      flag_single_precision_constant = 1;
+    }
+  else if (!strncmp (cfg, "60-2", 4))
+    {
+      nios2_set_fpu_custom_code (n2fpu_fmuls, 252, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fadds, 253, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fsubs, 254, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fdivs, 255, override_p);
+      flag_single_precision_constant = 1;
+    }
+  else if (!strncmp (cfg, "72-3", 4))
+    {
+      nios2_set_fpu_custom_code (n2fpu_floatus, 243, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fixsi, 244, override_p);
+      nios2_set_fpu_custom_code (n2fpu_floatis, 245, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fcmpgts, 246, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fcmples, 249, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fcmpeqs, 250, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fcmpnes, 251, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fmuls, 252, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fadds, 253, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fsubs, 254, override_p);
+      nios2_set_fpu_custom_code (n2fpu_fdivs, 255, override_p);
+      flag_single_precision_constant = 1;
+    }
+  else
+    warning (0, "ignoring unrecognized switch %<-mcustom-fpu-cfg%> value %<%s%>",
+	     cfg);
+
+  /* Guard against errors in the standard configurations.  */
+  nios2_custom_check_insns ();
+}
+
+/* Check individual FPU insn options, and register custom code.  */
+static void
+nios2_handle_custom_fpu_insn_option (int fpu_insn_index)
+{
+  int param = N2FPU_N (fpu_insn_index);
+
+  if (0 <= param && param <= 255)
+    nios2_register_custom_code (param, CCS_FPU, fpu_insn_index);
+
+  /* Valid values are 0-255, but also allow -1 so that the
+     -mno-custom-<opt> switches work.  */
+  else if (param != -1)
+    error ("switch %<-mcustom-%s%> value %d must be between 0 and 255",
+	   N2FPU_NAME (fpu_insn_index), param);
+}
+
+/* Implement TARGET_OPTION_OVERRIDE.  */
+static void
+nios2_option_override (void)
+{
+  unsigned int i;
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
+  /* Check for unsupported options.  */
+  if (flag_pic && !TARGET_LINUX_ABI)
+    error ("position-independent code requires the Linux ABI");
+
+  /* Function to allocate machine-dependent function status.  */
+  init_machine_status = &nios2_init_machine_status;
+
+  nios2_section_threshold
+    = (global_options_set.x_g_switch_value
+       ? g_switch_value : NIOS2_DEFAULT_GVALUE);
+
+  /* If we don't have mul, we don't have mulx either!  */
+  if (!TARGET_HAS_MUL && TARGET_HAS_MULX)
+    target_flags &= ~MASK_HAS_MULX;
+
+  /* Set up default handling for floating point custom instructions.
+
+     Putting things in this order means that the -mcustom-fpu-cfg=
+     switch will always be overridden by individual -mcustom-fadds=
+     switches, regardless of the order in which they were specified
+     on the command line.
+
+     This behavior of prioritization of individual -mcustom-<insn>=
+     options before the -mcustom-fpu-cfg= switch is maintained for
+     compatibility.  */
+  if (nios2_custom_fpu_cfg_string && *nios2_custom_fpu_cfg_string)
+    nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string, false);
+
+  /* Handle options for individual FPU insns.  */
+  for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+    nios2_handle_custom_fpu_insn_option (i);
+
+  nios2_custom_check_insns ();
+
+  /* Save the initial options in case the user does function specific
+     options.  */
+  target_option_default_node = target_option_current_node
+    = build_target_option_node (&global_options);
+}
+
+/* Allocate a chunk of memory for per-function machine-dependent data.  */
+static struct machine_function *
+nios2_init_machine_status (void)
+{
+  return ggc_alloc_cleared_machine_function ();
+}
+
+
+/* Return true if CST is a constant within range of movi/movui/movhi.  */
+static bool
+nios2_simple_const_p (const_rtx cst)
+{
+  HOST_WIDE_INT val = INTVAL (cst);
+  return (SMALL_INT (val) || SMALL_INT_UNSIGNED (val) || UPPER16_INT (val));
+}
+
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
+static bool
+nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
+		 int opno ATTRIBUTE_UNUSED,
+		 int *total, bool speed ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+      case CONST_INT:
+        if (INTVAL (x) == 0)
+          {
+            *total = COSTS_N_INSNS (0);
+            return true;
+          }
+        else if (nios2_simple_const_p (x))
+          {
+            *total = COSTS_N_INSNS (2);
+            return true;
+          }
+        else
+          {
+            *total = COSTS_N_INSNS (4);
+            return true;
+          }
+
+      case LABEL_REF:
+      case SYMBOL_REF:
+      case CONST:
+      case CONST_DOUBLE:
+        {
+          *total = COSTS_N_INSNS (4);
+          return true;
+        }
+
+      case AND:
+	{
+	  /* Recognize 'nor' insn pattern.  */
+	  if (GET_CODE (XEXP (x, 0)) == NOT
+	      && GET_CODE (XEXP (x, 1)) == NOT)
+	    {
+	      *total = COSTS_N_INSNS (1);
+	      return true;
+	    }
+	  return false;
+	}
+
+      case MULT:
+        {
+          *total = COSTS_N_INSNS (1);
+          return false;
+        }
+      case SIGN_EXTEND:
+        {
+          *total = COSTS_N_INSNS (3);
+          return false;
+        }
+      case ZERO_EXTEND:
+        {
+          *total = COSTS_N_INSNS (1);
+          return false;
+        }
+
+      default:
+        return false;
+    }
+}
+
+/* Implement TARGET_PREFERRED_RELOAD_CLASS.  */
+
+static reg_class_t
+nios2_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t regclass)
+{
+  return (regclass == NO_REGS ? GENERAL_REGS : regclass);
+}
+
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM.  */
+
+static bool
+nios2_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+  return nios2_legitimate_constant_p (mode, x) == false;
+}
+
+/* Emit a call to __tls_get_addr.  TI is the argument to this function.
+   RET is an RTX for the return value location.  The entire insn sequence
+   is returned.  */
+static GTY(()) rtx nios2_tls_symbol;
+
+static rtx
+nios2_call_tls_get_addr (rtx ti)
+{
+  rtx arg = gen_rtx_REG (Pmode, FIRST_ARG_REGNO);
+  rtx ret = gen_rtx_REG (Pmode, FIRST_RETVAL_REGNO);
+  rtx fn, insn;
+  
+  if (!nios2_tls_symbol)
+    nios2_tls_symbol = init_one_libfunc ("__tls_get_addr");
+
+  emit_insn (gen_rtx_SET (VOIDmode, arg, ti));
+  fn = gen_rtx_MEM (QImode, nios2_tls_symbol);
+  insn = emit_call_insn (gen_call_value (ret, fn, const0_rtx));
+  RTL_CONST_CALL_P (insn) = 1;
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), ret);
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg);
+
+  return ret;
+}
+
+static rtx
+nios2_unspec_address (rtx loc, rtx base_reg, int unspec)
+{
+  rtx unspec_offset =
+    gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc),
+					  unspec));
+  return gen_rtx_PLUS (Pmode, base_reg, unspec_offset);
+}
+
+static rtx
+nios2_got_address (rtx loc, int unspec)
+{
+  crtl->uses_pic_offset_table = 1;
+  return nios2_unspec_address (loc, pic_offset_table_rtx, unspec);
+}
+
+/* Generate the code to access LOC, a thread local SYMBOL_REF.  The
+   return value will be a valid address and move_operand (either a REG
+   or a LO_SUM).  */
+static rtx
+nios2_legitimize_tls_address (rtx loc)
+{
+  rtx tmp, mem, tp;
+  enum tls_model model = SYMBOL_REF_TLS_MODEL (loc);
+
+  switch (model)
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      tmp = gen_reg_rtx (Pmode);
+      emit_move_insn (tmp, nios2_got_address (loc, UNSPEC_ADD_TLS_GD));
+      return nios2_call_tls_get_addr (tmp);
+
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      tmp = gen_reg_rtx (Pmode);
+      emit_move_insn (tmp, nios2_got_address (loc, UNSPEC_ADD_TLS_LDM));
+      return nios2_unspec_address (loc, nios2_call_tls_get_addr (tmp),
+				   UNSPEC_ADD_TLS_LDO);
+
+    case TLS_MODEL_INITIAL_EXEC:
+      tmp = gen_reg_rtx (Pmode);
+      mem = gen_const_mem (Pmode, nios2_got_address (loc, UNSPEC_LOAD_TLS_IE));
+      emit_move_insn (tmp, mem);
+      tp = gen_rtx_REG (Pmode, TP_REGNO);
+      return gen_rtx_PLUS (Pmode, tp, tmp);
+
+    case TLS_MODEL_LOCAL_EXEC:
+      tp = gen_rtx_REG (Pmode, TP_REGNO);
+      return nios2_unspec_address (loc, tp, UNSPEC_ADD_TLS_LE);
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+int
+nios2_emit_move_sequence (rtx *operands, enum machine_mode mode)
+{
+  rtx to = operands[0];
+  rtx from = operands[1];
+
+  if (!register_operand (to, mode) && !reg_or_0_operand (from, mode))
+    {
+      gcc_assert (can_create_pseudo_p ());
+      from = copy_to_mode_reg (mode, from);
+    }
+
+  if (GET_CODE (from) == SYMBOL_REF || GET_CODE (from) == LABEL_REF
+      || GET_CODE (from) == CONST)
+    from = nios2_legitimize_constant_address (from);
+
+  operands[0] = to;
+  operands[1] = from;
+  return 0;
+}
+
+/* Divide Support
+
+   If -O3 is used, we want to output a table lookup for
+   divides between small numbers (both num and den >= 0
+   and < 0x10).  The overhead of this method in the worst
+   case is 40 bytes in the text section (10 insns) and
+   256 bytes in the data section.  Additional divides do
+   not incur additional penalties in the data section.
+
+   Code speed is improved for small divides by about 5x
+   when using this method in the worse case (~9 cycles
+   vs ~45).  And in the worst case divides not within the
+   table are penalized by about 10% (~5 cycles vs ~45).
+   However in the typical case the penalty is not as bad
+   because doing the long divide in only 45 cycles is
+   quite optimistic.
+
+   ??? would be nice to have some benchmarks other
+   than Dhrystone to back this up.
+
+   This bit of expansion is to create this instruction
+   sequence as rtl.
+        or      $8, $4, $5
+        slli    $9, $4, 4
+        cmpgeui $3, $8, 16
+        beq     $3, $0, .L3
+        or      $10, $9, $5
+        add     $12, $11, divide_table
+        ldbu    $2, 0($12)
+        br      .L1
+.L3:
+        call    slow_div
+.L1:
+#       continue here with result in $2
+
+   ??? Ideally I would like the libcall block to contain all
+   of this code, but I don't know how to do that.  What it
+   means is that if the divide can be eliminated, it may not
+   completely disappear.
+
+   ??? The __divsi3_table label should ideally be moved out
+   of this block and into a global.  If it is placed into the
+   sdata section we can save even more cycles by doing things
+   gp relative.  */
+void
+nios2_emit_expensive_div (rtx *operands, enum machine_mode mode)
+{
+  rtx or_result, shift_left_result;
+  rtx lookup_value;
+  rtx lab1, lab3;
+  rtx insns;
+  rtx libfunc;
+  rtx final_result;
+  rtx tmp;
+  rtx table;
+
+  /* It may look a little generic, but only SImode is supported for now.  */
+  gcc_assert (mode == SImode);
+  libfunc = optab_libfunc (sdiv_optab, SImode);
+
+  lab1 = gen_label_rtx ();
+  lab3 = gen_label_rtx ();
+
+  or_result = expand_simple_binop (SImode, IOR,
+                                   operands[1], operands[2],
+                                   0, 0, OPTAB_LIB_WIDEN);
+
+  emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0,
+                           GET_MODE (or_result), 0, lab3);
+  JUMP_LABEL (get_last_insn ()) = lab3;
+
+  shift_left_result = expand_simple_binop (SImode, ASHIFT,
+                                           operands[1], GEN_INT (4),
+                                           0, 0, OPTAB_LIB_WIDEN);
+
+  lookup_value = expand_simple_binop (SImode, IOR,
+                                      shift_left_result, operands[2],
+                                      0, 0, OPTAB_LIB_WIDEN);
+  table = gen_rtx_PLUS (SImode, lookup_value,
+			gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"));
+  convert_move (operands[0], gen_rtx_MEM (QImode, table), 1);
+
+  tmp = emit_jump_insn (gen_jump (lab1));
+  JUMP_LABEL (tmp) = lab1;
+  emit_barrier ();
+
+  emit_label (lab3);
+  LABEL_NUSES (lab3) = 1;
+
+  start_sequence ();
+  final_result = emit_library_call_value (libfunc, NULL_RTX,
+                                          LCT_CONST, SImode, 2,
+                                          operands[1], SImode,
+                                          operands[2], SImode);
+
+  insns = get_insns ();
+  end_sequence ();
+  emit_libcall_block (insns, operands[0], final_result,
+                      gen_rtx_DIV (SImode, operands[1], operands[2]));
+
+  emit_label (lab1);
+  LABEL_NUSES (lab1) = 1;
+}
+
+/* The function with address *ADDR is being called.  If the address
+   needs to be loaded from the GOT, emit the instruction to do so and
+   update *ADDR to point to the rtx for the loaded value.  */
+void
+nios2_adjust_call_address (rtx *call_op)
+{
+  rtx addr;
+  gcc_assert (MEM_P (*call_op));
+  addr = XEXP (*call_op, 0);
+  if (flag_pic && CONSTANT_P (addr))
+    {
+      rtx reg = gen_reg_rtx (Pmode);
+      emit_move_insn (reg, nios2_load_pic_address (addr, UNSPEC_PIC_CALL_SYM));
+      XEXP (*call_op, 0) = reg;
+    }
+}
+
+
+/* Branches and compares.  */
+
+/* Return in *ALT_CODE and *ALT_OP, an alternate equivalent constant
+   comparison, e.g. >= 1 into > 0.  */
+static void
+nios2_alternate_compare_const (enum rtx_code code, rtx op,
+			       enum rtx_code *alt_code, rtx *alt_op,
+			       enum machine_mode mode)
+{
+  HOST_WIDE_INT opval = INTVAL (op);
+  enum rtx_code scode = signed_condition (code);
+  bool dec_p = (scode == LT || scode == GE);
+
+  if (code == EQ || code == NE)
+    {
+      *alt_code = code;
+      *alt_op = op;
+      return;
+    }
+
+  *alt_op = (dec_p
+	     ? gen_int_mode (opval - 1, mode)
+	     : gen_int_mode (opval + 1, mode));
+
+  /* The required conversion between [>,>=] and [<,<=] is captured
+     by a reverse + swap of condition codes.  */
+  *alt_code = reverse_condition (swap_condition (code));
+
+  {
+    /* Test if the incremented/decremented value crosses the over/underflow
+       boundary.  Supposedly, such boundary cases should already be transformed
+       into always-true/false or EQ conditions, so use an assertion here.  */
+    unsigned HOST_WIDE_INT alt_opval = INTVAL (*alt_op);
+    if (code == scode)
+      alt_opval ^= (1 << (GET_MODE_BITSIZE (mode) - 1));
+    alt_opval &= GET_MODE_MASK (mode);
+    gcc_assert (dec_p ? alt_opval != GET_MODE_MASK (mode) : alt_opval != 0);
+  }
+}
+
+/* Return true if the constant comparison is supported by nios2.  */
+static bool
+nios2_valid_compare_const_p (enum rtx_code code, rtx op)
+{
+  switch (code)
+    {
+    case EQ: case NE: case GE: case LT:
+      return SMALL_INT (INTVAL (op));
+    case GEU: case LTU:
+      return SMALL_INT_UNSIGNED (INTVAL (op));
+    default:
+      return false;
+    }
+}
+
+/* Checks if the FPU comparison in *CMP, *OP1, and *OP2 can be supported in
+   the current configuration.  Perform modifications if MODIFY_P is true.
+   Returns true if FPU compare can be done.  */
+
+bool
+nios2_validate_fpu_compare (enum machine_mode mode, rtx *cmp, rtx *op1, rtx *op2,
+			    bool modify_p)
+{
+  bool rev_p = false;
+  enum rtx_code code = GET_CODE (*cmp);
+
+  if (!nios2_fpu_compare_enabled (code, mode))
+    {
+      code = swap_condition (code);
+      if (nios2_fpu_compare_enabled (code, mode))
+	rev_p = true;
+      else
+	return false;
+    }
+
+  if (modify_p)
+    {
+      if (rev_p)
+	{
+	  rtx tmp = *op1;
+	  *op1 = *op2;
+	  *op2 = tmp;
+	}
+      *op1 = force_reg (mode, *op1);
+      *op2 = force_reg (mode, *op2);
+      *cmp = gen_rtx_fmt_ee (code, mode, *op1, *op2);
+    }
+  return true;
+}
+
+/* Checks and modifies the comparison in *CMP, *OP1, and *OP2 into valid
+   nios2 supported form.  Returns true if success.  */
+bool
+nios2_validate_compare (enum machine_mode mode, rtx *cmp, rtx *op1, rtx *op2)
+{
+  enum rtx_code code = GET_CODE (*cmp);
+  enum rtx_code alt_code;
+  rtx alt_op2;
+
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+    return nios2_validate_fpu_compare (mode, cmp, op1, op2, true);
+
+  if (!reg_or_0_operand (*op2, mode))
+    {
+      /* Create alternate constant compare.  */
+      nios2_alternate_compare_const (code, *op2, &alt_code, &alt_op2, mode);
+
+      /* If alterate op2 is zero(0), we can use it directly, possibly
+	 swapping the compare code.  */
+      if (alt_op2 == const0_rtx)
+	{
+	  code = alt_code;
+	  *op2 = alt_op2;
+	  goto check_rebuild_cmp;
+	}
+
+      /* Check if either constant compare can be used.  */
+      if (nios2_valid_compare_const_p (code, *op2))
+	return true;
+      else if (nios2_valid_compare_const_p (alt_code, alt_op2))
+	{
+	  code = alt_code;
+	  *op2 = alt_op2;
+	  goto rebuild_cmp;
+	}
+
+      /* We have to force op2 into a register now.  Try to pick one
+	 with a lower cost.  */
+      if (! nios2_simple_const_p (*op2)
+	  && nios2_simple_const_p (alt_op2))
+	{
+	  code = alt_code;
+	  *op2 = alt_op2;
+	}
+      *op2 = force_reg (SImode, *op2);
+    }
+ check_rebuild_cmp:
+  if (code == GT || code == GTU || code == LE || code == LEU)
+    {
+      rtx t = *op1; *op1 = *op2; *op2 = t;
+      code = swap_condition (code);
+    }
+ rebuild_cmp:
+  *cmp = gen_rtx_fmt_ee (code, mode, *op1, *op2);
+  return true;
+}
+
+
+/* Addressing Modes.  */
+
+/* Implement TARGET_LEGITIMATE_CONSTANT_P.  */
+static bool
+nios2_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+  rtx base, offset;
+  split_const (x, &base, &offset);
+  return (GET_CODE (base) != SYMBOL_REF || !SYMBOL_REF_TLS_MODEL (base));
+}
+
+/* Return true if register REGNO is a valid base register.
+   STRICT_P is true if REG_OK_STRICT is in effect.  */
+
+bool
+nios2_regno_ok_for_base_p (int regno, bool strict_p)
+{
+  if (!HARD_REGISTER_NUM_P (regno))
+    {
+      if (!strict_p)
+	return true;
+
+      if (!reg_renumber)
+	return false;
+
+      regno = reg_renumber[regno];
+    }
+
+  /* The fake registers will be eliminated to either the stack or
+     hard frame pointer, both of which are usually valid base registers.
+     Reload deals with the cases where the eliminated form isn't valid.  */
+  return (GP_REG_P (regno)
+	  || regno == FRAME_POINTER_REGNUM
+	  || regno == ARG_POINTER_REGNUM);
+}
+
+/* Return true if the address expression formed by BASE + OFFSET is
+   valid.  */
+static bool
+nios2_valid_addr_expr_p (rtx base, rtx offset, bool strict_p)
+{
+  if (!strict_p && GET_CODE (base) == SUBREG)
+    base = SUBREG_REG (base);
+  return (REG_P (base)
+	  && nios2_regno_ok_for_base_p (REGNO (base), strict_p)
+	  && (offset == NULL_RTX
+	      || const_arith_operand (offset, Pmode)
+	      || nios2_unspec_reloc_p (offset)));
+}
+
+/* Implement TARGET_LEGITIMATE_ADDRESS_P.  */
+static bool
+nios2_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+			    rtx operand, bool strict_p)
+{
+  switch (GET_CODE (operand))
+    {
+      /* Direct.  */
+    case SYMBOL_REF:
+      if (SYMBOL_REF_TLS_MODEL (operand))
+	return false;
+      
+      if (nios2_symbol_ref_in_small_data_p (operand))
+	return true;
+
+      /* Else, fall through.  */
+    case LABEL_REF:
+    case CONST_INT:
+    case CONST:
+    case CONST_DOUBLE:
+      return false;
+
+      /* Register indirect.  */
+    case REG:
+      return nios2_regno_ok_for_base_p (REGNO (operand), strict_p);
+
+      /* Register indirect with displacement.  */
+    case PLUS:
+      {
+        rtx op0 = XEXP (operand, 0);
+        rtx op1 = XEXP (operand, 1);
+
+	return (nios2_valid_addr_expr_p (op0, op1, strict_p)
+		|| nios2_valid_addr_expr_p (op1, op0, strict_p));
+      }
+
+    default:
+      break;
+    }
+  return false;
+}
+
+/* Return true if SECTION is a small section name.  */
+static bool
+nios2_small_section_name_p (const char *section)
+{
+  return (strcmp (section, ".sbss") == 0
+	  || strncmp (section, ".sbss.", 6) == 0
+	  || strcmp (section, ".sdata") == 0
+	  || strncmp (section, ".sdata.", 7) == 0);
+}
+
+/* Return true if EXP should be placed in the small data section.  */
+static bool
+nios2_in_small_data_p (const_tree exp)
+{
+  /* We want to merge strings, so we never consider them small data.  */
+  if (TREE_CODE (exp) == STRING_CST)
+    return false;
+
+  if (TREE_CODE (exp) == VAR_DECL)
+    {
+      if (DECL_SECTION_NAME (exp))
+	{
+	  const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
+	  if (nios2_section_threshold > 0
+	      && nios2_small_section_name_p (section))
+	    return true;
+	}
+      else
+	{
+	  HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+
+	  /* If this is an incomplete type with size 0, then we can't put it
+	     in sdata because it might be too big when completed.  */
+	  if (size > 0
+	      && (unsigned HOST_WIDE_INT) size <= nios2_section_threshold)
+	    return true;
+	}
+    }
+
+  return false;
+}
+
+/* Return true if symbol is in small data section.  */
+
+bool
+nios2_symbol_ref_in_small_data_p (rtx sym)
+{
+  gcc_assert (GET_CODE (sym) == SYMBOL_REF);
+  return
+    /* GP-relative access is not available in PIC.  */
+    (!flag_pic
+     /* GP-relative access cannot be used for externally defined symbols,
+	because the compilation unit that defines the symbol may place it
+	in a section that cannot be reached from GP.  */
+     && !SYMBOL_REF_EXTERNAL_P (sym)
+     /* True if a symbol is both small and not weak.  */
+     && SYMBOL_REF_SMALL_P (sym)
+     && !(SYMBOL_REF_DECL (sym) && DECL_WEAK (SYMBOL_REF_DECL (sym)))
+     /* TLS variables are not accessed through the GP.  */
+     && SYMBOL_REF_TLS_MODEL (sym) == 0);
+
+}
+
+/* Implement TARGET_SECTION_TYPE_FLAGS.  */
+
+static unsigned int
+nios2_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags;
+
+  flags = default_section_type_flags (decl, name, reloc);
+
+  if (nios2_small_section_name_p (name))
+    flags |= SECTION_SMALL;
+
+  return flags;
+}
+
+
+/* Position independent code related.  */
+
+/* Emit code to load the PIC register.  */
+static void
+nios2_load_pic_register (void)
+{
+  rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM);
+
+  emit_insn (gen_load_got_register (pic_offset_table_rtx, tmp));
+  emit_insn (gen_add3_insn (pic_offset_table_rtx, pic_offset_table_rtx, tmp));
+}
+
+/* Generate a PIC address as a MEM rtx.  */
+static rtx
+nios2_load_pic_address (rtx sym, int unspec)
+{
+  rtx gotaddr = nios2_got_address (sym, unspec);
+  return gen_const_mem (Pmode, gotaddr);
+}
+
+/* Nonzero if the constant value X is a legitimate general operand
+   when generating PIC code.  It is given that flag_pic is on and
+   that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+bool
+nios2_legitimate_pic_operand_p (rtx x)
+{
+  return ! (GET_CODE (x) == SYMBOL_REF
+	    || GET_CODE (x) == LABEL_REF || GET_CODE (x) == CONST);
+}
+
+/* Return TRUE if X is a thread-local symbol.  */
+static bool
+nios2_tls_symbol_p (rtx x)
+{
+  return (TARGET_HAVE_TLS && GET_CODE (x) == SYMBOL_REF
+	  && SYMBOL_REF_TLS_MODEL (x) != 0);
+}
+
+/* Legitimize addresses that are CONSTANT_P expressions.  */
+static rtx
+nios2_legitimize_constant_address (rtx addr)
+{
+  rtx base, offset;
+  split_const (addr, &base, &offset);
+
+  if (nios2_tls_symbol_p (base))
+    base = nios2_legitimize_tls_address (base);
+  else if (flag_pic)
+    base = nios2_load_pic_address (base, UNSPEC_PIC_SYM);
+  else
+    return addr;
+
+  if (offset != const0_rtx)
+    {
+      gcc_assert (can_create_pseudo_p ());
+      return gen_rtx_PLUS (Pmode, force_reg (Pmode, base),
+			   (CONST_INT_P (offset)
+			    ? (SMALL_INT (INTVAL (offset))
+			       ? offset : force_reg (Pmode, offset))
+			    : offset));
+    }
+  return base;
+}
+
+/* Implement TARGET_LEGITIMIZE_ADDRESS.  */
+static rtx
+nios2_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+			  enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  if (CONSTANT_P (x))
+    return nios2_legitimize_constant_address (x);
+
+  /* For the TLS LE (Local Exec) model, the compiler may try to
+     combine constant offsets with unspec relocs, creating address RTXs
+     looking like this:
+     (plus:SI (reg:SI 23 r23)
+              (const:SI
+                (plus:SI
+                  (unspec:SI [(symbol_ref:SI ("var"))] UNSPEC_ADD_TLS_LE)
+                  (const_int 48 [0x30]))))
+
+     This usually happens when 'var' is a thread-local struct variable,
+     and access of a field in var causes the addend.
+
+     We typically want this combining, so transform the above into this
+     form, which is allowed:
+     (plus:SI (reg:SI 23 r23)
+              (const:SI
+                (unspec:SI
+                  [(const:SI
+                     (plus:SI (symbol_ref:SI ("var"))
+                              (const_int 48 [0x30])))] UNSPEC_ADD_TLS_LE)))
+
+     Which will be output as '%tls_le(var+48)(r23)' in assembly.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && GET_CODE (XEXP (x, 1)) == CONST)
+    {
+      rtx unspec, offset, reg = XEXP (x, 0);
+      split_const (XEXP (x, 1), &unspec, &offset);
+      if (GET_CODE (unspec) == UNSPEC
+	  && nios2_unspec_reloc_name (XINT (unspec, 1)) != NULL
+	  && offset != const0_rtx)
+	{
+	  unspec = copy_rtx (unspec);
+	  XVECEXP (unspec, 0, 0)
+	    = plus_constant (Pmode, XVECEXP (unspec, 0, 0), INTVAL (offset));
+	  x = gen_rtx_PLUS (Pmode, reg, gen_rtx_CONST (Pmode, unspec));
+	}
+    }
+
+  return x;
+}
+
+
+/* Output assembly language related definitions.  */
+
+/* Print the operand OP to file stream FILE modified by LETTER.
+   LETTER can be one of:
+
+     i: print "i" if OP is an immediate, except 0
+     o: print "io" if OP is volatile
+     z: for const0_rtx print $0 instead of 0
+     H: for %hiadj
+     L: for %lo
+     U: for upper half of 32 bit value
+     D: for the upper 32-bits of a 64-bit double value
+     R: prints reverse condition.
+*/
+static void
+nios2_print_operand (FILE *file, rtx op, int letter)
+{
+
+  switch (letter)
+    {
+    case 'i':
+      if (CONSTANT_P (op) && op != const0_rtx)
+        fprintf (file, "i");
+      return;
+
+    case 'o':
+      if (GET_CODE (op) == MEM
+	  && ((MEM_VOLATILE_P (op) && TARGET_BYPASS_CACHE_VOLATILE)
+	      || TARGET_BYPASS_CACHE))
+        fprintf (file, "io");
+      return;
+
+    default:
+      break;
+    }
+
+  if (comparison_operator (op, VOIDmode))
+    {
+      enum rtx_code cond = GET_CODE (op);
+      if (letter == 0)
+	{
+	  fprintf (file, "%s", GET_RTX_NAME (cond));
+	  return;
+	}
+      if (letter == 'R')
+	{
+	  fprintf (file, "%s", GET_RTX_NAME (reverse_condition (cond)));
+	  return;
+	}
+    }
+
+  switch (GET_CODE (op))
+    {
+    case REG:
+      if (letter == 0 || letter == 'z')
+        {
+          fprintf (file, "%s", reg_names[REGNO (op)]);
+          return;
+        }
+      else if (letter == 'D')
+        {
+          fprintf (file, "%s", reg_names[REGNO (op)+1]);
+          return;
+        }
+      break;
+
+    case CONST_INT:
+      if (INTVAL (op) == 0 && letter == 'z')
+        {
+          fprintf (file, "zero");
+          return;
+        }
+
+      if (letter == 'U')
+        {
+          HOST_WIDE_INT val = INTVAL (op);
+	  val = (val >> 16) & 0xFFFF;
+	  output_addr_const (file, gen_int_mode (val, SImode));
+          return;
+        }
+      /* Else, fall through.  */
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_DOUBLE:
+      if (letter == 0 || letter == 'z')
+        {
+          output_addr_const (file, op);
+          return;
+        }
+      else if (letter == 'H')
+        {
+          fprintf (file, "%%hiadj(");
+          output_addr_const (file, op);
+          fprintf (file, ")");
+          return;
+        }
+      else if (letter == 'L')
+        {
+          fprintf (file, "%%lo(");
+          output_addr_const (file, op);
+          fprintf (file, ")");
+          return;
+        }
+      break;
+
+    case SUBREG:
+    case MEM:
+      if (letter == 0)
+        {
+          output_address (op);
+          return;
+        }
+      break;
+
+    case CODE_LABEL:
+      if (letter == 0)
+        {
+          output_addr_const (file, op);
+          return;
+        }
+      break;
+
+    default:
+      break;
+    }
+
+  output_operand_lossage ("Unsupported operand for code '%c'", letter);
+  gcc_unreachable ();
+}
+
+/* Return true if this is a GP-relative accessible reference.  */
+static bool
+gprel_constant_p (rtx op)
+{
+  if (GET_CODE (op) == SYMBOL_REF
+      && nios2_symbol_ref_in_small_data_p (op))
+    return true;
+  else if (GET_CODE (op) == CONST
+           && GET_CODE (XEXP (op, 0)) == PLUS)
+    return gprel_constant_p (XEXP (XEXP (op, 0), 0));
+
+  return false;
+}
+
+/* Return the name string for a supported unspec reloc offset.  */
+static const char *
+nios2_unspec_reloc_name (int unspec)
+{
+  switch (unspec)
+    {
+    case UNSPEC_PIC_SYM:
+      return "got";
+    case UNSPEC_PIC_CALL_SYM:
+      return "call";
+    case UNSPEC_LOAD_TLS_IE:
+      return "tls_ie";
+    case UNSPEC_ADD_TLS_LE:
+      return "tls_le";
+    case UNSPEC_ADD_TLS_GD:
+      return "tls_gd";
+    case UNSPEC_ADD_TLS_LDM:
+      return "tls_ldm";
+    case UNSPEC_ADD_TLS_LDO:
+      return "tls_ldo";
+    default:
+      return NULL;
+    }
+}
+
+/* Return true for conforming unspec relocations.  Also used in
+   constraints.md and predicates.md.  */
+bool
+nios2_unspec_reloc_p (rtx op)
+{
+  return (GET_CODE (op) == CONST
+	  && GET_CODE (XEXP (op, 0)) == UNSPEC
+	  && nios2_unspec_reloc_name (XINT (XEXP (op, 0), 1)) != NULL);
+}
+
+/* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA.  */
+static bool
+nios2_output_addr_const_extra (FILE *file, rtx op)
+{
+  const char *name;
+  gcc_assert (GET_CODE (op) == UNSPEC);
+
+  /* Support for printing out const unspec relocations.  */
+  name = nios2_unspec_reloc_name (XINT (op, 1));
+  if (name)
+    {
+      fprintf (file, "%%%s(", name);
+      output_addr_const (file, XVECEXP (op, 0, 0));
+      fprintf (file, ")");
+      return true;
+    }
+  return false;
+}
+
+/* Implement TARGET_PRINT_OPERAND_ADDRESS.  */
+static void
+nios2_print_operand_address (FILE *file, rtx op)
+{
+  switch (GET_CODE (op))
+    {
+    case CONST:
+    case CONST_INT:
+    case LABEL_REF:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+      if (gprel_constant_p (op))
+        {
+          fprintf (file, "%%gprel(");
+          output_addr_const (file, op);
+          fprintf (file, ")(%s)", reg_names[GP_REGNO]);
+          return;
+        }
+
+      break;
+
+    case PLUS:
+      {
+        rtx op0 = XEXP (op, 0);
+        rtx op1 = XEXP (op, 1);
+
+        if (REG_P (op0) && CONSTANT_P (op1))
+          {
+            output_addr_const (file, op1);
+            fprintf (file, "(%s)", reg_names[REGNO (op0)]);
+            return;
+          }
+        else if (REG_P (op1) && CONSTANT_P (op0))
+          {
+            output_addr_const (file, op0);
+            fprintf (file, "(%s)", reg_names[REGNO (op1)]);
+            return;
+          }
+      }
+      break;
+
+    case REG:
+      fprintf (file, "0(%s)", reg_names[REGNO (op)]);
+      return;
+
+    case MEM:
+      {
+        rtx base = XEXP (op, 0);
+        nios2_print_operand_address (file, base);
+        return;
+      }
+    default:
+      break;
+    }
+
+  fprintf (stderr, "Missing way to print address\n");
+  debug_rtx (op);
+  gcc_unreachable ();
+}
+
+/* Implement TARGET_ASM_OUTPUT_DWARF_DTPREL.  */
+static void
+nios2_output_dwarf_dtprel (FILE *file, int size, rtx x)
+{
+  gcc_assert (size == 4);
+  fprintf (file, "\t.4byte\t%%tls_ldo(");
+  output_addr_const (file, x);
+  fprintf (file, ")");
+}
+
+/* Implement TARGET_ASM_FUNCTION_PROLOGUE.  */
+static void
+nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+  if (flag_verbose_asm || flag_debug_asm)
+    {
+      nios2_compute_frame_layout ();
+      nios2_dump_frame_layout (file);
+    }
+}
+
+/* Emit assembly of custom FPU instructions.  */
+const char *
+nios2_fpu_insn_asm (enum n2fpu_code code)
+{
+  static char buf[256];
+  const char *op1, *op2, *op3;
+  int ln = 256, n = 0;
+  
+  int N = N2FPU_N (code);
+  int num_operands = N2FPU (code).num_operands;
+  const char *insn_name = N2FPU_NAME (code);
+  tree ftype = nios2_ftype (N2FPU_FTCODE (code));
+  enum machine_mode dst_mode = TYPE_MODE (TREE_TYPE (ftype));
+  enum machine_mode src_mode = TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (ftype)));
+
+  /* Prepare X register for DF input operands.  */
+  if (GET_MODE_SIZE (src_mode) == 8 && num_operands == 3)
+    n = snprintf (buf, ln, "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t",
+		  N2FPU_N (n2fpu_fwrx));
+
+  if (src_mode == SFmode)
+    {
+      if (dst_mode == VOIDmode)
+	{
+	  /* The fwry case.  */
+	  op1 = op3 = "zero";
+	  op2 = "%0";
+	  num_operands -= 1;
+	}
+      else
+	{
+	  op1 = "%0"; op2 = "%1";
+	  op3 = (num_operands == 2 ? "zero" : "%2");
+	}
+    }
+  else if (src_mode == DFmode)
+    {
+      if (dst_mode == VOIDmode)
+	{
+	  /* The fwrx case.  */
+	  op1 = "zero";
+	  op2 = "%0";
+	  op3 = "%D0";
+	  num_operands -= 1;
+	}
+      else
+	{
+	  op1 = (dst_mode == DFmode ? "%D0" : "%0");
+	  op2 = (num_operands == 2 ? "%1" : "%2");
+	  op3 = (num_operands == 2 ? "%D1" : "%D2");
+	}
+    }
+  else if (src_mode == VOIDmode)
+    {
+      /* frdxlo, frdxhi, frdy cases.  */
+      gcc_assert (dst_mode == SFmode);
+      op1 = "%0";
+      op2 = op3 = "zero";
+    }
+  else if (src_mode == SImode)
+    {
+      /* Conversion operators.  */
+      gcc_assert (num_operands == 2);
+      op1 = (dst_mode == DFmode ? "%D0" : "%0");
+      op2 = "%1";
+      op3 = "zero";
+    }
+  else
+    gcc_unreachable ();
+
+  /* Main instruction string.  */
+  n += snprintf (buf + n, ln - n, "custom\t%d, %s, %s, %s # %s %%0%s%s",
+		 N, op1, op2, op3, insn_name,
+		 (num_operands >= 2 ? ", %1" : ""),
+		 (num_operands == 3 ? ", %2" : ""));
+
+  /* Extraction of Y register for DF results.  */
+  if (dst_mode == DFmode)
+    snprintf (buf + n, ln - n, "\n\tcustom\t%d, %%0, zero, zero # frdy %%0",
+	      N2FPU_N (n2fpu_frdy));
+  return buf;
+}
+
+
+
+/* Function argument related.  */
+
+/* Define where to put the arguments to a function.  Value is zero to
+   push the argument on the stack, or a hard register in which to
+   store the argument.
+
+   MODE is the argument's machine mode.
+   TYPE is the data type of the argument (as a tree).
+   This is null for libcalls where that information may
+   not be available.
+   CUM is a variable of type CUMULATIVE_ARGS which gives info about
+   the preceding args and about the function being called.
+   NAMED is nonzero if this argument is a named parameter
+   (otherwise it is an extra parameter matching an ellipsis).  */
+
+static rtx
+nios2_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
+		    const_tree type ATTRIBUTE_UNUSED,
+		    bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 
+  rtx return_rtx = NULL_RTX;
+
+  if (cum->regs_used < NUM_ARG_REGS)
+    return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used);
+
+  return return_rtx;
+}
+
+/* Return number of bytes, at the beginning of the argument, that must be
+   put in registers.  0 is the argument is entirely in registers or entirely
+   in memory.  */
+
+static int
+nios2_arg_partial_bytes (cumulative_args_t cum_v,
+                         enum machine_mode mode, tree type ATTRIBUTE_UNUSED,
+                         bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 
+  HOST_WIDE_INT param_size;
+
+  if (mode == BLKmode)
+    {
+      param_size = int_size_in_bytes (type);
+      gcc_assert (param_size >= 0);
+    }
+  else
+    param_size = GET_MODE_SIZE (mode);
+
+  /* Convert to words (round up).  */
+  param_size = (UNITS_PER_WORD - 1 + param_size) / UNITS_PER_WORD;
+
+  if (cum->regs_used < NUM_ARG_REGS
+      && cum->regs_used + param_size > NUM_ARG_REGS)
+    return (NUM_ARG_REGS - cum->regs_used) * UNITS_PER_WORD;
+
+  return 0;
+}
+
+/* Update the data in CUM to advance over an argument of mode MODE
+   and data type TYPE; TYPE is null for libcalls where that information
+   may not be available.  */
+
+static void
+nios2_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+			    const_tree type ATTRIBUTE_UNUSED,
+			    bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 
+  HOST_WIDE_INT param_size;
+
+  if (mode == BLKmode)
+    {
+      param_size = int_size_in_bytes (type);
+      gcc_assert (param_size >= 0);
+    }
+  else
+    param_size = GET_MODE_SIZE (mode);
+
+  /* Convert to words (round up).  */
+  param_size = (UNITS_PER_WORD - 1 + param_size) / UNITS_PER_WORD;
+
+  if (cum->regs_used + param_size > NUM_ARG_REGS)
+    cum->regs_used = NUM_ARG_REGS;
+  else
+    cum->regs_used += param_size;
+}
+
+enum direction
+nios2_function_arg_padding (enum machine_mode mode, const_tree type)
+{
+  /* On little-endian targets, the first byte of every stack argument
+     is passed in the first byte of the stack slot.  */
+  if (!BYTES_BIG_ENDIAN)
+    return upward;
+
+  /* Otherwise, integral types are padded downward: the last byte of a
+     stack argument is passed in the last byte of the stack slot.  */
+  if (type != 0
+      ? INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)
+      : GET_MODE_CLASS (mode) == MODE_INT)
+    return downward;
+
+  /* Arguments smaller than a stack slot are padded downward.  */
+  if (mode != BLKmode)
+    return (GET_MODE_BITSIZE (mode) >= PARM_BOUNDARY) ? upward : downward;
+  else
+    return ((int_size_in_bytes (type) >= (PARM_BOUNDARY / BITS_PER_UNIT))
+            ? upward : downward);
+}
+
+enum direction
+nios2_block_reg_padding (enum machine_mode mode, tree type,
+                         int first ATTRIBUTE_UNUSED)
+{
+  return nios2_function_arg_padding (mode, type);
+}
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+   FNADDR is an RTX for the address of the function's pure code.
+   CXT is an RTX for the static chain value for the function.
+   On Nios II, we handle this by a library call.  */
+static void
+nios2_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx ctx_reg = force_reg (Pmode, cxt);
+  rtx addr = force_reg (Pmode, XEXP (m_tramp, 0));
+
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
+		     LCT_NORMAL, VOIDmode, 3, addr, Pmode, fnaddr, Pmode,
+		     ctx_reg, Pmode);
+}
+
+/* Implement TARGET_FUNCTION_VALUE.  */
+static rtx
+nios2_function_value (const_tree ret_type, const_tree fn ATTRIBUTE_UNUSED,
+		      bool outgoing ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (TYPE_MODE (ret_type), FIRST_RETVAL_REGNO);
+}
+
+/* Implement TARGET_LIBCALL_VALUE.  */
+static rtx
+nios2_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (mode, FIRST_RETVAL_REGNO);
+}
+
+/* Implement TARGET_FUNCTION_VALUE_REGNO_P.  */
+static bool
+nios2_function_value_regno_p (const unsigned int regno)
+{
+  return (regno == FIRST_RETVAL_REGNO);
+}
+
+/* Implement TARGET_RETURN_IN_MEMORY.  */
+static bool
+nios2_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  return (int_size_in_bytes (type) > (2 * UNITS_PER_WORD)
+	  || int_size_in_bytes (type) == -1);
+}
+
+/* TODO: It may be possible to eliminate the copyback and implement
+   own va_arg type.  */
+static void
+nios2_setup_incoming_varargs (cumulative_args_t cum_v,
+                              enum machine_mode mode, tree type,
+                              int *pretend_size, int second_time)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 
+  CUMULATIVE_ARGS local_cum;
+  cumulative_args_t local_cum_v = pack_cumulative_args (&local_cum);
+  int regs_to_push;
+  int pret_size;
+
+  local_cum = *cum;
+  nios2_function_arg_advance (local_cum_v, mode, type, 1);
+
+  regs_to_push = NUM_ARG_REGS - local_cum.regs_used;
+
+  if (!second_time && regs_to_push > 0)
+    {
+      rtx ptr = virtual_incoming_args_rtx;
+      rtx mem = gen_rtx_MEM (BLKmode, ptr);
+      emit_insn (gen_blockage ());
+      move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem,
+			   regs_to_push);
+      emit_insn (gen_blockage ());
+    }
+
+  pret_size = regs_to_push * UNITS_PER_WORD;
+  if (pret_size)
+    *pretend_size = pret_size;
+}
+
+
+
+/* Init FPU builtins.  */
+static void
+nios2_init_fpu_builtins (int start_code)
+{
+  tree fndecl;
+  char builtin_name[64] = "__builtin_custom_";
+  unsigned int i, n = strlen ("__builtin_custom_");
+
+  for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+    {
+      snprintf (builtin_name + n, sizeof (builtin_name) - n,
+		"%s", N2FPU_NAME (i));
+      fndecl =
+	add_builtin_function (builtin_name, nios2_ftype (N2FPU_FTCODE (i)),
+			      start_code + i, BUILT_IN_MD, NULL, NULL_TREE);
+      nios2_register_builtin_fndecl (start_code + i, fndecl);
+    }
+}
+
+/* Helper function for expanding FPU builtins.  */
+static rtx
+nios2_expand_fpu_builtin (tree exp, unsigned int code, rtx target)
+{
+  struct expand_operand ops[MAX_RECOG_OPERANDS];
+  enum insn_code icode = N2FPU_ICODE (code);
+  int nargs, argno, opno = 0;
+  int num_operands = N2FPU (code).num_operands;
+  enum machine_mode dst_mode = TYPE_MODE (TREE_TYPE (exp));
+  bool has_target_p = (dst_mode != VOIDmode);
+
+  if (N2FPU_N (code) < 0)
+    fatal_error ("Cannot call %<__builtin_custom_%s%> without specifying switch"
+		 " %<-mcustom-%s%>", N2FPU_NAME (code), N2FPU_NAME (code));
+  if (has_target_p)
+    create_output_operand (&ops[opno++], target, dst_mode);
+  else
+    /* Subtract away the count of the VOID return, mainly for fwrx/fwry.   */
+    num_operands -= 1;
+  nargs = call_expr_nargs (exp);
+  for (argno = 0; argno < nargs; argno++)
+    {
+      tree arg = CALL_EXPR_ARG (exp, argno);
+      create_input_operand (&ops[opno++], expand_normal (arg),
+			    TYPE_MODE (TREE_TYPE (arg)));
+    }
+  if (!maybe_expand_insn (icode, num_operands, ops))
+    {
+      error ("invalid argument to built-in function");
+      return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx;
+    }
+  return has_target_p ? ops[0].value : const0_rtx;
+}
+
+/* Nios II has custom instruction built-in functions of the forms:
+   __builtin_custom_n
+   __builtin_custom_nX
+   __builtin_custom_nXX
+   __builtin_custom_Xn
+   __builtin_custom_XnX
+   __builtin_custom_XnXX
+
+   where each X could be either 'i' (int), 'f' (float), or 'p' (void*).
+   Therefore with 0-1 return values, and 0-2 arguments, we have a
+   total of (3 + 1) * (1 + 3 + 9) == 52 custom builtin functions.
+*/
+#define NUM_CUSTOM_BUILTINS ((3 + 1) * (1 + 3 + 9))
+static char custom_builtin_name[NUM_CUSTOM_BUILTINS][5];
+
+static void
+nios2_init_custom_builtins (int start_code)
+{
+  tree builtin_ftype, ret_type, fndecl;
+  char builtin_name[32] = "__builtin_custom_";
+  int n = strlen ("__builtin_custom_");
+  int builtin_code = 0;
+  int lhs, rhs1, rhs2;
+
+  struct { tree type; const char *c; } op[4];
+  /* z */ op[0].c = "";  op[0].type = NULL_TREE;
+  /* f */ op[1].c = "f"; op[1].type = float_type_node;
+  /* i */ op[2].c = "i"; op[2].type = integer_type_node;
+  /* p */ op[3].c = "p"; op[3].type = ptr_type_node;
+
+  /* We enumerate through the possible operand types to create all the
+     __builtin_custom_XnXX function tree types.  Note that these may slightly
+     overlap with the function types created for other fixed builtins.  */
+
+  for (lhs = 0; lhs < 4; lhs++)
+    for (rhs1 = 0; rhs1 < 4; rhs1++)
+      for (rhs2 = 0; rhs2 < 4; rhs2++)
+	{
+	  if (rhs1 == 0 && rhs2 != 0)
+	    continue;
+	  ret_type = (op[lhs].type ? op[lhs].type : void_type_node);
+	  builtin_ftype
+	    = build_function_type_list (ret_type, integer_type_node,
+					op[rhs1].type, op[rhs2].type,
+					NULL_TREE);
+	  snprintf (builtin_name + n, 32 - n, "%sn%s%s",
+		    op[lhs].c, op[rhs1].c, op[rhs2].c);
+	  /* Save copy of parameter string into custom_builtin_name[].  */
+	  strncpy (custom_builtin_name[builtin_code], builtin_name + n, 5);
+	  fndecl =
+	    add_builtin_function (builtin_name, builtin_ftype,
+				  start_code + builtin_code,
+				  BUILT_IN_MD, NULL, NULL_TREE);
+	  nios2_register_builtin_fndecl (start_code + builtin_code, fndecl);
+	  builtin_code += 1;
+	}
+}
+
+/* Helper function for expanding custom builtins.  */
+static rtx
+nios2_expand_custom_builtin (tree exp, unsigned int index, rtx target)
+{
+  bool has_target_p = (TREE_TYPE (exp) != void_type_node);
+  enum machine_mode tmode = VOIDmode;
+  int nargs, argno;
+  rtx value, insn, unspec_args[3];
+  tree arg;
+
+  /* XnXX form.  */
+  if (has_target_p)
+    {
+      tmode = TYPE_MODE (TREE_TYPE (exp));
+      if (!target || GET_MODE (target) != tmode
+	  || !REG_P (target))
+	target = gen_reg_rtx (tmode);
+    }
+
+  nargs = call_expr_nargs (exp);
+  for (argno = 0; argno < nargs; argno++)
+    {
+      arg = CALL_EXPR_ARG (exp, argno);
+      value = expand_normal (arg);
+      unspec_args[argno] = value;
+      if (argno == 0)
+	{
+	  if (!custom_insn_opcode (value, VOIDmode))
+	    error ("custom instruction opcode must be compile time "
+		   "constant in the range 0-255 for __builtin_custom_%s",
+		   custom_builtin_name[index]);
+	}
+      else
+	/* For other arguments, force into a register.  */
+	unspec_args[argno] = force_reg (TYPE_MODE (TREE_TYPE (arg)),
+					unspec_args[argno]);
+    }
+  /* Fill remaining unspec operands with zero.  */
+  for (; argno < 3; argno++)
+    unspec_args[argno] = const0_rtx;
+
+  insn = (has_target_p
+	  ? gen_rtx_SET (VOIDmode, target,
+			 gen_rtx_UNSPEC_VOLATILE (tmode,
+						  gen_rtvec_v (3, unspec_args),
+						  UNSPECV_CUSTOM_XNXX))
+	  : gen_rtx_UNSPEC_VOLATILE (VOIDmode, gen_rtvec_v (3, unspec_args),
+				     UNSPECV_CUSTOM_NXX));
+  emit_insn (insn);
+  return has_target_p ? target : const0_rtx;
+}
+
+
+
+
+/* Main definition of built-in functions.  Nios II has a small number of fixed
+   builtins, plus a large number of FPU insn builtins, and builtins for
+   generating custom instructions.  */
+
+struct nios2_builtin_desc
+{
+  enum insn_code icode;
+  enum nios2_ftcode ftype;
+  const char *name;
+};
+
+#define N2_BUILTINS					\
+  N2_BUILTIN_DEF (sync,   N2_FTYPE_VOID_VOID)		\
+  N2_BUILTIN_DEF (ldbio,  N2_FTYPE_SI_CVPTR)		\
+  N2_BUILTIN_DEF (ldbuio, N2_FTYPE_UI_CVPTR)		\
+  N2_BUILTIN_DEF (ldhio,  N2_FTYPE_SI_CVPTR)		\
+  N2_BUILTIN_DEF (ldhuio, N2_FTYPE_UI_CVPTR)		\
+  N2_BUILTIN_DEF (ldwio,  N2_FTYPE_SI_CVPTR)		\
+  N2_BUILTIN_DEF (stbio,  N2_FTYPE_VOID_VPTR_SI)	\
+  N2_BUILTIN_DEF (sthio,  N2_FTYPE_VOID_VPTR_SI)	\
+  N2_BUILTIN_DEF (stwio,  N2_FTYPE_VOID_VPTR_SI)	\
+  N2_BUILTIN_DEF (rdctl,  N2_FTYPE_SI_SI)		\
+  N2_BUILTIN_DEF (wrctl,  N2_FTYPE_VOID_SI_SI)
+
+enum nios2_builtin_code {
+#define N2_BUILTIN_DEF(name, ftype) NIOS2_BUILTIN_ ## name,
+  N2_BUILTINS
+#undef N2_BUILTIN_DEF
+  NUM_FIXED_NIOS2_BUILTINS
+};
+
+static const struct nios2_builtin_desc nios2_builtins[] = {
+#define N2_BUILTIN_DEF(name, ftype)			\
+  { CODE_FOR_ ## name, ftype, "__builtin_" #name },
+  N2_BUILTINS
+#undef N2_BUILTIN_DEF
+};
+
+/* Start/ends of FPU/custom insn builtin index ranges.  */
+static unsigned int nios2_fpu_builtin_base;
+static unsigned int nios2_custom_builtin_base;
+static unsigned int nios2_custom_builtin_end;
+
+/* Implement TARGET_INIT_BUILTINS.  */
+static void
+nios2_init_builtins (void)
+{
+  unsigned int i;
+
+  /* Initialize fixed builtins.  */
+  for (i = 0; i < ARRAY_SIZE (nios2_builtins); i++)
+    {
+      const struct nios2_builtin_desc *d = &nios2_builtins[i];
+      tree fndecl =
+	add_builtin_function (d->name, nios2_ftype (d->ftype), i,
+			      BUILT_IN_MD, NULL, NULL);
+      nios2_register_builtin_fndecl (i, fndecl);
+    }
+
+  /* Initialize FPU builtins.  */
+  nios2_fpu_builtin_base = ARRAY_SIZE (nios2_builtins);
+  nios2_init_fpu_builtins (nios2_fpu_builtin_base);
+
+  /* Initialize custom insn builtins.  */
+  nios2_custom_builtin_base
+    = nios2_fpu_builtin_base + ARRAY_SIZE (nios2_fpu_insn);
+  nios2_custom_builtin_end
+    = nios2_custom_builtin_base + NUM_CUSTOM_BUILTINS;
+  nios2_init_custom_builtins (nios2_custom_builtin_base);
+}
+
+/* Array of fndecls for TARGET_BUILTIN_DECL.  */
+#define NIOS2_NUM_BUILTINS \
+  (ARRAY_SIZE (nios2_builtins) + ARRAY_SIZE (nios2_fpu_insn) + NUM_CUSTOM_BUILTINS)
+static GTY(()) tree nios2_builtin_decls[NIOS2_NUM_BUILTINS];
+
+static void
+nios2_register_builtin_fndecl (unsigned code, tree fndecl)
+{
+  nios2_builtin_decls[code] = fndecl;
+}
+
+/* Implement TARGET_BUILTIN_DECL.  */
+static tree
+nios2_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  gcc_assert (nios2_custom_builtin_end == ARRAY_SIZE (nios2_builtin_decls));
+
+  if (code >= nios2_custom_builtin_end)
+    return error_mark_node;
+
+  if (code >= nios2_fpu_builtin_base
+      && code < nios2_custom_builtin_base
+      && ! N2FPU_ENABLED_P (code - nios2_fpu_builtin_base))
+    return error_mark_node;
+
+  return nios2_builtin_decls[code];
+}
+
+
+/* Low-level built-in expand routine.  */
+static rtx
+nios2_expand_builtin_insn (const struct nios2_builtin_desc *d, int n,
+			   struct expand_operand *ops, bool has_target_p)
+{
+  if (maybe_expand_insn (d->icode, n, ops))
+    return has_target_p ? ops[0].value : const0_rtx;
+  else
+    {
+      error ("invalid argument to built-in function %s", d->name);
+      return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx;	  
+    } 
+}
+
+/* Expand ldio/stio form load-store instruction builtins.  */
+static rtx
+nios2_expand_ldstio_builtin (tree exp, rtx target,
+			     const struct nios2_builtin_desc *d)
+{
+  bool has_target_p;
+  rtx addr, mem, val;
+  struct expand_operand ops[MAX_RECOG_OPERANDS];
+  enum machine_mode mode = insn_data[d->icode].operand[0].mode;
+
+  addr = expand_normal (CALL_EXPR_ARG (exp, 0));
+  mem = gen_rtx_MEM (mode, addr);
+
+  if (insn_data[d->icode].operand[0].allows_mem)
+    {
+      /* stxio.  */
+      val = expand_normal (CALL_EXPR_ARG (exp, 1));
+      if (CONST_INT_P (val))
+	val = force_reg (mode, gen_int_mode (INTVAL (val), mode));
+      val = simplify_gen_subreg (mode, val, GET_MODE (val), 0);
+      create_output_operand (&ops[0], mem, mode);
+      create_input_operand (&ops[1], val, mode);
+      has_target_p = false;
+    }
+  else
+    {
+      /* ldxio.  */
+      create_output_operand (&ops[0], target, mode);
+      create_input_operand (&ops[1], mem, mode);
+      has_target_p = true;
+    }
+  return nios2_expand_builtin_insn (d, 2, ops, has_target_p);
+}
+
+/* Expand rdctl/wrctl builtins.  */
+static rtx
+nios2_expand_rdwrctl_builtin (tree exp, rtx target,
+			     const struct nios2_builtin_desc *d)
+{
+  bool has_target_p = (insn_data[d->icode].operand[0].predicate
+		       == register_operand);
+  rtx ctlcode = expand_normal (CALL_EXPR_ARG (exp, 0));
+  struct expand_operand ops[MAX_RECOG_OPERANDS];
+  if (!rdwrctl_operand (ctlcode, VOIDmode))
+    {
+      error ("Control register number must be in range 0-31 for %s",
+	     d->name);
+      return has_target_p ? gen_reg_rtx (SImode) : const0_rtx;
+    }
+  if (has_target_p)
+    {
+      create_output_operand (&ops[0], target, SImode);
+      create_integer_operand (&ops[1], INTVAL (ctlcode));
+    }
+  else
+    {
+      rtx val = expand_normal (CALL_EXPR_ARG (exp, 1));
+      create_integer_operand (&ops[0], INTVAL (ctlcode));
+      create_input_operand (&ops[1], val, SImode);
+    }
+  return nios2_expand_builtin_insn (d, 2, ops, has_target_p);
+}
+
+/* Implement TARGET_EXPAND_BUILTIN.  Expand an expression EXP that calls
+   a built-in function, with result going to TARGET if that's convenient
+   (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
+
+static rtx
+nios2_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+                      enum machine_mode mode ATTRIBUTE_UNUSED,
+		      int ignore ATTRIBUTE_UNUSED)
+{
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+
+  if (fcode < nios2_fpu_builtin_base)
+    {
+      const struct nios2_builtin_desc *d = &nios2_builtins[fcode];
+
+      switch (fcode)
+	{
+	case NIOS2_BUILTIN_sync:
+	  emit_insn (gen_sync ());
+	  return const0_rtx;
+
+	case NIOS2_BUILTIN_ldbio:
+	case NIOS2_BUILTIN_ldbuio:
+	case NIOS2_BUILTIN_ldhio:
+	case NIOS2_BUILTIN_ldhuio:
+	case NIOS2_BUILTIN_ldwio:
+	case NIOS2_BUILTIN_stbio:
+	case NIOS2_BUILTIN_sthio:
+	case NIOS2_BUILTIN_stwio:
+	  return nios2_expand_ldstio_builtin (exp, target, d);
+
+	case NIOS2_BUILTIN_rdctl:
+	case NIOS2_BUILTIN_wrctl:
+	  return nios2_expand_rdwrctl_builtin (exp, target, d);
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  else if (fcode < nios2_custom_builtin_base)
+    /* FPU builtin range.  */
+    return nios2_expand_fpu_builtin (exp, fcode - nios2_fpu_builtin_base,
+				     target);
+  else if (fcode < nios2_custom_builtin_end)
+    /* Custom insn builtin range.  */
+    return nios2_expand_custom_builtin (exp, fcode - nios2_custom_builtin_base,
+					target);
+  else
+    gcc_unreachable ();
+}
+
+/* Implement TARGET_INIT_LIBFUNCS.  */
+static void
+nios2_init_libfuncs (void)
+{
+  /* For Linux, we have access to kernel support for atomic operations.  */
+  if (TARGET_LINUX_ABI)
+    init_sync_libfuncs (UNITS_PER_WORD);
+}
+
+
+
+/* Register a custom code use, and signal error if a conflict was found.  */
+static void
+nios2_register_custom_code (unsigned int N, enum nios2_ccs_code status,
+			    int index)
+{
+  gcc_assert (N <= 255);
+
+  if (status == CCS_FPU)
+    {
+      if (custom_code_status[N] == CCS_FPU && index != custom_code_index[N])
+	{
+	  custom_code_conflict = true;
+	  error ("switch %<-mcustom-%s%> conflicts with switch %<-mcustom-%s%>",
+		 N2FPU_NAME (custom_code_index[N]), N2FPU_NAME (index));
+	}
+      else if (custom_code_status[N] == CCS_BUILTIN_CALL)
+	{
+	  custom_code_conflict = true;
+	  error ("call to %<__builtin_custom_%s%> conflicts with switch "
+		 "%<-mcustom-%s%>", custom_builtin_name[custom_code_index[N]],
+		 N2FPU_NAME (index));
+	}
+    }
+  else if (status == CCS_BUILTIN_CALL)
+    {
+      if (custom_code_status[N] == CCS_FPU)
+	{
+	  custom_code_conflict = true;
+	  error ("call to %<__builtin_custom_%s%> conflicts with switch "
+		 "%<-mcustom-%s%>", custom_builtin_name[index],
+		 N2FPU_NAME (custom_code_index[N]));
+	}
+      else
+	{
+	  /* Note that code conflicts between different __builtin_custom_xnxx
+	     calls are not checked.  */
+	}
+    }
+  else
+    gcc_unreachable ();
+
+  custom_code_status[N] = status;
+  custom_code_index[N] = index;
+}
+
+/* Mark a custom code as not in use.  */
+static void
+nios2_deregister_custom_code (unsigned int N)
+{
+  if (N <= 255)
+    {
+      custom_code_status[N] = CCS_UNUSED;
+      custom_code_index[N] = 0;
+    }
+}
+
+/* Target attributes can affect per-function option state, so we need to
+   save/restore the custom code tracking info using the
+   TARGET_OPTION_SAVE/TARGET_OPTION_RESTORE hooks.  */
+
+static void
+nios2_option_save (struct cl_target_option *ptr,
+		   struct gcc_options *opts ATTRIBUTE_UNUSED)
+{
+  unsigned int i;
+  for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+    ptr->saved_fpu_custom_code[i] = N2FPU_N (i);
+  memcpy (ptr->saved_custom_code_status, custom_code_status,
+	  sizeof (custom_code_status));
+  memcpy (ptr->saved_custom_code_index, custom_code_index,
+	  sizeof (custom_code_index));
+}
+
+static void
+nios2_option_restore (struct gcc_options *opts ATTRIBUTE_UNUSED,
+		      struct cl_target_option *ptr)
+{
+  unsigned int i;
+  for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+    N2FPU_N (i) = ptr->saved_fpu_custom_code[i];
+  memcpy (custom_code_status, ptr->saved_custom_code_status,
+	  sizeof (custom_code_status));
+  memcpy (custom_code_index, ptr->saved_custom_code_index,
+	  sizeof (custom_code_index));
+}
+
+/* Inner function to process the attribute((target(...))), take an argument and
+   set the current options from the argument.  If we have a list, recursively
+   go over the list.  */
+
+static bool
+nios2_valid_target_attribute_rec (tree args)
+{
+  if (TREE_CODE (args) == TREE_LIST)
+    {
+      bool ret = true;
+      for (; args; args = TREE_CHAIN (args))
+	if (TREE_VALUE (args)
+	    && !nios2_valid_target_attribute_rec (TREE_VALUE (args)))
+	  ret = false;
+      return ret;
+    }
+  else if (TREE_CODE (args) == STRING_CST)
+    {
+      char *argstr = ASTRDUP (TREE_STRING_POINTER (args));
+      while (argstr && *argstr != '\0')
+	{
+	  bool no_opt = false, end_p = false;
+	  char *eq = NULL, *p;
+	  while (ISSPACE (*argstr))
+	    argstr++;
+	  p = argstr;
+	  while (*p != '\0' && *p != ',')
+	    {
+	      if (!eq && *p == '=')
+		eq = p;
+	      ++p;
+	    }
+	  if (*p == '\0')
+	    end_p = true;
+	  else
+	    *p = '\0';
+	  if (eq) *eq = '\0';
+
+	  if (!strncmp (argstr, "no-", 3))
+	    {
+	      no_opt = true;
+	      argstr += 3;
+	    }
+	  if (!strncmp (argstr, "custom-fpu-cfg", 14))
+	    {
+	      if (no_opt)
+		{
+		  error ("custom-fpu-cfg option does not support %<no-%>");
+		  return false;
+		}
+	      if (!eq)
+		{
+		  error ("custom-fpu-cfg option requires configuration"
+			 " argument");
+		  return false;
+		}
+	      /* Increment and skip whitespace.  */
+	      while (ISSPACE (*(++eq))) ;
+	      nios2_handle_custom_fpu_cfg (eq, true);
+	    }
+	  else if (!strncmp (argstr, "custom-", 7))
+	    {
+	      int code = -1;
+	      unsigned int i;
+	      for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
+		if (!strncmp (argstr + 7, N2FPU_NAME (i),
+			      strlen (N2FPU_NAME (i))))
+		  {
+		    /* Found insn.  */
+		    code = i;
+		    break;
+		  }
+	      if (code >= 0)
+		{
+		  if (no_opt)
+		    {
+		      if (eq)
+			{
+			  error ("%<no-custom-%s%> does not accept arguments",
+				 N2FPU_NAME (code));
+			  return false;
+			}
+		      /* Disable option by setting to -1.  */
+		      nios2_deregister_custom_code (N2FPU_N (code));
+		      N2FPU_N (code) = -1;
+		    }
+		  else
+		    {
+		      char *t;
+		      if (eq)
+			while (ISSPACE (*(++eq))) ;
+		      if (!eq || eq == p)
+			{
+			  error ("%<custom-%s=%> requires argument",
+				 N2FPU_NAME (code));
+			  return false;
+			}
+		      for (t = eq; t != p; ++t)
+			{
+			  if (ISSPACE (*t))
+			    continue;
+			  if (!ISDIGIT (*t))
+			    {			 
+			      error ("`custom-%s=' argument requires "
+				     "numeric digits", N2FPU_NAME (code));
+			      return false;
+			    }
+			}
+		      /* Set option to argument.  */
+		      N2FPU_N (code) = atoi (eq);
+		      nios2_handle_custom_fpu_insn_option (code);
+		    }
+		}
+	      else
+		{
+		  error ("%<custom-%s=%> is not recognised as FPU instruction",
+			 argstr + 7);
+		  return false;
+		}		
+	    }
+	  else
+	    {
+	      error ("%<%s%> is unknown", argstr);
+	      return false;
+	    }
+
+	  if (end_p)
+	    break;
+	  else
+	    argstr = p + 1;
+	}
+      return true;
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Return a TARGET_OPTION_NODE tree of the target options listed or NULL.  */
+
+static tree
+nios2_valid_target_attribute_tree (tree args)
+{
+  if (!nios2_valid_target_attribute_rec (args))
+    return NULL_TREE;
+  nios2_custom_check_insns ();
+  return build_target_option_node (&global_options);
+}
+
+/* Hook to validate attribute((target("string"))).  */
+
+static bool
+nios2_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
+				tree args, int ARG_UNUSED (flags))
+{
+  struct cl_target_option cur_target;
+  bool ret = true;
+  tree old_optimize = build_optimization_node (&global_options);
+  tree new_target, new_optimize;
+  tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  /* If the function changed the optimization levels as well as setting target
+     options, start with the optimizations specified.  */
+  if (func_optimize && func_optimize != old_optimize)
+    cl_optimization_restore (&global_options,
+			     TREE_OPTIMIZATION (func_optimize));
+
+  /* The target attributes may also change some optimization flags, so update
+     the optimization options if necessary.  */
+  cl_target_option_save (&cur_target, &global_options);
+  new_target = nios2_valid_target_attribute_tree (args);
+  new_optimize = build_optimization_node (&global_options);
+
+  if (!new_target)
+    ret = false;
+
+  else if (fndecl)
+    {
+      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
+
+      if (old_optimize != new_optimize)
+	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+    }
+
+  cl_target_option_restore (&global_options, &cur_target);
+
+  if (old_optimize != new_optimize)
+    cl_optimization_restore (&global_options,
+			     TREE_OPTIMIZATION (old_optimize));
+  return ret;
+}
+
+/* Remember the last target of nios2_set_current_function.  */
+static GTY(()) tree nios2_previous_fndecl;
+
+/* Establish appropriate back-end context for processing the function
+   FNDECL.  The argument might be NULL to indicate processing at top
+   level, outside of any function scope.  */
+static void
+nios2_set_current_function (tree fndecl)
+{
+  tree old_tree = (nios2_previous_fndecl
+		   ? DECL_FUNCTION_SPECIFIC_TARGET (nios2_previous_fndecl)
+		   : NULL_TREE);
+
+  tree new_tree = (fndecl
+		   ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl)
+		   : NULL_TREE);
+
+  if (fndecl && fndecl != nios2_previous_fndecl)
+    {
+      nios2_previous_fndecl = fndecl;
+      if (old_tree == new_tree)
+	;
+
+      else if (new_tree)
+	{
+	  cl_target_option_restore (&global_options,
+				    TREE_TARGET_OPTION (new_tree));
+	  target_reinit ();
+	}
+
+      else if (old_tree)
+	{
+	  struct cl_target_option *def
+	    = TREE_TARGET_OPTION (target_option_current_node);
+
+	  cl_target_option_restore (&global_options, def);
+	  target_reinit ();
+	}
+    }
+}
+
+/* Hook to validate the current #pragma GCC target and set the FPU custom
+   code option state.  If ARGS is NULL, then POP_TARGET is used to reset
+   the options.  */
+static bool
+nios2_pragma_target_parse (tree args, tree pop_target)
+{
+  tree cur_tree;
+  if (! args)
+    {
+      cur_tree = ((pop_target)
+		  ? pop_target
+		  : target_option_default_node);
+      cl_target_option_restore (&global_options,
+				TREE_TARGET_OPTION (cur_tree));
+    }
+  else
+    {
+      cur_tree = nios2_valid_target_attribute_tree (args);
+      if (!cur_tree)
+	return false;
+    }
+
+  target_option_current_node = cur_tree;
+  return true;
+}
+
+/* Implement TARGET_MERGE_DECL_ATTRIBUTES.
+   We are just using this hook to add some additional error checking to
+   the default behavior.  GCC does not provide a target hook for merging
+   the target options, and only correctly handles merging empty vs non-empty
+   option data; see merge_decls() in c-decl.c.
+   So here we require either that at least one of the decls has empty
+   target options, or that the target options/data be identical.  */
+static tree
+nios2_merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  tree oldopts = lookup_attribute ("target", DECL_ATTRIBUTES (olddecl));
+  tree newopts = lookup_attribute ("target", DECL_ATTRIBUTES (newdecl));
+  if (newopts && oldopts && newopts != oldopts)
+    {
+      tree oldtree = DECL_FUNCTION_SPECIFIC_TARGET (olddecl);
+      tree newtree = DECL_FUNCTION_SPECIFIC_TARGET (newdecl);
+      if (oldtree && newtree && oldtree != newtree)
+	{
+	  struct cl_target_option *olddata = TREE_TARGET_OPTION (oldtree);
+	  struct cl_target_option *newdata = TREE_TARGET_OPTION (newtree);
+	  if (olddata != newdata
+	      && memcmp (olddata, newdata, sizeof (struct cl_target_option)))
+	    error ("%qE redeclared with conflicting %qs attributes",
+		   DECL_NAME (newdecl), "target");
+	}
+    }
+  return merge_attributes (DECL_ATTRIBUTES (olddecl),
+			   DECL_ATTRIBUTES (newdecl));
+}
+
+#include "gt-nios2.h"
Index: gcc/config/nios2/t-nios2
===================================================================
--- gcc/config/nios2/t-nios2	(revision 0)
+++ gcc/config/nios2/t-nios2	(revision 0)
@@ -0,0 +1,27 @@ 
+# Target Makefile Fragment for Altera Nios II.
+# Copyright (C) 2013 Free Software Foundation, Inc.
+# Contributed by Altera and Mentor Graphics, Inc.
+#
+# 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/>.
+
+# MULTILIB_OPTIONS = mno-hw-mul/mhw-mulx mcustom-fpu-cfg=60-1/mcustom-fpu-cfg=60-2
+# MULTILIB_DIRNAMES = nomul mulx fpu-60-1 fpu-60-2
+# MULTILIB_EXCEPTIONS = 
+
+# MULTILIB_OPTIONS += EL/EB
+# MULTILIB_DIRNAMES += le be
+# MULTILIB_MATCHES += EL=mel EB=meb
Index: gcc/config/nios2/nios2.opt
===================================================================
--- gcc/config/nios2/nios2.opt	(revision 0)
+++ gcc/config/nios2/nios2.opt	(revision 0)
@@ -0,0 +1,527 @@ 
+; Options for the Altera Nios II port of the compiler.
+; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+; Contributed by Altera and Mentor Graphics, Inc.
+;
+; 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/nios2/nios2-opts.h
+
+TargetSave
+int saved_fpu_custom_code[n2fpu_code_num]
+
+TargetSave
+enum nios2_ccs_code saved_custom_code_status[256]
+
+TargetSave
+int saved_custom_code_index[256]
+
+mhw-div
+Target Report Mask(HAS_DIV)
+Enable DIV, DIVU
+
+mhw-mul
+Target Report Mask(HAS_MUL)
+Enable MUL instructions
+
+mhw-mulx
+Target Report Mask(HAS_MULX)
+Enable MULX instructions, assume fast shifter
+
+mfast-sw-div
+Target Report Mask(FAST_SW_DIV)
+Use table based fast divide (default at -O3)
+
+mbypass-cache
+Target Report Mask(BYPASS_CACHE)
+All memory accesses use I/O load/store instructions
+
+mno-cache-volatile
+Target Report RejectNegative Mask(BYPASS_CACHE_VOLATILE)
+Volatile memory accesses use I/O load/store instructions
+
+mcache-volatile
+Target Report RejectNegative Undocumented InverseMask(BYPASS_CACHE_VOLATILE)
+Volatile memory accesses do not use I/O load/store instructions
+
+meb
+Target Report RejectNegative Mask(BIG_ENDIAN)
+Use big-endian byte order
+
+mel
+Target Report RejectNegative InverseMask(BIG_ENDIAN)
+Use little-endian byte order
+
+mcustom-fpu-cfg=
+Target RejectNegative Joined Var(nios2_custom_fpu_cfg_string)
+Floating point custom instruction configuration name
+
+mno-custom-ftruncds
+Target Report RejectNegative Var(nios2_custom_ftruncds, -1)
+Do not use the ftruncds custom instruction
+
+mcustom-ftruncds=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_ftruncds) Init(-1)
+Integer id (N) of ftruncds custom instruction
+
+mno-custom-fextsd
+Target Report RejectNegative Var(nios2_custom_fextsd, -1)
+Do not use the fextsd custom instruction
+
+mcustom-fextsd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fextsd) Init(-1)
+Integer id (N) of fextsd custom instruction
+
+mno-custom-fixdu
+Target Report RejectNegative Var(nios2_custom_fixdu, -1)
+Do not use the fixdu custom instruction
+
+mcustom-fixdu=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fixdu) Init(-1)
+Integer id (N) of fixdu custom instruction
+
+mno-custom-fixdi
+Target Report RejectNegative Var(nios2_custom_fixdi, -1)
+Do not use the fixdi custom instruction
+
+mcustom-fixdi=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fixdi) Init(-1)
+Integer id (N) of fixdi custom instruction
+
+mno-custom-fixsu
+Target Report RejectNegative Var(nios2_custom_fixsu, -1)
+Do not use the fixsu custom instruction
+
+mcustom-fixsu=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fixsu) Init(-1)
+Integer id (N) of fixsu custom instruction
+
+mno-custom-fixsi
+Target Report RejectNegative Var(nios2_custom_fixsi, -1)
+Do not use the fixsi custom instruction
+
+mcustom-fixsi=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fixsi) Init(-1)
+Integer id (N) of fixsi custom instruction
+
+mno-custom-floatud
+Target Report RejectNegative Var(nios2_custom_floatud, -1)
+Do not use the floatud custom instruction
+
+mcustom-floatud=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_floatud) Init(-1)
+Integer id (N) of floatud custom instruction
+
+mno-custom-floatid
+Target Report RejectNegative Var(nios2_custom_floatid, -1)
+Do not use the floatid custom instruction
+
+mcustom-floatid=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_floatid) Init(-1)
+Integer id (N) of floatid custom instruction
+
+mno-custom-floatus
+Target Report RejectNegative Var(nios2_custom_floatus, -1)
+Do not use the floatus custom instruction
+
+mcustom-floatus=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_floatus) Init(-1)
+Integer id (N) of floatus custom instruction
+
+mno-custom-floatis
+Target Report RejectNegative Var(nios2_custom_floatis, -1)
+Do not use the floatis custom instruction
+
+mcustom-floatis=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_floatis) Init(-1)
+Integer id (N) of floatis custom instruction
+
+mno-custom-fcmpned
+Target Report RejectNegative Var(nios2_custom_fcmpned, -1)
+Do not use the fcmpned custom instruction
+
+mcustom-fcmpned=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpned) Init(-1)
+Integer id (N) of fcmpned custom instruction
+
+mno-custom-fcmpeqd
+Target Report RejectNegative Var(nios2_custom_fcmpeqd, -1)
+Do not use the fcmpeqd custom instruction
+
+mcustom-fcmpeqd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpeqd) Init(-1)
+Integer id (N) of fcmpeqd custom instruction
+
+mno-custom-fcmpged
+Target Report RejectNegative Var(nios2_custom_fcmpged, -1)
+Do not use the fcmpged custom instruction
+
+mcustom-fcmpged=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpged) Init(-1)
+Integer id (N) of fcmpged custom instruction
+
+mno-custom-fcmpgtd
+Target Report RejectNegative Var(nios2_custom_fcmpgtd, -1)
+Do not use the fcmpgtd custom instruction
+
+mcustom-fcmpgtd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpgtd) Init(-1)
+Integer id (N) of fcmpgtd custom instruction
+
+mno-custom-fcmpled
+Target Report RejectNegative Var(nios2_custom_fcmpled, -1)
+Do not use the fcmpled custom instruction
+
+mcustom-fcmpled=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpled) Init(-1)
+Integer id (N) of fcmpled custom instruction
+
+mno-custom-fcmpltd
+Target Report RejectNegative Var(nios2_custom_fcmpltd, -1)
+Do not use the fcmpltd custom instruction
+
+mcustom-fcmpltd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpltd) Init(-1)
+Integer id (N) of fcmpltd custom instruction
+
+mno-custom-flogd
+Target Report RejectNegative Var(nios2_custom_flogd, -1)
+Do not use the flogd custom instruction
+
+mcustom-flogd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_flogd) Init(-1)
+Integer id (N) of flogd custom instruction
+
+mno-custom-fexpd
+Target Report RejectNegative Var(nios2_custom_fexpd, -1)
+Do not use the fexpd custom instruction
+
+mcustom-fexpd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fexpd) Init(-1)
+Integer id (N) of fexpd custom instruction
+
+mno-custom-fatand
+Target Report RejectNegative Var(nios2_custom_fatand, -1)
+Do not use the fatand custom instruction
+
+mcustom-fatand=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fatand) Init(-1)
+Integer id (N) of fatand custom instruction
+
+mno-custom-ftand
+Target Report RejectNegative Var(nios2_custom_ftand, -1)
+Do not use the ftand custom instruction
+
+mcustom-ftand=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_ftand) Init(-1)
+Integer id (N) of ftand custom instruction
+
+mno-custom-fsind
+Target Report RejectNegative Var(nios2_custom_fsind, -1)
+Do not use the fsind custom instruction
+
+mcustom-fsind=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fsind) Init(-1)
+Integer id (N) of fsind custom instruction
+
+mno-custom-fcosd
+Target Report RejectNegative Var(nios2_custom_fcosd, -1)
+Do not use the fcosd custom instruction
+
+mcustom-fcosd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcosd) Init(-1)
+Integer id (N) of fcosd custom instruction
+
+mno-custom-fsqrtd
+Target Report RejectNegative Var(nios2_custom_fsqrtd, -1)
+Do not use the fsqrtd custom instruction
+
+mcustom-fsqrtd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fsqrtd) Init(-1)
+Integer id (N) of fsqrtd custom instruction
+
+mno-custom-fabsd
+Target Report RejectNegative Var(nios2_custom_fabsd, -1)
+Do not use the fabsd custom instruction
+
+mcustom-fabsd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fabsd) Init(-1)
+Integer id (N) of fabsd custom instruction
+
+mno-custom-fnegd
+Target Report RejectNegative Var(nios2_custom_fnegd, -1)
+Do not use the fnegd custom instruction
+
+mcustom-fnegd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fnegd) Init(-1)
+Integer id (N) of fnegd custom instruction
+
+mno-custom-fmaxd
+Target Report RejectNegative Var(nios2_custom_fmaxd, -1)
+Do not use the fmaxd custom instruction
+
+mcustom-fmaxd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fmaxd) Init(-1)
+Integer id (N) of fmaxd custom instruction
+
+mno-custom-fmind
+Target Report RejectNegative Var(nios2_custom_fmind, -1)
+Do not use the fmind custom instruction
+
+mcustom-fmind=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fmind) Init(-1)
+Integer id (N) of fmind custom instruction
+
+mno-custom-fdivd
+Target Report RejectNegative Var(nios2_custom_fdivd, -1)
+Do not use the fdivd custom instruction
+
+mcustom-fdivd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fdivd) Init(-1)
+Integer id (N) of fdivd custom instruction
+
+mno-custom-fmuld
+Target Report RejectNegative Var(nios2_custom_fmuld, -1)
+Do not use the fmuld custom instruction
+
+mcustom-fmuld=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fmuld) Init(-1)
+Integer id (N) of fmuld custom instruction
+
+mno-custom-fsubd
+Target Report RejectNegative Var(nios2_custom_fsubd, -1)
+Do not use the fsubd custom instruction
+
+mcustom-fsubd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fsubd) Init(-1)
+Integer id (N) of fsubd custom instruction
+
+mno-custom-faddd
+Target Report RejectNegative Var(nios2_custom_faddd, -1)
+Do not use the faddd custom instruction
+
+mcustom-faddd=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_faddd) Init(-1)
+Integer id (N) of faddd custom instruction
+
+mno-custom-fcmpnes
+Target Report RejectNegative Var(nios2_custom_fcmpnes, -1)
+Do not use the fcmpnes custom instruction
+
+mcustom-fcmpnes=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpnes) Init(-1)
+Integer id (N) of fcmpnes custom instruction
+
+mno-custom-fcmpeqs
+Target Report RejectNegative Var(nios2_custom_fcmpeqs, -1)
+Do not use the fcmpeqs custom instruction
+
+mcustom-fcmpeqs=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpeqs) Init(-1)
+Integer id (N) of fcmpeqs custom instruction
+
+mno-custom-fcmpges
+Target Report RejectNegative Var(nios2_custom_fcmpges, -1)
+Do not use the fcmpges custom instruction
+
+mcustom-fcmpges=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpges) Init(-1)
+Integer id (N) of fcmpges custom instruction
+
+mno-custom-fcmpgts
+Target Report RejectNegative Var(nios2_custom_fcmpgts, -1)
+Do not use the fcmpgts custom instruction
+
+mcustom-fcmpgts=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpgts) Init(-1)
+Integer id (N) of fcmpgts custom instruction
+
+mno-custom-fcmples
+Target Report RejectNegative Var(nios2_custom_fcmples, -1)
+Do not use the fcmples custom instruction
+
+mcustom-fcmples=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmples) Init(-1)
+Integer id (N) of fcmples custom instruction
+
+mno-custom-fcmplts
+Target Report RejectNegative Var(nios2_custom_fcmplts, -1)
+Do not use the fcmplts custom instruction
+
+mcustom-fcmplts=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmplts) Init(-1)
+Integer id (N) of fcmplts custom instruction
+
+mno-custom-flogs
+Target Report RejectNegative Var(nios2_custom_flogs, -1)
+Do not use the flogs custom instruction
+
+mcustom-flogs=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_flogs) Init(-1)
+Integer id (N) of flogs custom instruction
+
+mno-custom-fexps
+Target Report RejectNegative Var(nios2_custom_fexps, -1)
+Do not use the fexps custom instruction
+
+mcustom-fexps=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fexps) Init(-1)
+Integer id (N) of fexps custom instruction
+
+mno-custom-fatans
+Target Report RejectNegative Var(nios2_custom_fatans, -1)
+Do not use the fatans custom instruction
+
+mcustom-fatans=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fatans) Init(-1)
+Integer id (N) of fatans custom instruction
+
+mno-custom-ftans
+Target Report RejectNegative Var(nios2_custom_ftans, -1)
+Do not use the ftans custom instruction
+
+mcustom-ftans=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_ftans) Init(-1)
+Integer id (N) of ftans custom instruction
+
+mno-custom-fsins
+Target Report RejectNegative Var(nios2_custom_fsins, -1)
+Do not use the fsins custom instruction
+
+mcustom-fsins=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fsins) Init(-1)
+Integer id (N) of fsins custom instruction
+
+mno-custom-fcoss
+Target Report RejectNegative Var(nios2_custom_fcoss, -1)
+Do not use the fcoss custom instruction
+
+mcustom-fcoss=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fcoss) Init(-1)
+Integer id (N) of fcoss custom instruction
+
+mno-custom-fsqrts
+Target Report RejectNegative Var(nios2_custom_fsqrts, -1)
+Do not use the fsqrts custom instruction
+
+mcustom-fsqrts=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fsqrts) Init(-1)
+Integer id (N) of fsqrts custom instruction
+
+mno-custom-fabss
+Target Report RejectNegative Var(nios2_custom_fabss, -1)
+Do not use the fabss custom instr
+
+mcustom-fabss=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fabss) Init(-1)
+Integer id (N) of fabss custom instruction
+
+mno-custom-fnegs
+Target Report RejectNegative Var(nios2_custom_fnegs, -1)
+Do not use the fnegs custom instruction
+
+mcustom-fnegs=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fnegs) Init(-1)
+Integer id (N) of fnegs custom instruction
+
+mno-custom-fmaxs
+Target Report RejectNegative Var(nios2_custom_fmaxs, -1)
+Do not use the fmaxs custom instruction
+
+mcustom-fmaxs=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fmaxs) Init(-1)
+Integer id (N) of fmaxs custom instruction
+
+mno-custom-fmins
+Target Report RejectNegative Var(nios2_custom_fmins, -1)
+Do not use the fmins custom instruction
+
+mcustom-fmins=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fmins) Init(-1)
+Integer id (N) of fmins custom instruction
+
+mno-custom-fdivs
+Target Report RejectNegative Var(nios2_custom_fdivs, -1)
+Do not use the fdivs custom instruction
+
+mcustom-fdivs=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fdivs) Init(-1)
+Integer id (N) of fdivs custom instruction
+
+mno-custom-fmuls
+Target Report RejectNegative Var(nios2_custom_fmuls, -1)
+Do not use the fmuls custom instruction
+
+mcustom-fmuls=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fmuls) Init(-1)
+Integer id (N) of fmuls custom instruction
+
+mno-custom-fsubs
+Target Report RejectNegative Var(nios2_custom_fsubs, -1)
+Do not use the fsubs custom instruction
+
+mcustom-fsubs=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fsubs) Init(-1)
+Integer id (N) of fsubs custom instruction
+
+mno-custom-fadds
+Target Report RejectNegative Var(nios2_custom_fadds, -1)
+Do not use the fadds custom instruction
+
+mcustom-fadds=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fadds) Init(-1)
+Integer id (N) of fadds custom instruction
+
+mno-custom-frdy
+Target Report RejectNegative Var(nios2_custom_frdy, -1)
+Do not use the frdy custom instruction
+
+mcustom-frdy=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_frdy) Init(-1)
+Integer id (N) of frdy custom instruction
+
+mno-custom-frdxhi
+Target Report RejectNegative Var(nios2_custom_frdxhi, -1)
+Do not use the frdxhi custom instruction
+
+mcustom-frdxhi=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_frdxhi) Init(-1)
+Integer id (N) of frdxhi custom instruction
+
+mno-custom-frdxlo
+Target Report RejectNegative Var(nios2_custom_frdxlo, -1)
+Do not use the frdxlo custom instruction
+
+mcustom-frdxlo=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_frdxlo) Init(-1)
+Integer id (N) of frdxlo custom instruction
+
+mno-custom-fwry
+Target Report RejectNegative Var(nios2_custom_fwry, -1)
+Do not use the fwry custom instruction
+
+mcustom-fwry=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fwry) Init(-1)
+Integer id (N) of fwry custom instruction
+
+mno-custom-fwrx
+Target Report RejectNegative Var(nios2_custom_fwrx, -1)
+Do not use the fwrx custom instruction
+
+mcustom-fwrx=
+Target Report RejectNegative Joined UInteger Var(nios2_custom_fwrx) Init(-1)
+Integer id (N) of fwrx custom instruction
Index: gcc/config/nios2/elf.h
===================================================================
--- gcc/config/nios2/elf.h	(revision 0)
+++ gcc/config/nios2/elf.h	(revision 0)
@@ -0,0 +1,52 @@ 
+/* Definitions of ELF target support for Altera Nios II.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Jonah Graham (jgraham@altera.com), 
+   Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   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/>.  */
+
+
+/* Specs to support the additional command-line options for Nios II ELF
+   toolchains.  */
+
+/* -msmallc chooses an alternate C library.
+   -msys-lib= specifies an additional low-level system/hosting library and
+   is typically used to suck in a library provided by a HAL BSP.  */
+#undef LIB_SPEC
+#define LIB_SPEC \
+"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
+ %{msys-lib=*: -l%*} \
+ --end-group \
+"
+
+/* Linking with -mhal suppresses inclusion of the GCC-provided crt* begin/end
+   code.  Normally in this case you also link with -msys-crt0= to specify
+   the startup code provided by the HAL BSP instead.  */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC						\
+  "%{mhal:"							\
+  "%{msys-crt0=*:%*} %{!msys-crt0=*:crt0%O%s} "			\
+  "%{msys-crt0=:%eYou need a C startup file for -msys-crt0=};"	\
+  ":crti%O%s crtbegin%O%s}"
+
+#undef  ENDFILE_SPEC
+#define ENDFILE_SPEC "%{!mhal:crtend%O%s crtn%O%s}"
+
+/* The ELF target doesn't support the Nios II Linux ABI.  */
+#define TARGET_LINUX_ABI 0
+
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 204897)
+++ gcc/config.gcc	(working copy)
@@ -425,6 +425,10 @@  nds32*)
 	cpu_type=nds32
 	extra_headers="nds32_intrinsic.h"
 	;;
+nios2-*-*)
+	cpu_type=nios2
+	extra_options="${extra_options} g.opt"
+	;;	
 picochip-*-*)
         cpu_type=picochip
         ;;
@@ -2107,6 +2111,19 @@  nds32be-*-*)
 	tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
 	tmake_file="nds32/t-mlibs"
 	;;
+nios2-*-*)
+	tm_file="elfos.h ${tm_file}"
+        tmake_file="${tmake_file} nios2/t-nios2"
+        case ${target} in
+        nios2-*-linux*)
+                tm_file="${tm_file} gnu-user.h linux.h glibc-stdint.h nios2/linux.h "
+                ;;
+	nios2-*-elf*)
+		tm_file="${tm_file} newlib-stdint.h nios2/elf.h"
+		extra_options="${extra_options} nios2/elf.opt"
+		;;
+        esac
+	;;
 pdp11-*-*)
 	tm_file="${tm_file} newlib-stdint.h"
 	use_gcc_stdint=wrap
Index: gcc/configure
===================================================================
--- gcc/configure	(revision 204897)
+++ gcc/configure	(working copy)
@@ -23344,6 +23344,13 @@  foo:
 	tls_first_minor=19
 	tls_as_opt='--fatal-warnings'
 	;;
+  nios2-*-*)
+      conftest_s='
+	.section ".tdata","awT",@progbits'
+	tls_first_major=2
+	tls_first_minor=23
+	tls_as_opt="--fatal-warnings"
+	;;
   aarch64*-*-*)
     conftest_s='
 	.section ".tdata","awT",%progbits
@@ -26145,8 +26152,8 @@  esac
 # version to the per-target configury.
 case "$cpu_type" in
   aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \
-  | mips | pa | rs6000 | score | sparc | spu | tilegx | tilepro | xstormy16 \
-  | xtensa)
+  | mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \
+  | xstormy16 | xtensa)
     insn="nop"
     ;;
   ia64 | s390)
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 204897)
+++ gcc/configure.ac	(working copy)
@@ -3027,6 +3027,13 @@  foo:
 	tls_first_minor=19
 	tls_as_opt='--fatal-warnings'
 	;;
+  nios2-*-*)
+      conftest_s='
+	.section ".tdata","awT",@progbits'
+	tls_first_major=2
+	tls_first_minor=23
+	tls_as_opt="--fatal-warnings"
+	;;
   aarch64*-*-*)
     conftest_s='
 	.section ".tdata","awT",%progbits
@@ -4233,8 +4240,8 @@  esac
 # version to the per-target configury.
 case "$cpu_type" in
   aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \
-  | mips | pa | rs6000 | score | sparc | spu | tilegx | tilepro | xstormy16 \
-  | xtensa)
+  | mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \
+  | xstormy16 | xtensa)
     insn="nop"
     ;;
   ia64 | s390)
Index: gcc/common/config/nios2/nios2-common.c
===================================================================
--- gcc/common/config/nios2/nios2-common.c	(revision 0)
+++ gcc/common/config/nios2/nios2-common.c	(revision 0)
@@ -0,0 +1,44 @@ 
+/* Common hooks for Altera Nios II.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic-core.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+#include "opts.h"
+#include "flags.h"
+
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
+static const struct default_options nios2_option_optimization_table[] =
+  {
+    { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+    { OPT_LEVELS_3_PLUS, OPT_mfast_sw_div, NULL, 1 },
+    { OPT_LEVELS_NONE, 0, NULL, 0 }
+  };
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE nios2_option_optimization_table
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 204897)
+++ gcc/doc/invoke.texi	(working copy)
@@ -837,6 +837,16 @@  Objective-C and Objective-C++ Dialects}.
 -mforce-fp-as-gp -mforbid-fp-as-gp @gol
 -mex9 -mctor-dtor -mrelax}
 
+@emph{Nios II Options}
+@gccoptlist{-G @var{num} -mel -meb @gol
+-mno-bypass-cache -mbypass-cache @gol
+-mno-cache-volatile -mcache-volatile @gol
+-mno-fast-sw-div -mfast-sw-div @gol
+-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx -mno-hw-div -mhw-div @gol
+-mcustom-@var{insn}=@var{N} -mno-custom-@var{insn} @gol
+-mcustom-fpu-cfg=@var{name} @gol
+-mhal -msmallc -msys-crt0=@var{name} -msys-lib=@var{name}}
+
 @emph{PDP-11 Options}
 @gccoptlist{-mfpu  -msoft-float  -mac0  -mno-ac0  -m40  -m45  -m10 @gol
 -mbcopy  -mbcopy-builtin  -mint32  -mno-int16 @gol
@@ -11051,6 +11061,7 @@  platform.
 * Moxie Options::
 * MSP430 Options::
 * NDS32 Options::
+* Nios II Options::
 * PDP-11 Options::
 * picoChip Options::
 * PowerPC Options::
@@ -17970,6 +17981,269 @@  Guide linker to relax instructions.
 
 @end table
 
+@node Nios II Options
+@subsection Nios II Options
+@cindex Nios II options
+@cindex Altera Nios II options
+
+These are the options defined for the Altera Nios II processor.
+
+@table @gcctabopt
+
+@item -G @var{num}
+@opindex G
+@cindex smaller data references
+Put global and static objects less than or equal to @var{num} bytes
+into the small data or BSS sections instead of the normal data or BSS
+sections.  The default value of @var{num} is 8.
+
+@item -mel
+@itemx -meb
+@opindex mel
+@opindex meb
+Generate little-endian (default) or big-endian (experimental) code,
+respectively.
+
+@item -mbypass-cache
+@itemx -mno-bypass-cache
+@opindex mno-bypass-cache
+@opindex mbypass-cache
+Force all load and store instructions to always bypass cache by 
+using I/O variants of the instructions. The default is not to
+bypass the cache.
+
+@item -mno-cache-volatile 
+@itemx -mcache-volatile       
+@opindex mcache-volatile 
+@opindex mno-cache-volatile
+Volatile memory access bypass the cache using the I/O variants of 
+the load and store instructions. The default is not to bypass the cache.
+
+@item -mno-fast-sw-div
+@itemx -mfast-sw-div
+@opindex mno-fast-sw-div
+@opindex mfast-sw-div
+Do not use table-based fast divide for small numbers. The default 
+is to use the fast divide at @option{-O3} and above.
+
+@item -mno-hw-mul
+@itemx -mhw-mul
+@itemx -mno-hw-mulx
+@itemx -mhw-mulx
+@itemx -mno-hw-div
+@itemx -mhw-div
+@opindex mno-hw-mul
+@opindex mhw-mul
+@opindex mno-hw-mulx
+@opindex mhw-mulx
+@opindex mno-hw-div
+@opindex mhw-div
+Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of 
+instructions by the compiler. The default is to emit @code{mul}
+and not emit @code{div} and @code{mulx}.
+
+@item -mcustom-@var{insn}=@var{N}
+@itemx -mno-custom-@var{insn}
+@opindex mcustom-@var{insn}
+@opindex mno-custom-@var{insn}
+Each @option{-mcustom-@var{insn}=@var{N}} option enables use of a
+custom instruction with encoding @var{N} when generating code that uses 
+@var{insn}.  For example, @code{-mcustom-fadds=253} generates custom
+instruction 253 for single-precision floating-point add operations instead
+of the default behavior of using a library call.
+
+The following values of @var{insn} are supported.  Except as otherwise
+noted, floating-point operations are expected to be implemented with
+normal IEEE 754 semantics and correspond directly to the C operators or the
+equivalent GCC built-in functions (@pxref{Other Builtins}).
+
+Single-precision floating point:
+@table @asis
+
+@item @samp{fadds}, @samp{fsubs}, @samp{fdivs}, @samp{fmuls}
+Binary arithmetic operations.
+
+@item @samp{fnegs}
+Unary negation.
+
+@item @samp{fabss}
+Unary absolute value.
+
+@item @samp{fcmpeqs}, @samp{fcmpges}, @samp{fcmpgts}, @samp{fcmples}, @samp{fcmplts}, @samp{fcmpnes}
+Comparison operations.
+
+@item @samp{fmins}, @samp{fmaxs}
+Floating-point minimum and maximum.  These instructions are only
+generated if @option{-ffinite-math-only} is specified.
+
+@item @samp{fsqrts}
+Unary square root operation.
+
+@item @samp{fcoss}, @samp{fsins}, @samp{ftans}, @samp{fatans}, @samp{fexps}, @samp{flogs}
+Floating-point trigonometric and exponential functions.  These instructions
+are only generated if @option{-funsafe-math-optimizations} is also specified.
+
+@end table
+
+Double-precision floating point:
+@table @asis
+
+@item @samp{faddd}, @samp{fsubd}, @samp{fdivd}, @samp{fmuld}
+Binary arithmetic operations.
+
+@item @samp{fnegd}
+Unary negation.
+
+@item @samp{fabsd}
+Unary absolute value.
+
+@item @samp{fcmpeqd}, @samp{fcmpged}, @samp{fcmpgtd}, @samp{fcmpled}, @samp{fcmpltd}, @samp{fcmpned}
+Comparison operations.
+
+@item @samp{fmind}, @samp{fmaxd}
+Double-precision minimum and maximum.  These instructions are only
+generated if @option{-ffinite-math-only} is specified.
+
+@item @samp{fsqrtd}
+Unary square root operation.
+
+@item @samp{fcosd}, @samp{fsind}, @samp{ftand}, @samp{fatand}, @samp{fexpd}, @samp{flogd}
+Double-precision trigonometric and exponential functions.  These instructions
+are only generated if @option{-funsafe-math-optimizations} is also specified.
+
+@end table
+
+Conversions:
+@table @asis
+@item @samp{fextsd}
+Conversion from single precision to double precision.
+
+@item @samp{ftruncds}
+Conversion from double precision to single precision.
+
+@item @samp{fixsi}, @samp{fixsu}, @samp{fixdi}, @samp{fixdu}
+Conversion from floating point to signed or unsigned integer types, with
+truncation towards zero.
+
+@item @samp{floatis}, @samp{floatus}, @samp{floatid}, @samp{floatud}
+Conversion from signed or unsigned integer types to floating-point types.
+
+@end table
+
+In addition, all of the following transfer instructions for internal
+registers X and Y must be provided to use any of the double-precision
+floating-point instructions.  Custom instructions taking two
+double-precision source operands expect the first operand in the
+64-bit register X.  The other operand (or only operand of a unary
+operation) is given to the custom arithmetic instruction with the
+least significant half in source register @var{src1} and the most
+significant half in @var{src2}.  A custom instruction that returns a
+double-precision result returns the most significant 32 bits in the
+destination register and the other half in 32-bit register Y.  
+GCC automatically generates the necessary code sequences to write
+register X and/or read register Y when double-precision floating-point
+instructions are used.
+
+@table @asis
+
+@item @samp{fwrx}
+Write @var{src1} into the least significant half of X and @var{src2} into
+the most significant half of X.
+
+@item @samp{fwry}
+Write @var{src1} into Y.
+
+@item @samp{frdxhi}, @samp{frdxlo}
+Read the most or least (respectively) significant half of X and store it in
+@var{dest}.
+
+@item @samp{frdy}
+Read the value of Y and store it into @var{dest}.
+@end table
+
+Note that you can gain more local control over generation of Nios II custom
+instructions by using the @code{target("custom-@var{insn}=@var{N}")}
+and @code{target("no-custom-@var{insn}")} function attributes
+(@pxref{Function Attributes})
+or pragmas (@pxref{Function Specific Option Pragmas}).
+
+@item -mcustom-fpu-cfg=@var{name}
+@opindex mcustom-fpu-cfg
+
+This option enables a predefined, named set of custom instruction encodings
+(see @option{-mcustom-@var{insn}} above).  
+Currently, the following sets are defined:
+
+@option{-mcustom-fpu-cfg=60-1} is equivalent to:
+@gccoptlist{-mcustom-fmuls=252 @gol
+-mcustom-fadds=253 @gol
+-mcustom-fsubs=254 @gol
+-fsingle-precision-constant}
+
+@option{-mcustom-fpu-cfg=60-2} is equivalent to:
+@gccoptlist{-mcustom-fmuls=252 @gol
+-mcustom-fadds=253 @gol
+-mcustom-fsubs=254 @gol
+-mcustom-fdivs=255 @gol
+-fsingle-precision-constant}
+
+@option{-mcustom-fpu-cfg=72-3} is equivalent to:
+@gccoptlist{-mcustom-floatus=243 @gol
+-mcustom-fixsi=244 @gol
+-mcustom-floatis=245 @gol
+-mcustom-fcmpgts=246 @gol
+-mcustom-fcmples=249 @gol
+-mcustom-fcmpeqs=250 @gol
+-mcustom-fcmpnes=251 @gol
+-mcustom-fmuls=252 @gol
+-mcustom-fadds=253 @gol
+-mcustom-fsubs=254 @gol
+-mcustom-fdivs=255 @gol
+-fsingle-precision-constant}
+
+Custom instruction assignments given by individual
+@option{-mcustom-@var{insn}=} options override those given by
+@option{-mcustom-fpu-cfg=}, regardless of the
+order of the options on the command line.
+
+Note that you can gain more local control over selection of a FPU
+configuration by using the @code{target("custom-fpu-cfg=@var{name}")}
+function attribute (@pxref{Function Attributes})
+or pragma (@pxref{Function Specific Option Pragmas}).
+
+@end table
+
+These additional @samp{-m} options are available for the Altera Nios II
+ELF (bare-metal) target:
+
+@table @gcctabopt
+
+@item -mhal
+@opindex mhal
+Link with HAL BSP.  This suppresses linking with the GCC-provided C runtime
+startup and termination code, and is typically used in conjunction with
+@option{-msys-crt0=} to specify the location of the alternate startup code
+provided by the HAL BSP.
+
+@item -msmallc
+@opindex msmallc
+Link with a limited version of the C library, @option{-lsmallc}, rather than
+Newlib.
+
+@item -msys-crt0=@var{startfile}
+@opindex msys-crt0
+@var{startfile} is the file name of the startfile (crt0) to use 
+when linking.  This option is only useful in conjunction with @option{-mhal}.
+
+@item -msys-lib=@var{systemlib}
+@opindex msys-lib
+@var{systemlib} is the library name of the library that provides
+low-level system calls required by the C library,
+e.g. @code{read} and @code{write}.
+This option is typically used to link with a library provided by a HAL BSP.
+
+@end table
+
 @node PDP-11 Options
 @subsection PDP-11 Options
 @cindex PDP-11 Options
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 204897)
+++ gcc/doc/md.texi	(working copy)
@@ -3233,6 +3233,52 @@  Memory constraint for 45 format.
 Memory constraint for 37 format.
 @end table
 
+@item Nios II family---@file{config/nios2/constraints.md}
+@table @code
+
+@item I
+Integer that is valid as an immediate operand in an
+instruction taking a signed 16-bit number. Range
+@minus{}32768 to 32767.
+
+@item J
+Integer that is valid as an immediate operand in an
+instruction taking an unsigned 16-bit number. Range
+0 to 65535.
+
+@item K
+Integer that is valid as an immediate operand in an
+instruction taking only the upper 16-bits of a
+32-bit number. Range 32-bit numbers with the lower
+16-bits being 0.
+
+@item L
+Integer that is valid as an immediate operand for a 
+shift instruction. Range 0 to 31.
+
+@item M
+Integer that is valid as an immediate operand for
+only the value 0. Can be used in conjunction with
+the format modifier @code{z} to use @code{r0}
+instead of @code{0} in the assembly output.
+
+@item N
+Integer that is valid as an immediate operand for
+a custom instruction opcode. Range 0 to 255.
+
+@item S
+Matches immediates which are addresses in the small
+data section and therefore can be added to @code{gp}
+as a 16-bit immediate to re-create their 32-bit value.
+
+@ifset INTERNALS
+@item T
+A @code{const} wrapped @code{UNSPEC} expression,
+representing a supported PIC or TLS relocation.
+@end ifset
+
+@end table
+
 @item PDP-11---@file{config/pdp11/constraints.md}
 @table @code
 @item a
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 204897)
+++ gcc/doc/extend.texi	(working copy)
@@ -3836,6 +3836,14 @@  int core2_func (void) __attribute__ ((__target__ (
 int sse3_func (void) __attribute__ ((__target__ ("sse3")));
 @end smallexample
 
+You can either use multiple
+strings to specify multiple options, or separate the options
+with a comma (@samp{,}).
+
+The @code{target} attribute is presently implemented for
+i386/x86_64, PowerPC, and Nios II targets only.
+The options supported are specific to each target.
+
 On the 386, the following options are allowed:
 
 @table @samp
@@ -4157,20 +4165,36 @@  compilation tunes for the @var{CPU} architecture,
 default tuning specified on the command line.
 @end table
 
-On the 386/x86_64 and PowerPC back ends, you can use either multiple
-strings to specify multiple options, or you can separate the option
-with a comma (@code{,}).
+When compiling for Nios II, the following options are allowed:
 
+@table @samp
+@item custom-@var{insn}=@var{N}
+@itemx no-custom-@var{insn}
+@cindex @code{target("custom-@var{insn}=@var{N}")} attribute
+@cindex @code{target("no-custom-@var{insn}")} attribute
+Each @samp{custom-@var{insn}=@var{N}} attribute locally enables use of a
+custom instruction with encoding @var{N} when generating code that uses 
+@var{insn}.  Similarly, @samp{no-custom-@var{insn}} locally inhibits use of
+the custom instruction @var{insn}.
+These target attributes correspond to the
+@option{-mcustom-@var{insn}=@var{N}} and @option{-mno-custom-@var{insn}}
+command-line options, and support the same set of @var{insn} keywords.
+@xref{Nios II Options}, for more information.
+
+@item custom-fpu-cfg=@var{name}
+@cindex @code{target("custom-fpu-cfg=@var{name}")} attribute
+This attribute corresponds to the @option{-mcustom-fpu-cfg=@var{name}}
+command-line option, to select a predefined set of custom instructions
+named @var{name}.
+@xref{Nios II Options}, for more information.
+@end table
+
 On the 386/x86_64 and PowerPC back ends, the inliner does not inline a
 function that has different target options than the caller, unless the
 callee has a subset of the target options of the caller.  For example
 a function declared with @code{target("sse3")} can inline a function
 with @code{target("sse2")}, since @code{-msse3} implies @code{-msse2}.
 
-The @code{target} attribute is not implemented in GCC versions earlier
-than 4.4 for the i386/x86_64 and 4.6 for the PowerPC back ends.  It is
-not currently implemented for other back ends.
-
 @item tiny_data
 @cindex tiny data section on the H8/300H and H8S
 Use this attribute on the H8/300H and H8S to indicate that the specified
@@ -9200,6 +9224,7 @@  instructions, but allow the compiler to schedule t
 
 @menu
 * Alpha Built-in Functions::
+* Altera Nios II Built-in Functions::
 * ARC Built-in Functions::
 * ARC SIMD Built-in Functions::
 * ARM iWMMXt Built-in Functions::
@@ -9310,6 +9335,110 @@  void *__builtin_thread_pointer (void)
 void __builtin_set_thread_pointer (void *)
 @end smallexample
 
+@node Altera Nios II Built-in Functions
+@subsection Altera Nios II Built-in Functions
+
+These built-in functions are available for the Altera Nios II
+family of processors.
+
+The following built-in functions are always available.  They
+all generate the machine instruction that is part of the name.
+
+@example
+int __builtin_ldbio (volatile const void *)
+int __builtin_ldbuio (volatile const void *)
+int __builtin_ldhio (volatile const void *)
+int __builtin_ldhuio (volatile const void *)
+int __builtin_ldwio (volatile const void *)
+void __builtin_stbio (volatile void *, int)
+void __builtin_sthio (volatile void *, int)
+void __builtin_stwio (volatile void *, int)
+void __builtin_sync (void)
+int __builtin_rdctl (int) 
+void __builtin_wrctl (int, int)
+@end example
+
+The following built-in functions are always available.  They
+all generate a Nios II Custom Instruction. The name of the
+function represents the types that the function takes and
+returns. The letter before the @code{n} is the return type
+or void if absent. The @code{n} represents the first parameter
+to all the custom instructions, the custom instruction number.
+The two letters after the @code{n} represent the up to two
+parameters to the function.
+
+The letters represent the following data types:
+@table @code
+@item <no letter>
+@code{void} for return type and no parameter for parameter types.
+
+@item i
+@code{int} for return type and parameter type
+
+@item f
+@code{float} for return type and parameter type
+
+@item p
+@code{void *} for return type and parameter type
+
+@end table
+
+And the function names are:
+@example
+void __builtin_custom_n (void)
+void __builtin_custom_ni (int)
+void __builtin_custom_nf (float)
+void __builtin_custom_np (void *)
+void __builtin_custom_nii (int, int)
+void __builtin_custom_nif (int, float)
+void __builtin_custom_nip (int, void *)
+void __builtin_custom_nfi (float, int)
+void __builtin_custom_nff (float, float)
+void __builtin_custom_nfp (float, void *)
+void __builtin_custom_npi (void *, int)
+void __builtin_custom_npf (void *, float)
+void __builtin_custom_npp (void *, void *)
+int __builtin_custom_in (void)
+int __builtin_custom_ini (int)
+int __builtin_custom_inf (float)
+int __builtin_custom_inp (void *)
+int __builtin_custom_inii (int, int)
+int __builtin_custom_inif (int, float)
+int __builtin_custom_inip (int, void *)
+int __builtin_custom_infi (float, int)
+int __builtin_custom_inff (float, float)
+int __builtin_custom_infp (float, void *)
+int __builtin_custom_inpi (void *, int)
+int __builtin_custom_inpf (void *, float)
+int __builtin_custom_inpp (void *, void *)
+float __builtin_custom_fn (void)
+float __builtin_custom_fni (int)
+float __builtin_custom_fnf (float)
+float __builtin_custom_fnp (void *)
+float __builtin_custom_fnii (int, int)
+float __builtin_custom_fnif (int, float)
+float __builtin_custom_fnip (int, void *)
+float __builtin_custom_fnfi (float, int)
+float __builtin_custom_fnff (float, float)
+float __builtin_custom_fnfp (float, void *)
+float __builtin_custom_fnpi (void *, int)
+float __builtin_custom_fnpf (void *, float)
+float __builtin_custom_fnpp (void *, void *)
+void * __builtin_custom_pn (void)
+void * __builtin_custom_pni (int)
+void * __builtin_custom_pnf (float)
+void * __builtin_custom_pnp (void *)
+void * __builtin_custom_pnii (int, int)
+void * __builtin_custom_pnif (int, float)
+void * __builtin_custom_pnip (int, void *)
+void * __builtin_custom_pnfi (float, int)
+void * __builtin_custom_pnff (float, float)
+void * __builtin_custom_pnfp (float, void *)
+void * __builtin_custom_pnpi (void *, int)
+void * __builtin_custom_pnpf (void *, float)
+void * __builtin_custom_pnpp (void *, void *)
+@end example
+
 @node ARC Built-in Functions
 @subsection ARC Built-in Functions
 
@@ -16275,9 +16404,8 @@  function.  The parenthesis around the options is o
 @xref{Function Attributes}, for more information about the
 @code{target} attribute and the attribute syntax.
 
-The @code{#pragma GCC target} attribute is not implemented in GCC versions earlier
-than 4.4 for the i386/x86_64 and 4.6 for the PowerPC back ends.  At
-present, it is not implemented for other back ends.
+The @code{#pragma GCC target} pragma is presently implemented for
+i386/x86_64, PowerPC, and Nios II targets only.
 @end table
 
 @table @code