--- /dev/null
+--- gcc-3.4.2/gcc/config/mips/mips.h Thu Jul 15 02:42:47 2004
++++ gcc-3.4.2/gcc/config/mips/mips.h Sat Sep 18 00:41:48 2004
+@@ -122,6 +122,7 @@
+ extern const char *mips_isa_string; /* for -mips{1,2,3,4} */
+ extern const char *mips_abi_string; /* for -mabi={32,n32,64} */
+ extern const char *mips_cache_flush_func;/* for -mflush-func= and -mno-flush-func */
++extern const char *mips_ip28_cache_barrier;/* for -mip28-cache-barrier */
+ extern int mips_string_length; /* length of strings for mips16 */
+ extern const struct mips_cpu_info mips_cpu_info_table[];
+ extern const struct mips_cpu_info *mips_arch_info;
+@@ -333,6 +334,7 @@
+ #define TARGET_MIPS9000 (mips_arch == PROCESSOR_R9000)
+ #define TARGET_SB1 (mips_arch == PROCESSOR_SB1)
+ #define TARGET_SR71K (mips_arch == PROCESSOR_SR71000)
++#define TARGET_IP28 (mips_ip28_cache_barrier != 0)
+
+ /* Scheduling target defines. */
+ #define TUNE_MIPS3000 (mips_tune == PROCESSOR_R3000)
+@@ -752,6 +754,8 @@
+ N_("Don't call any cache flush functions"), 0}, \
+ { "flush-func=", &mips_cache_flush_func, \
+ N_("Specify cache flush function"), 0}, \
++ { "ip28-cache-barrier", &mips_ip28_cache_barrier, \
++ N_("Generate special cache barriers for SGI Indigo2 R10k"), 0}, \
+ }
+
+ /* This is meant to be redefined in the host dependent files. */
+@@ -3448,3 +3452,11 @@
+ " TEXT_SECTION_ASM_OP);
+ #endif
+ #endif
++\f
++#define ASM_OUTPUT_R10K_CACHE_BARRIER(STREAM) \
++ fprintf (STREAM, "\tcache 0x14,0($sp)\t%s Cache Barrier\n", ASM_COMMENT_START)
++
++/*
++ * mips.h Thu Jul 15 02:42:47 2004
++ * mips.h Fri Sep 17 23:18:19 2004 ip28
++ */
+--- gcc-3.4.2/gcc/config/mips/mips.c Wed Jul 7 21:21:10 2004
++++ gcc-3.4.2/gcc/config/mips/mips.c Fri Sep 17 23:33:44 2004
+@@ -502,6 +502,11 @@
+
+ const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
+
++/* Nonzero means generate special cache barriers to inhibit speculative
++ stores which might endanger cache coherency or reference invalid
++ addresses (especially on SGI's Indigo2 R10k (IP28)). */
++const char *mips_ip28_cache_barrier;
++
+ /* If TRUE, we split addresses into their high and low parts in the RTL. */
+ int mips_split_addresses;
+
+@@ -9676,3 +9681,7 @@
+ #endif /* TARGET_IRIX */
+
+ #include "gt-mips.h"
++/*
++ * mips.c Wed Jul 7 21:21:10 2004
++ * mips.c Fri Sep 17 23:25:53 2004 ip28
++ */
+--- gcc-3.4.2/gcc/final.c Sun Jan 18 23:39:57 2004
++++ gcc-3.4.2/gcc/final.c Thu Apr 7 00:00:05 2005
+@@ -146,6 +146,13 @@
+
+ static rtx last_ignored_compare = 0;
+
++/* Flag indicating this insn is the start of a new basic block. */
++
++#define NEW_BLOCK_LABEL 1
++#define NEW_BLOCK_BRANCH 2
++
++static int new_block = NEW_BLOCK_LABEL;
++
+ /* Assign a unique number to each insn that is output.
+ This can be used to generate unique local labels. */
+
+@@ -235,6 +242,7 @@
+ #ifdef HAVE_ATTR_length
+ static int align_fuzz (rtx, rtx, int, unsigned);
+ #endif
++static int output_store_cache_barrier (FILE *, rtx);
+ \f
+ /* Initialize data in final at the beginning of a compilation. */
+
+@@ -1505,6 +1513,7 @@
+ int seen = 0;
+
+ last_ignored_compare = 0;
++ new_block = NEW_BLOCK_LABEL;
+
+ #ifdef SDB_DEBUGGING_INFO
+ /* When producing SDB debugging info, delete troublesome line number
+@@ -1571,6 +1580,7 @@
+
+ insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen);
+ }
++ new_block = 0;
+ }
+ \f
+ const char *
+@@ -1851,6 +1861,7 @@
+ #endif
+ if (prescan > 0)
+ break;
++ new_block = NEW_BLOCK_LABEL;
+
+ if (LABEL_NAME (insn))
+ (*debug_hooks->label) (insn);
+@@ -2009,6 +2020,26 @@
+
+ break;
+ }
++
++#ifdef TARGET_IP28
++ if (new_block)
++ {
++ /* .reorder: not really in the branch-delay-slot. */
++ if (! set_noreorder)
++ new_block = NEW_BLOCK_LABEL;
++
++ if (new_block == NEW_BLOCK_BRANCH)
++ /* Not yet, only *after* the branch-delay-slot ! */
++ new_block = NEW_BLOCK_LABEL;
++ else
++ {
++ if (TARGET_IP28)
++ output_store_cache_barrier (file, insn);
++ new_block = 0;
++ }
++ }
++#endif
++
+ /* Output this line note if it is the first or the last line
+ note in a row. */
+ if (notice_source_line (insn))
+@@ -2132,8 +2163,29 @@
+ clobbered by the function. */
+ if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
+ {
++#ifdef TARGET_IP28
++ if (TARGET_IP28)
++ new_block = NEW_BLOCK_LABEL;
++#endif
+ CC_STATUS_INIT;
+ }
++#ifdef TARGET_IP28
++ /* Following a conditional branch sequence, we have a new basic
++ block. */
++ if (TARGET_IP28)
++ {
++ rtx insn = XVECEXP (body, 0, 0);
++ rtx body = PATTERN (insn);
++
++ if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
++ && GET_CODE (SET_SRC (body)) != LABEL_REF)
++ || (GET_CODE (insn) == JUMP_INSN
++ && GET_CODE (body) == PARALLEL
++ && GET_CODE (XVECEXP (body, 0, 0)) == SET
++ && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
++ new_block = NEW_BLOCK_LABEL;
++ }
++#endif
+ break;
+ }
+
+@@ -2188,6 +2240,20 @@
+ }
+ #endif
+
++#ifdef TARGET_IP28
++ /* Following a conditional branch, we have a new basic block.
++ But if we are inside a sequence, the new block starts after the
++ last insn of the sequence. */
++ if (TARGET_IP28 && final_sequence == 0
++ && (GET_CODE (insn) == CALL_INSN
++ || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
++ && GET_CODE (SET_SRC (body)) != LABEL_REF)
++ || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL
++ && GET_CODE (XVECEXP (body, 0, 0)) == SET
++ && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)))
++ new_block = NEW_BLOCK_BRANCH;
++#endif
++
+ #ifndef STACK_REGS
+ /* Don't bother outputting obvious no-ops, even without -O.
+ This optimization is fast and doesn't interfere with debugging.
+@@ -2402,6 +2468,7 @@
+
+ if (prev_nonnote_insn (insn) != last_ignored_compare)
+ abort ();
++ new_block = 0;
+
+ /* We have already processed the notes between the setter and
+ the user. Make sure we don't process them again, this is
+@@ -2435,6 +2502,7 @@
+ abort ();
+ #endif
+
++ new_block = 0;
+ return new;
+ }
+
+@@ -3866,3 +3934,254 @@
+ symbol_queue_size = 0;
+ }
+ }
++
++
++#ifdef TARGET_IP28
++
++/* Check, whether an instruction is a possibly harmful store instruction,
++ i.e. a store which might cause damage, if speculatively executed. */
++
++static rtx
++find_mem_expr (rtx xexp)
++{
++ if (xexp)
++ {
++ const char *fmt;
++ int i, j, lng;
++ rtx x;
++ RTX_CODE code = GET_CODE (xexp);
++
++ if (MEM == code)
++ return xexp;
++
++ fmt = GET_RTX_FORMAT (code);
++ lng = GET_RTX_LENGTH (code);
++
++ for (i = 0; i < lng; ++i)
++ switch (fmt[i])
++ {
++ case 'e':
++ x = find_mem_expr (XEXP (xexp, i));
++ if (x)
++ return x;
++ break;
++ case 'E':
++ if (XVEC (xexp, i))
++ for (j = 0; j < XVECLEN (xexp, i); ++j)
++ {
++ x = find_mem_expr (XVECEXP (xexp, i, j));
++ if (x)
++ return x;
++ }
++ }
++ }
++ return 0;
++}
++
++static int
++check_mem_expr (rtx memx)
++{
++ /* Check the expression `memx' (with type GET_CODE(memx) == MEM)
++ for the most common stackpointer-addressing modes.
++ It's not worthwile to avoid a cache barrier also on the
++ remaining unfrequently used modes. */
++ rtx x = XEXP (memx, 0);
++ switch (GET_CODE (x))
++ {
++ case REG:
++ if (REGNO (x) == STACK_POINTER_REGNUM)
++ return 0;
++ default:
++ break;
++ case PLUS: case MINUS: /* always `SP + const' ? */
++ if (GET_CODE (XEXP (x, 1)) == REG
++ && REGNO (XEXP (x, 1)) == STACK_POINTER_REGNUM)
++ return 0;
++ case NEG: case SIGN_EXTEND: case ZERO_EXTEND:
++ if (GET_CODE (XEXP (x, 0)) == REG
++ && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM)
++ return 0;
++ }
++
++ /* Stores/Loads to/from constant addresses can be considered
++ harmless, since:
++ 1) the address is always valid, even when taken speculatively.
++ 2a) the location is (hopefully) never used as a dma-target, thus
++ there is no danger of cache-inconsistency.
++ 2b) uncached loads/stores are guaranteed to be non-speculative. */
++ if ( CONSTANT_P(x) )
++ return 0;
++
++ return 1;
++}
++
++/* inline */ static int
++check_pattern_for_store (rtx body)
++{
++ /* Check for (set (mem:M (non_stackpointer_address) ...)). Here we
++ assume, that addressing with the stackpointer accesses neither
++ uncached-aliased nor invalid memory. (May be, this applies to the
++ global pointer and frame pointer also, but its saver not to assume
++ it. And probably it's not worthwile to regard these registers)
++
++ Speculative loads from invalid addresses also cause bus errors...
++ So check for (set (reg:M ...) (mem:M (non_stackpointer_address)))
++ too. */
++
++ if (body && GET_CODE (body) == SET)
++ {
++ rtx x = find_mem_expr (body);
++
++ if (x && check_mem_expr (x))
++ return 1;
++ }
++ return 0;
++}
++
++static int
++check_insn_for_store (int state, rtx insn)
++{
++ /* Check for (ins (set (mem:M (dangerous_address)) ...)) or end of the
++ current basic block.
++ Criteria to recognize end-of/next basic-block are reduplicated here
++ from final_scan_insn. */
++
++ rtx body;
++ int code;
++
++ if (INSN_DELETED_P (insn))
++ return 0;
++
++ switch (code = GET_CODE (insn))
++ {
++ case CODE_LABEL:
++ return -1;
++ case CALL_INSN:
++ case JUMP_INSN:
++ case INSN:
++ body = PATTERN (insn);
++ if (GET_CODE (body) == SEQUENCE)
++ {
++ /* A delayed-branch sequence */
++ rtx ins0 = XVECEXP (body, 0, 0);
++ rtx pat0 = PATTERN (ins0);
++ int i;
++ for (i = 0; i < XVECLEN (body, 0); i++)
++ {
++ rtx insq = XVECEXP (body, 0, i);
++ if (! INSN_DELETED_P (insq))
++ {
++ int j = check_insn_for_store (state|1, insq);
++ if (j)
++ return j;
++ }
++ }
++ /* Following a conditional branch sequence, we have a new
++ basic block. */
++ if (GET_CODE (ins0) == JUMP_INSN)
++ if ((GET_CODE (pat0) == SET
++ && GET_CODE (SET_SRC (pat0)) != LABEL_REF)
++ || (GET_CODE (pat0) == PARALLEL
++ && GET_CODE (XVECEXP (pat0, 0, 0)) == SET
++ && GET_CODE (SET_SRC (XVECEXP (pat0, 0, 0))) != LABEL_REF))
++ return -1;
++ /* Handle a call sequence like a conditional branch sequence */
++ if (GET_CODE (ins0) == CALL_INSN)
++ return -1;
++ break;
++ }
++ if (GET_CODE (body) == PARALLEL)
++ {
++ int i;
++ for (i = 0; i < XVECLEN (body, 0); i++)
++ if (check_pattern_for_store (XVECEXP (body, 0, i)))
++ return 1;
++ }
++ /* Now, only a `simple' INSN or JUMP_INSN remains to be checked. */
++ if (code == INSN)
++ {
++ /* Since we don't know, what's inside, we must take inline
++ assembly to be dangerous */
++ if (GET_CODE (body) == ASM_INPUT)
++ return 1;
++
++ if (check_pattern_for_store (body))
++ return 1;
++ }
++ /* Handle a CALL_INSN instruction like a conditional branch */
++ if (code == JUMP_INSN || code == CALL_INSN)
++ {
++ /* Following a conditional branch, we have a new basic block. */
++ int ckds = 0;
++ if (code == CALL_INSN)
++ ckds = 1;
++ else
++ {
++ code = GET_CODE (body);
++ if ((code == SET
++ && GET_CODE (SET_SRC (body)) != LABEL_REF)
++ || (code == PARALLEL
++ && GET_CODE (XVECEXP (body, 0, 0)) == SET
++ && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
++ ckds = 1;
++ }
++ if (ckds)
++ {
++ /* But check insn(s) in delay-slot first. If we could know in
++ advance that this jump is in `.reorder' mode, where gas will
++ insert a `nop' into the delay-slot, we could skip this test.
++ Since we don't know, always assume `.noreorder', sometimes
++ emitting a cache-barrier, that isn't needed. */
++ /* But if we are here recursively, already checking a (pseudo-)
++ delay-slot, we are done. */
++ if ( !(state & 2) )
++ for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
++ switch (GET_CODE (insn))
++ {
++ case INSN:
++ if (check_insn_for_store (state|1|2, insn) > 0)
++ return 1;
++ case CODE_LABEL:
++ case CALL_INSN:
++ case JUMP_INSN:
++ return -1;
++ default:
++ /* skip NOTE,... */;
++ }
++ return -1;
++ }
++ }
++ /*break*/
++ }
++ return 0;
++}
++
++/* Scan a basic block, starting with `insn', for a possibly harmful store
++ instruction. If found, output a cache barrier at the start of this
++ block. */
++
++static int
++output_store_cache_barrier (FILE *file, rtx insn)
++{
++ for (; insn; insn = NEXT_INSN (insn))
++ {
++ int found = check_insn_for_store (0, insn);
++ if (found < 0)
++ break;
++ if (found > 0)
++ {
++ /* found critical store instruction */
++ ASM_OUTPUT_R10K_CACHE_BARRIER(file);
++ return 1;
++ }
++ }
++ fprintf(file, "\t%s Cache Barrier omitted.\n", ASM_COMMENT_START);
++ return 0;
++}
++
++#endif /* TARGET_IP28 */
++
++/*
++ * final.c Sun Jan 18 23:39:57 2004
++ * final.c Sat Sep 18 00:23:34 2004 ip28
++ */
--- /dev/null
+diff -Naurp gcc-3.4.1.orig/gcc/config/mips/mips.c gcc-3.4.1/gcc/config/mips/mips.c
+--- gcc-3.4.1.orig/gcc/config/mips/mips.c 2004-06-28 09:58:42.000000000 -0400
++++ gcc-3.4.1/gcc/config/mips/mips.c 2004-08-09 22:37:21.983939192 -0400
+@@ -707,6 +707,7 @@ const struct mips_cpu_info mips_cpu_info
+
+ /* MIPS IV */
+ { "r8000", PROCESSOR_R8000, 4 },
++ { "r10000", PROCESSOR_R10000, 4 },
+ { "vr5000", PROCESSOR_R5000, 4 },
+ { "vr5400", PROCESSOR_R5400, 4 },
+ { "vr5500", PROCESSOR_R5500, 4 },
+@@ -9401,6 +9402,9 @@ mips_issue_rate (void)
+ {
+ switch (mips_tune)
+ {
++ case PROCESSOR_R10000:
++ return 4;
++
+ case PROCESSOR_R5400:
+ case PROCESSOR_R5500:
+ case PROCESSOR_R7000:
+diff -Naurp gcc-3.4.1.orig/gcc/config/mips/mips.h gcc-3.4.1/gcc/config/mips/mips.h
+--- gcc-3.4.1.orig/gcc/config/mips/mips.h 2004-03-11 16:52:33.000000000 -0500
++++ gcc-3.4.1/gcc/config/mips/mips.h 2004-08-09 01:02:35.042149496 -0400
+@@ -66,6 +66,7 @@ enum processor_type {
+ PROCESSOR_R7000,
+ PROCESSOR_R8000,
+ PROCESSOR_R9000,
++ PROCESSOR_R10000,
+ PROCESSOR_SB1,
+ PROCESSOR_SR71000
+ };
+diff -Naurp gcc-3.4.1.orig/gcc/config/mips/mips.md gcc-3.4.1/gcc/config/mips/mips.md
+--- gcc-3.4.1.orig/gcc/config/mips/mips.md 2004-06-25 03:35:30.000000000 -0400
++++ gcc-3.4.1/gcc/config/mips/mips.md 2004-08-09 04:55:10.158649320 -0400
+@@ -103,6 +103,7 @@
+ ;; arith integer arithmetic instruction
+ ;; darith double precision integer arithmetic instructions
+ ;; const load constant
++;; shift integer shift
+ ;; imul integer multiply
+ ;; imadd integer multiply-add
+ ;; idiv integer divide
+@@ -120,7 +121,7 @@
+ ;; multi multiword sequence (or user asm statements)
+ ;; nop no operation
+ (define_attr "type"
+- "unknown,branch,jump,call,load,store,prefetch,prefetchx,move,condmove,xfer,hilo,const,arith,darith,imul,imadd,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop"
++ "unknown,branch,jump,call,load,store,prefetch,prefetchx,move,condmove,xfer,hilo,const,arith,darith,shift,imul,imadd,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop"
+ (cond [(eq_attr "jal" "!unset") (const_string "call")
+ (eq_attr "got" "load") (const_string "load")]
+ (const_string "unknown")))
+@@ -214,7 +215,7 @@
+ ;; Attribute describing the processor. This attribute must match exactly
+ ;; with the processor_type enumeration in mips.h.
+ (define_attr "cpu"
+- "default,4kc,5kc,20kc,m4k,r3000,r3900,r6000,r4000,r4100,r4111,r4120,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,sb1,sr71000"
++ "default,4kc,5kc,20kc,m4k,r3000,r3900,r6000,r4000,r4100,r4111,r4120,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,r10000,sb1,sr71000"
+ (const (symbol_ref "mips_tune")))
+
+ ;; The type of hardware hazard associated with this instruction.
+@@ -305,12 +306,12 @@
+
+ (define_function_unit "memory" 1 0
+ (and (eq_attr "type" "load")
+- (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4100,r4120,r4300,r5000"))
++ (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4100,r4120,r4300,r5000,r10000"))
+ 3 0)
+
+ (define_function_unit "memory" 1 0
+ (and (eq_attr "type" "load")
+- (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4120,r4300,r5000"))
++ (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4120,r4300,r5000,r10000"))
+ 2 0)
+
+ (define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0)
+@@ -323,7 +324,7 @@
+
+ (define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul,imadd")
+- (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4120,r4300,r5000"))
++ (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4120,r4300,r5000,r10000"))
+ 17 17)
+
+ ;; On them mips16, we want to stronly discourage a mult from appearing
+@@ -375,7 +376,7 @@
+
+ (define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+- (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4120,r4300,r5000"))
++ (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4120,r4300,r5000,r10000"))
+ 38 38)
+
+ (define_function_unit "imuldiv" 1 0
+@@ -424,6 +425,40 @@
+ (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
+ 68 68)
+
++;; R10000 has 2 integer ALUs
++(define_function_unit "alu" 2 0
++ (and (eq_attr "type" "arith,darith,shift")
++ (eq_attr "cpu" "r10000"))
++ 1 0)
++
++;; Only ALU1 can do shifts. We model shifts as an additional unit
++(define_function_unit "alu1" 1 0
++ (and (eq_attr "type" "shift")
++ (eq_attr "cpu" "r10000"))
++ 1 0)
++
++;; only ALU2 does multiplications and divisions
++(define_function_unit "alu2" 1 0
++ (and (eq_attr "type" "imul")
++ (and (eq_attr "mode" "SI") (eq_attr "cpu" "r10000")))
++ 6 6)
++
++(define_function_unit "alu2" 1 0
++ (and (eq_attr "type" "imul")
++ (and (eq_attr "mode" "DI") (eq_attr "cpu" "r10000")))
++ 10 10)
++
++(define_function_unit "alu2" 1 0
++ (and (eq_attr "type" "idiv")
++ (and (eq_attr "mode" "SI") (eq_attr "cpu" "r10000")))
++ 35 35)
++
++(define_function_unit "alu2" 1 0
++ (and (eq_attr "type" "idiv")
++ (and (eq_attr "mode" "DI") (eq_attr "cpu" "r10000")))
++ 67 67)
++
++
+ ;; The R4300 does *NOT* have a separate Floating Point Unit, instead
+ ;; the FP hardware is part of the normal ALU circuitry. This means FP
+ ;; instructions affect the pipe-line, and no functional unit
+@@ -432,11 +467,11 @@
+ ;; instructions to be processed in the "imuldiv" unit.
+
+ (define_function_unit "adder" 1 1
+- (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000"))
++ (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000,r10000"))
+ 3 0)
+
+ (define_function_unit "adder" 1 1
+- (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r3000,r3900,r6000"))
++ (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r3000,r3900,r6000,r10000"))
+ 2 0)
+
+ (define_function_unit "adder" 1 1
+@@ -444,7 +479,7 @@
+ 1 0)
+
+ (define_function_unit "adder" 1 1
+- (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r3900,r6000,r4300"))
++ (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r10000"))
+ 4 0)
+
+ (define_function_unit "adder" 1 1
+@@ -456,6 +491,10 @@
+ 3 0)
+
+ (define_function_unit "adder" 1 1
++ (and (eq_attr "type" "fadd,fmadd") (eq_attr "cpu" "r10000"))
++ 2 0)
++
++(define_function_unit "adder" 1 1
+ (and (eq_attr "type" "fabs,fneg")
+ (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4300,r5000"))
+ 2 0)
+@@ -467,7 +506,7 @@
+ (define_function_unit "mult" 1 1
+ (and (eq_attr "type" "fmul")
+ (and (eq_attr "mode" "SF")
+- (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000")))
++ (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000,r10000")))
+ 7 0)
+
+ (define_function_unit "mult" 1 1
+@@ -487,7 +526,7 @@
+
+ (define_function_unit "mult" 1 1
+ (and (eq_attr "type" "fmul")
+- (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000")))
++ (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000,r10000")))
+ 8 0)
+
+ (define_function_unit "mult" 1 1
+@@ -500,10 +539,14 @@
+ (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
+ 6 0)
+
++(define_function_unit "mult" 1 1
++ (and (eq_attr "type" "fmul,fmadd") (eq_attr "cpu" "r10000"))
++ 2 0)
++
+ (define_function_unit "divide" 1 1
+ (and (eq_attr "type" "fdiv")
+ (and (eq_attr "mode" "SF")
+- (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000")))
++ (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000,r10000")))
+ 23 0)
+
+ (define_function_unit "divide" 1 1
+@@ -529,7 +572,7 @@
+ (define_function_unit "divide" 1 1
+ (and (eq_attr "type" "fdiv")
+ (and (eq_attr "mode" "DF")
+- (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300")))
++ (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r10000")))
+ 36 0)
+
+ (define_function_unit "divide" 1 1
+@@ -547,10 +590,21 @@
+ (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
+ 61 0)
+
++;; divisions keep multiplier busy on R10000
++(define_function_unit "mult" 1 1
++ (and (eq_attr "type" "fdiv")
++ (and (eq_attr "mode" "SF") (eq_attr "cpu" "r10000")))
++ 12 14)
++
++(define_function_unit "mult" 1 1
++ (and (eq_attr "type" "fdiv")
++ (and (eq_attr "mode" "DF") (eq_attr "cpu" "r10000")))
++ 19 21)
++
+ ;;; ??? Is this number right?
+ (define_function_unit "divide" 1 1
+ (and (eq_attr "type" "fsqrt,frsqrt")
+- (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
++ (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000,r10000")))
+ 54 0)
+
+ (define_function_unit "divide" 1 1
+@@ -566,7 +620,7 @@
+ ;;; ??? Is this number right?
+ (define_function_unit "divide" 1 1
+ (and (eq_attr "type" "fsqrt,frsqrt")
+- (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
++ (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000,r10000")))
+ 112 0)
+
+ (define_function_unit "divide" 1 1
+@@ -579,6 +633,17 @@
+ (and (eq_attr "mode" "DF") (eq_attr "cpu" "r5000")))
+ 36 0)
+
++;; sqrt is executed by multiplier on R10000
++(define_function_unit "mult" 1 1
++ (and (eq_attr "type" "fsqrt")
++ (and (eq_attr "mode" "SF") (eq_attr "cpu" "r10000")))
++ 18 20)
++
++(define_function_unit "mult" 1 1
++ (and (eq_attr "type" "fsqrt")
++ (and (eq_attr "mode" "DF") (eq_attr "cpu" "r10000")))
++ 33 35)
++
+ ;; R4300 FP instruction classes treated as part of the "imuldiv"
+ ;; functional unit:
+
+@@ -3157,7 +3222,7 @@ dsrl\t%3,%3,1\n\
+ "@
+ sll\t%0,%1,0
+ sw\t%1,%0"
+- [(set_attr "type" "darith,store")
++ [(set_attr "type" "shift,store")
+ (set_attr "mode" "SI")
+ (set_attr "extended_mips16" "yes,*")])
+
+@@ -3191,7 +3256,7 @@ dsrl\t%3,%3,1\n\
+ (match_operand:DI 2 "small_int" "I"))))]
+ "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) >= 32"
+ "dsra\t%0,%1,%2"
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")])
+
+ (define_insn ""
+@@ -3200,7 +3265,7 @@ dsrl\t%3,%3,1\n\
+ (const_int 32))))]
+ "TARGET_64BIT && !TARGET_MIPS16"
+ "dsra\t%0,%1,32"
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")])
+
+
+@@ -5241,7 +5306,7 @@ dsrl\t%3,%3,1\n\
+
+ return "sll\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")])
+
+ (define_insn "ashlsi3_internal1_extend"
+@@ -5255,7 +5320,7 @@ dsrl\t%3,%3,1\n\
+
+ return "sll\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")])
+
+
+@@ -5273,7 +5338,7 @@ dsrl\t%3,%3,1\n\
+
+ return "sll\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")
+ (set_attr_alternative "length"
+ [(const_int 4)
+@@ -5374,7 +5439,7 @@ sll\t%L0,%L1,%2\n\
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+ return "sll\t%M0,%L1,%2\;move\t%L0,%.";
+ }
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+@@ -5429,7 +5494,7 @@ sll\t%L0,%L1,%2\n\
+
+ return "sll\t%M0,%M1,%2\;srl\t%3,%L1,%4\;or\t%M0,%M0,%3\;sll\t%L0,%L1,%2";
+ }
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr "length" "16")])
+
+@@ -5513,7 +5578,7 @@ sll\t%L0,%L1,%2\n\
+
+ return "dsll\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")])
+
+ (define_insn ""
+@@ -5530,7 +5595,7 @@ sll\t%L0,%L1,%2\n\
+
+ return "dsll\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr_alternative "length"
+ [(const_int 4)
+@@ -5591,7 +5656,7 @@ sll\t%L0,%L1,%2\n\
+
+ return "sra\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")])
+
+ (define_insn "ashrsi3_internal2"
+@@ -5608,7 +5673,7 @@ sll\t%L0,%L1,%2\n\
+
+ return "sra\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")
+ (set_attr_alternative "length"
+ [(const_int 4)
+@@ -5705,7 +5770,7 @@ sra\t%M0,%M1,%2\n\
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+ return "sra\t%L0,%M1,%2\;sra\t%M0,%M1,31";
+ }
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+@@ -5760,7 +5825,7 @@ sra\t%M0,%M1,%2\n\
+
+ return "srl\t%L0,%L1,%2\;sll\t%3,%M1,%4\;or\t%L0,%L0,%3\;sra\t%M0,%M1,%2";
+ }
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr "length" "16")])
+
+@@ -5844,7 +5909,7 @@ sra\t%M0,%M1,%2\n\
+
+ return "dsra\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")])
+
+ (define_insn ""
+@@ -5858,7 +5923,7 @@ sra\t%M0,%M1,%2\n\
+
+ return "dsra\t%0,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr_alternative "length"
+ [(const_int 4)
+@@ -5918,7 +5983,7 @@ sra\t%M0,%M1,%2\n\
+
+ return "srl\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")])
+
+ (define_insn "lshrsi3_internal2"
+@@ -5935,7 +6000,7 @@ sra\t%M0,%M1,%2\n\
+
+ return "srl\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")
+ (set_attr_alternative "length"
+ [(const_int 4)
+@@ -6056,7 +6121,7 @@ srl\t%M0,%M1,%2\n\
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+ return "srl\t%L0,%M1,%2\;move\t%M0,%.";
+ }
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+@@ -6111,7 +6176,7 @@ srl\t%M0,%M1,%2\n\
+
+ return "srl\t%L0,%L1,%2\;sll\t%3,%M1,%4\;or\t%L0,%L0,%3\;srl\t%M0,%M1,%2";
+ }
+- [(set_attr "type" "darith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr "length" "16")])
+
+@@ -6195,7 +6260,7 @@ srl\t%M0,%M1,%2\n\
+
+ return "dsrl\t%0,%1,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")])
+
+ (define_insn ""
+@@ -6209,7 +6274,7 @@ srl\t%M0,%M1,%2\n\
+
+ return "dsrl\t%0,%2";
+ }
+- [(set_attr "type" "arith")
++ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")
+ (set_attr_alternative "length"
+ [(const_int 4)