Created
December 24, 2025 22:12
-
-
Save uyjulian/3a2b5227440aa0e2dec17ba8d67b4047 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- gcc-2.96-20000731/gcc/config/mips/mips.c 2000-07-18 14:15:50.000000000 -0500 | |
| +++ ee/gcc/src/gcc/config/mips/mips.c 2001-04-22 19:58:34.000000000 -0500 | |
| @@ -114,6 +114,25 @@ | |
| static int symbolic_expression_p PARAMS ((rtx)); | |
| static void mips_add_gc_roots PARAMS ((void)); | |
| +/* Describe a builtin function. | |
| + Needed here so that it can be used in the protoypes below. */ | |
| +struct builtin_description | |
| +{ | |
| + enum insn_code icode; | |
| + const char *name; | |
| + enum mips_builtins code; | |
| +}; | |
| + | |
| +static rtx mips_expand_mtsax_builtin PARAMS ((struct builtin_description *, tree)); | |
| +static rtx mips_expand_shiftc_builtin PARAMS ((struct builtin_description *, tree, rtx)); | |
| +static rtx mips_expand_binop_builtin PARAMS ((struct builtin_description *, tree, rtx)); | |
| +static rtx safe_vector_operand PARAMS ((rtx, enum machine_mode)); | |
| +static void mips_r5900_lengthen_loops PARAMS ((rtx)); | |
| +static rtx mips_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx)); | |
| +static rtx mips_expand_mtspr_builtin PARAMS ((enum insn_code, tree)); | |
| +static rtx mips_expand_mfspr_builtin PARAMS ((enum insn_code, rtx)); | |
| +static void mips_check_reg_mode PARAMS ((rtx, rtx, void *)); | |
| + | |
| /* Global variables for machine-dependent things. */ | |
| /* Threshold for data being put into the small data/bss area, instead | |
| @@ -255,13 +274,17 @@ | |
| initialized in override_options. */ | |
| REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow; | |
| -/* Mode used for saving/restoring general purpose registers. */ | |
| -static enum machine_mode gpr_mode; | |
| +/* CYGNUS LOCAL: declaration of gpr_mode deleted. */ | |
| /* Array giving truth value on whether or not a given hard register | |
| can support a given mode. */ | |
| char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER]; | |
| +/* The mode that will be used to save a given gpr on the stack. Note | |
| + the entry for $0 is special; it indicates the generic size of a gpr | |
| + save/restore by the prologue/epilogue and must be the maximum mode | |
| + ever used to save a GPR. This is typically WORD_MODE. */ | |
| +enum machine_mode mips_reg_mode[GP_REG_NUM]; | |
| /* Current frame information calculated by compute_frame_size. */ | |
| struct mips_frame_info current_frame_info; | |
| @@ -323,6 +346,7 @@ | |
| "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", | |
| "hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", | |
| "$fcc5","$fcc6","$fcc7","$rap" | |
| + , "hi1", "lo1", "accum1" | |
| }; | |
| /* Mips software names for the registers, used to overwrite the | |
| @@ -340,6 +364,7 @@ | |
| "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", | |
| "hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", | |
| "$fcc5","$fcc6","$fcc7","$rap" | |
| + , "hi1", "lo1", "accum1" | |
| }; | |
| /* Map hard register number to register class */ | |
| @@ -352,7 +377,7 @@ | |
| M16_NA_REGS, M16_NA_REGS, GR_REGS, GR_REGS, | |
| GR_REGS, GR_REGS, GR_REGS, GR_REGS, | |
| T_REG, GR_REGS, GR_REGS, GR_REGS, | |
| - GR_REGS, GR_REGS, GR_REGS, GR_REGS, | |
| + GR_REGS, GR_REGS, GR_REGS, ARGP_REGS, | |
| FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
| FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
| FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
| @@ -363,7 +388,8 @@ | |
| FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
| HI_REG, LO_REG, HILO_REG, ST_REGS, | |
| ST_REGS, ST_REGS, ST_REGS, ST_REGS, | |
| - ST_REGS, ST_REGS, ST_REGS, GR_REGS | |
| + ST_REGS, ST_REGS, ST_REGS, ARGP_REGS, | |
| + HI1_REG, LO1_REG, HILO1_REG | |
| }; | |
| /* Map register constraint character to register class. */ | |
| @@ -554,6 +580,37 @@ | |
| return 0; | |
| } | |
| +/* Return truth value of whether OP is a register, a memory operand, | |
| + or a constant. This is used by the r5900 lq/sq support. */ | |
| + | |
| +int | |
| +movti_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + switch (GET_CODE (op)) | |
| + { | |
| + case CONST_INT: | |
| + if (TARGET_MIPS16) | |
| + return FALSE; | |
| + return TRUE; | |
| + | |
| + case CONST_DOUBLE: | |
| + if (TARGET_MIPS16 || GET_MODE (op) != VOIDmode) | |
| + return FALSE; | |
| + return TRUE; | |
| + | |
| + case REG: | |
| + case SUBREG: | |
| + return register_operand (op, mode); | |
| + | |
| + case MEM: | |
| + return memory_operand (op, mode); | |
| + | |
| + default: | |
| + return FALSE; | |
| + } | |
| +} | |
| /* Return truth value of whether OP is a register or the constant 0, | |
| even in mips16 mode. */ | |
| @@ -692,7 +749,7 @@ | |
| off = 0x100; | |
| else | |
| off = 0x20; | |
| - if (INTVAL (offset) >= 0 && INTVAL (offset) < off * size) | |
| + if (INTVAL (offset) >= 0 && INTVAL (offset) < (HOST_WIDE_INT)(off * size)) | |
| return 1; | |
| return 0; | |
| } | |
| @@ -715,7 +772,7 @@ | |
| /* ??? This isn't strictly correct. It is OK to accept multiword modes | |
| here, since the length attributes are being set correctly, but only | |
| if the address is offsettable. LO_SUM is not offsettable. */ | |
| - if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD) | |
| + if (GET_MODE_SIZE (GET_MODE (op)) > (unsigned) UNITS_PER_WORD) | |
| return 0; | |
| /* Decode the address now. */ | |
| @@ -777,6 +834,15 @@ | |
| /* fall through */ | |
| + /* The symbol_ref_5900 stuff was done as part of the 5900 | |
| + enhancement project. | |
| + | |
| + By #if 0-ing the SYMBOL_REF case out here, the compiler doesn't | |
| + notice that GP relative references are only one insn long, and | |
| + won't put then in delay slots. I've moved the SYMBOL_REF case | |
| + back out of the #if 0. I believe the PIC case is now handled | |
| + by the compiler, and I'd rather find and fix the G++ problem. */ | |
| + | |
| case SYMBOL_REF: | |
| return SYMBOL_REF_FLAG (addr); | |
| #endif | |
| @@ -784,6 +850,11 @@ | |
| /* This SYMBOL_REF case is for the mips16. If the above case is | |
| reenabled, this one should be merged in. */ | |
| case SYMBOL_REF: | |
| + /* If the symbol is going to referenced using GP relative addressing | |
| + then it is a simple_memory_operand. SYMBOL_REF_FLAG is used for | |
| + a number of things, as descibed near ENCODE_SECTION_INFO in mips.h. */ | |
| + if (!TARGET_MIPS16 && !TARGET_EMBEDDED_DATA && !TARGET_EMBEDDED_PIC) | |
| + return SYMBOL_REF_FLAG (addr); | |
| /* References to the constant pool on the mips16 use a small | |
| offset if the function is small. The only time we care about | |
| getting this right is during delayed branch scheduling, so | |
| @@ -868,7 +939,7 @@ | |
| address will get reloaded anyhow. */ | |
| if (GET_CODE (addr) == PLUS | |
| && GET_CODE (XEXP (addr, 0)) == REG | |
| - && (REGNO (XEXP (addr, 0)) == HARD_FRAME_POINTER_REGNUM | |
| + && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM | |
| || REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM) | |
| && ((GET_CODE (XEXP (addr, 1)) == CONST_INT | |
| && ! SMALL_INT (XEXP (addr, 1))) | |
| @@ -885,7 +956,7 @@ | |
| maddr = XEXP (addr, 0); | |
| if (GET_CODE (maddr) == PLUS | |
| && GET_CODE (XEXP (maddr, 0)) == REG | |
| - && (REGNO (XEXP (maddr, 0)) == HARD_FRAME_POINTER_REGNUM | |
| + && (REGNO (XEXP (maddr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM | |
| || REGNO (XEXP (maddr, 0)) == STACK_POINTER_REGNUM) | |
| && ((GET_CODE (XEXP (maddr, 1)) == CONST_INT | |
| && ! SMALL_INT (XEXP (maddr, 1))) | |
| @@ -905,7 +976,7 @@ | |
| addr = XEXP (XEXP (addr, 0), 0); | |
| if (GET_CODE (addr) == PLUS | |
| && GET_CODE (XEXP (addr, 0)) == REG | |
| - && (REGNO (XEXP (addr, 0)) == HARD_FRAME_POINTER_REGNUM | |
| + && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM | |
| || REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM) | |
| && ((GET_CODE (XEXP (addr, 1)) == CONST_INT | |
| && ! SMALL_INT (XEXP (addr, 1))) | |
| @@ -1176,6 +1247,80 @@ | |
| return CONSTANT_P (op); | |
| } | |
| +/* Return truth value of whether OP is a register, a memory operand, | |
| + or a constant. This is used by the r5900 lq/sq support. */ | |
| + | |
| +int | |
| +vector_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + switch (GET_CODE (op)) | |
| + { | |
| + case CONST_INT: | |
| + return TARGET_MIPS5900; | |
| + | |
| + case CONST_DOUBLE: | |
| + return TARGET_MIPS5900; | |
| + | |
| + case REG: | |
| + case SUBREG: | |
| + return register_operand (op, mode); | |
| + | |
| + case MEM: | |
| + return memory_operand (op, mode); | |
| + | |
| + default: | |
| + return FALSE; | |
| + } | |
| +} | |
| + | |
| +int | |
| +movv16qi_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + return vector_operand (op, mode); | |
| +} | |
| + | |
| +int | |
| +movv8hi_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + return vector_operand (op, mode); | |
| +} | |
| + | |
| +int | |
| +movv4si_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + return vector_operand (op, mode); | |
| +} | |
| + | |
| +int | |
| +movv2di_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + return vector_operand (op, mode); | |
| +} | |
| + | |
| +int | |
| +movv2si_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + return vector_operand (op, mode); | |
| +} | |
| + | |
| +int register_or_int_operand (op, mode) | |
| + rtx op; | |
| + enum machine_mode mode; | |
| +{ | |
| + return const_int_operand (op, mode) || register_operand (op, mode); | |
| +} | |
| /* Return nonzero if we split the address into high and low parts. */ | |
| /* ??? We should also handle reg+array somewhere. We get four | |
| @@ -1199,7 +1344,7 @@ | |
| { | |
| /* ??? This is the same check used in simple_memory_operand. | |
| We use it here because LO_SUM is not offsettable. */ | |
| - if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) | |
| + if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD) | |
| return 0; | |
| if ((GET_CODE (address) == SYMBOL_REF && ! SYMBOL_REF_FLAG (address)) | |
| @@ -1247,6 +1392,8 @@ | |
| accept (subreg (const_int)) which will fail to reload. */ | |
| if (CONSTANT_ADDRESS_P (xinsn) | |
| && ! (mips_split_addresses && mips_check_split (xinsn, mode)) | |
| + && ! (TARGET_MIPS5900 && mode == TImode) | |
| + && ! (SIMD_MODE_SUPPORTED_P (mode)) | |
| && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0))) | |
| return 1; | |
| @@ -1325,11 +1472,16 @@ | |
| || mips_abi == ABI_O64 | |
| || mips_abi == ABI_EABI) | |
| && CONSTANT_ADDRESS_P (xplus1) | |
| - && ! mips_split_addresses | |
| + && ! (mips_split_addresses && mips_check_split (xinsn, mode)) | |
| && (!TARGET_EMBEDDED_PIC | |
| || code1 != CONST | |
| || GET_CODE (XEXP (xplus1, 0)) != MINUS) | |
| - && !TARGET_MIPS16) | |
| + /* When assembling for machines with 64 bit registers, | |
| + the assembler will not sign-extend the constant "foo" | |
| + in "la x, foo(x)" */ | |
| + && (!TARGET_64BIT || (INTVAL (xplus1) > 0)) | |
| + && !TARGET_MIPS16 | |
| + && !(TARGET_MIPS5900 && mode == TImode)) | |
| return 1; | |
| } | |
| } | |
| @@ -1578,6 +1730,8 @@ | |
| else if (type == DELAY_HILO) | |
| num_nops = 2; | |
| + else if (type == DELAY_HILO1) | |
| + num_nops = 2; | |
| else | |
| num_nops = 0; | |
| @@ -1615,7 +1769,7 @@ | |
| dslots_number_nops = num_nops; | |
| mips_load_reg = set_reg; | |
| if (GET_MODE_SIZE (mode) | |
| - > (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD)) | |
| + > (unsigned) (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD)) | |
| mips_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1); | |
| else | |
| mips_load_reg2 = 0; | |
| @@ -1625,6 +1779,11 @@ | |
| mips_load_reg3 = gen_rtx_REG (SImode, MD_REG_FIRST); | |
| mips_load_reg4 = gen_rtx_REG (SImode, MD_REG_FIRST+1); | |
| } | |
| + else if (type == DELAY_HILO1) | |
| + { | |
| + mips_load_reg3 = gen_rtx_REG (SImode, MD1_REG_FIRST); | |
| + mips_load_reg4 = gen_rtx_REG (SImode, MD1_REG_FIRST+1); | |
| + } | |
| else | |
| { | |
| mips_load_reg3 = 0; | |
| @@ -1853,6 +2012,14 @@ | |
| ret = "mflo\t%0"; | |
| } | |
| + else if (MD1_REG_P (regno1)) | |
| + { | |
| + delay = DELAY_HILO1; | |
| + if (regno1 != HILO1_REGNUM) | |
| + ret = "mf%1\t%0"; | |
| + else | |
| + ret = "mflo1\t%0"; | |
| + } | |
| else if (ST_REG_P (regno1) && ISA_HAS_8CC) | |
| ret = "li\t%0,1\n\tmovf\t%0,%.,%1"; | |
| @@ -1889,6 +2056,15 @@ | |
| } | |
| } | |
| + else if (MD1_REG_P (regno0)) | |
| + { | |
| + if (GP_REG_P (regno1)) | |
| + { | |
| + delay = DELAY_HILO1; | |
| + if (regno0 != HILO1_REGNUM && ! TARGET_MIPS16) | |
| + ret = "mt%0\t%1"; | |
| + } | |
| + } | |
| else if (regno0 == FPSW_REGNUM && ! ISA_HAS_8CC) | |
| { | |
| if (GP_REG_P (regno1)) | |
| @@ -1974,6 +2150,11 @@ | |
| delay = DELAY_HILO; | |
| ret = "mt%0\t%."; | |
| } | |
| + else if (MD1_REG_P (regno0)) | |
| + { | |
| + delay = DELAY_HILO1; | |
| + ret = "mt%0\t%."; | |
| + } | |
| } | |
| else if (GP_REG_P (regno0)) | |
| @@ -2302,6 +2483,19 @@ | |
| ret = "mthi\t%M1\n\tmtlo\t%L1"; | |
| } | |
| + else if (MD1_REG_P (regno0) && GP_REG_P (regno1) && !TARGET_MIPS16) | |
| + { | |
| + delay = DELAY_HILO1; | |
| + if (TARGET_64BIT) | |
| + { | |
| + if (regno0 != HILO1_REGNUM) | |
| + ret = "mt%0\t%1"; | |
| + else if (regno1 == 0) | |
| + ret = "mtlo%H0\t%.\n\tmthi%H0\t%."; | |
| + } | |
| + else | |
| + ret = "mthi%H0\t%M1\n\tmtlo%H0\t%L1"; | |
| + } | |
| else if (GP_REG_P (regno0) && MD_REG_P (regno1)) | |
| { | |
| delay = DELAY_HILO; | |
| @@ -2314,6 +2508,17 @@ | |
| ret = "mfhi\t%M0\n\tmflo\t%L0"; | |
| } | |
| + else if (GP_REG_P (regno0) && MD1_REG_P (regno1)) | |
| + { | |
| + delay = DELAY_HILO1; | |
| + if (TARGET_64BIT) | |
| + { | |
| + if (regno1 != HILO1_REGNUM) | |
| + ret = "mf%1\t%0"; | |
| + } | |
| + else | |
| + ret = "mfhi%H1\t%M0\n\tmflo%H1\t%L0"; | |
| + } | |
| else if (TARGET_64BIT) | |
| ret = "move\t%0,%1"; | |
| @@ -2419,6 +2624,13 @@ | |
| ? "mtlo\t%.\n\tmthi\t%." | |
| : "mt%0\t%.\n"); | |
| } | |
| + else if (MD1_REG_P (regno0)) | |
| + { | |
| + delay = DELAY_HILO1; | |
| + ret = (regno0 == HILO1_REGNUM | |
| + ? "mtlo%H0\t%.\n\tmthi%H0\t%." | |
| + : "mt%0\t%.\n"); | |
| + } | |
| } | |
| else if (code1 == CONST_INT && GET_MODE (op0) == DImode | |
| @@ -3179,7 +3391,7 @@ | |
| rtx bytes_rtx; | |
| int leftover; | |
| - if (bytes < 2 * MAX_MOVE_BYTES) | |
| + if (bytes < (unsigned)2 * MAX_MOVE_BYTES) | |
| abort (); | |
| leftover = bytes % MAX_MOVE_BYTES; | |
| @@ -3246,7 +3458,7 @@ | |
| /* We want to pass the size as Pmode, which will normally be SImode | |
| but will be DImode if we are using 64 bit longs and pointers. */ | |
| if (GET_MODE (bytes_rtx) != VOIDmode | |
| - && GET_MODE (bytes_rtx) != Pmode) | |
| + && GET_MODE (bytes_rtx) != (unsigned) Pmode) | |
| bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1); | |
| #ifdef TARGET_MEM_FUNCTIONS | |
| @@ -3288,7 +3500,7 @@ | |
| if (constp && bytes == 0) | |
| return; | |
| - if (align > UNITS_PER_WORD) | |
| + if (align > (unsigned) UNITS_PER_WORD) | |
| align = UNITS_PER_WORD; | |
| /* Move the address into scratch registers. */ | |
| @@ -3298,18 +3510,18 @@ | |
| if (TARGET_MEMCPY) | |
| block_move_call (dest_reg, src_reg, bytes_rtx); | |
| - else if (constp && bytes <= 2 * MAX_MOVE_BYTES | |
| - && align == UNITS_PER_WORD) | |
| + else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES | |
| + && align == (unsigned) UNITS_PER_WORD) | |
| move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD); | |
| - else if (constp && bytes <= 2 * MAX_MOVE_BYTES) | |
| + else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES) | |
| emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode, | |
| dest_reg), | |
| change_address (orig_src, BLKmode, | |
| src_reg), | |
| bytes_rtx, align_rtx)); | |
| - else if (constp && align >= UNITS_PER_WORD && optimize) | |
| + else if (constp && align >= (unsigned) UNITS_PER_WORD && optimize) | |
| block_move_loop (dest_reg, src_reg, bytes, align, orig_dest, orig_src); | |
| else if (constp && optimize) | |
| @@ -3782,7 +3994,7 @@ | |
| "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, ", | |
| cum->gp_reg_found, cum->arg_number, cum->arg_words, | |
| GET_MODE_NAME (mode)); | |
| - fprintf (stderr, HOST_PTR_PRINTF, type); | |
| + fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type); | |
| fprintf (stderr, ", %d )\n\n", named); | |
| } | |
| @@ -3793,6 +4005,15 @@ | |
| break; | |
| default: | |
| + /* The r5900 only needs a single general register to pass a | |
| + SIMD vector mode. It should be impossible to reach this code | |
| + with any other port, so abort if it happens. */ | |
| + if (SIMD_MODE_SUPPORTED_P (mode)) | |
| + { | |
| + cum->gp_reg_found = 1; | |
| + cum->arg_words += 1; | |
| + break; | |
| + } | |
| if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT | |
| && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) | |
| abort (); | |
| @@ -3831,6 +4052,15 @@ | |
| cum->arg_words += (TARGET_64BIT ? 1 : 2); | |
| break; | |
| + /* The r5900 only needs a single general register to pass a | |
| + TImode value. It should be impossible to reach this code | |
| + with any other port, so abort if it happens. */ | |
| + case TImode: | |
| + if (!TARGET_MIPS5900) | |
| + abort (); | |
| + cum->gp_reg_found = 1; | |
| + cum->arg_words += 1; | |
| + break; | |
| case QImode: | |
| case HImode: | |
| case SImode: | |
| @@ -3853,7 +4083,7 @@ | |
| rtx ret; | |
| int regbase = -1; | |
| int bias = 0; | |
| - int *arg_words = &cum->arg_words; | |
| + unsigned int *arg_words = &cum->arg_words; | |
| int struct_p = (type != 0 | |
| && (TREE_CODE (type) == RECORD_TYPE | |
| || TREE_CODE (type) == UNION_TYPE | |
| @@ -3865,7 +4095,7 @@ | |
| "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, ", | |
| cum->gp_reg_found, cum->arg_number, cum->arg_words, | |
| GET_MODE_NAME (mode)); | |
| - fprintf (stderr, HOST_PTR_PRINTF, type); | |
| + fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type); | |
| fprintf (stderr, ", %d ) = ", named); | |
| } | |
| @@ -3928,13 +4158,21 @@ | |
| break; | |
| default: | |
| + /* The r5900 only needs a single general register to pass a | |
| + SIMD vector mode. It should be impossible to reach this code | |
| + with any other port, so abort if it happens. */ | |
| + if (SIMD_MODE_SUPPORTED_P (mode)) | |
| + { | |
| + regbase = GP_ARG_FIRST; | |
| + break; | |
| + } | |
| if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT | |
| && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) | |
| abort (); | |
| /* Drops through. */ | |
| case BLKmode: | |
| - if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD | |
| + if (type != NULL_TREE && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD | |
| && ! TARGET_64BIT && mips_abi != ABI_EABI) | |
| cum->arg_words += (cum->arg_words & 1); | |
| regbase = GP_ARG_FIRST; | |
| @@ -3947,13 +4185,21 @@ | |
| regbase = GP_ARG_FIRST; | |
| break; | |
| + /* The r5900 only needs a single general register to pass a | |
| + TImode value. It should be impossible to reach this code | |
| + with any other port, so abort if it happens. */ | |
| + case TImode: | |
| + if (!TARGET_MIPS5900) | |
| + abort (); | |
| + regbase = GP_ARG_FIRST; | |
| + break; | |
| case DImode: | |
| if (! TARGET_64BIT) | |
| cum->arg_words += (cum->arg_words & 1); | |
| regbase = GP_ARG_FIRST; | |
| } | |
| - if (*arg_words >= MAX_ARGS_IN_REGISTERS) | |
| + if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS) | |
| { | |
| if (TARGET_DEBUG_E_MODE) | |
| fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : ""); | |
| @@ -4003,7 +4249,7 @@ | |
| chunks | |
| = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD; | |
| - if (chunks + *arg_words + bias > MAX_ARGS_IN_REGISTERS) | |
| + if (chunks + *arg_words + bias > (unsigned) MAX_ARGS_IN_REGISTERS) | |
| chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias; | |
| /* assign_parms checks the mode of ENTRY_PARM, so we must | |
| @@ -4026,7 +4272,9 @@ | |
| && int_bit_position (field) == bitpos | |
| && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE | |
| && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD) | |
| - reg = gen_rtx_REG (DFmode, | |
| + reg = gen_rtx_REG ( | |
| + DFmode | |
| + , | |
| regno + FP_ARG_FIRST - GP_ARG_FIRST); | |
| else | |
| reg = gen_rtx_REG (word_mode, regno); | |
| @@ -4035,7 +4283,7 @@ | |
| = gen_rtx_EXPR_LIST (VOIDmode, reg, | |
| GEN_INT (bitpos / BITS_PER_UNIT)); | |
| - bitpos += 64; | |
| + bitpos += BITS_PER_WORD; /* CYGNUS LOCAL gavin */ | |
| regno++; | |
| } | |
| } | |
| @@ -4104,9 +4352,11 @@ | |
| int named ATTRIBUTE_UNUSED;/* != 0 for normal args, == 0 for ... args */ | |
| { | |
| if ((mode == BLKmode | |
| + || (mode == TImode && TARGET_MIPS5900) | |
| + || SIMD_MODE_SUPPORTED_P (mode) | |
| || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT | |
| || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) | |
| - && cum->arg_words < MAX_ARGS_IN_REGISTERS | |
| + && cum->arg_words < (unsigned) MAX_ARGS_IN_REGISTERS | |
| && mips_abi != ABI_EABI) | |
| { | |
| int words; | |
| @@ -4116,7 +4366,7 @@ | |
| else | |
| words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; | |
| - if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS) | |
| + if (words + cum->arg_words <= (unsigned) MAX_ARGS_IN_REGISTERS) | |
| return 0; /* structure fits in registers */ | |
| if (TARGET_DEBUG_E_MODE) | |
| @@ -4126,7 +4376,8 @@ | |
| return MAX_ARGS_IN_REGISTERS - cum->arg_words; | |
| } | |
| - else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1 | |
| + else if (mode == DImode | |
| + && cum->arg_words == MAX_ARGS_IN_REGISTERS - (unsigned)1 | |
| && ! TARGET_64BIT && mips_abi != ABI_EABI) | |
| { | |
| if (TARGET_DEBUG_E_MODE) | |
| @@ -4386,7 +4637,10 @@ | |
| indirect | |
| = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0); | |
| if (indirect) | |
| - size = rsize = POINTER_SIZE / BITS_PER_UNIT; | |
| + { | |
| + size = POINTER_SIZE / BITS_PER_UNIT; | |
| + rsize = UNITS_PER_WORD; | |
| + } | |
| addr_rtx = gen_reg_rtx (Pmode); | |
| @@ -4623,6 +4877,20 @@ | |
| mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE; | |
| +#ifndef MIPS_DISABLE_GPOPT | |
| +#define MIPS_DISABLE_GPOPT 0 | |
| +#endif | |
| + | |
| + if (MIPS_DISABLE_GPOPT) | |
| + { | |
| + if (mips_section_threshold != 0) | |
| + { | |
| + error ("-G not supported in this configuration."); | |
| + mips_section_threshold = 0; | |
| + } | |
| + target_flags &= ~MASK_GPOPT; | |
| + } | |
| + else | |
| if (mips_section_threshold <= 0) | |
| target_flags &= ~MASK_GPOPT; | |
| else if (optimize) | |
| @@ -4634,7 +4902,7 @@ | |
| user. */ | |
| #ifdef TARGET_DEFAULT | |
| if (TARGET_SINGLE_FLOAT && TARGET_SOFT_FLOAT) | |
| - target_flags &= ~(TARGET_DEFAULT&(MASK_SOFT_FLOAT|MASK_SINGLE_FLOAT)); | |
| + target_flags &= ~((TARGET_DEFAULT) & (MASK_SOFT_FLOAT | MASK_SINGLE_FLOAT)); | |
| #endif | |
| /* Get the architectural level. */ | |
| @@ -4673,6 +4941,9 @@ | |
| mips_isa = 1; | |
| } | |
| + if (!TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG) | |
| + error ("-mhandle-ee-div-pipeline-bug is not supported."); | |
| + | |
| #ifdef MIPS_ABI_DEFAULT | |
| /* Get the ABI to use. */ | |
| if (mips_abi_string == (char *) 0) | |
| @@ -4733,9 +5004,14 @@ | |
| || mips_abi == ABI_64)) | |
| target_flags |= MASK_LONG64; | |
| - /* ??? This doesn't work yet, so don't let people try to use it. */ | |
| + /* CYGNUS LOCAL vr4111/gavin */ | |
| +#ifndef MIPS_ENABLE_EMBEDDED_O32 | |
| + /* ??? The native version of this have not been well tested; | |
| + enable O32 only for specific embedded targets. */ | |
| if (mips_abi == ABI_32) | |
| error ("The -mabi=32 support does not work yet."); | |
| +#endif | |
| + /* END CYGNUS LOCAL vr4111/gavin */ | |
| #else | |
| if (mips_abi_string) | |
| @@ -4751,10 +5027,10 @@ | |
| mips_cpu_string = MIPS_CPU_STRING_DEFAULT; | |
| #endif | |
| - /* Identify the processor type */ | |
| + /* Identify the processor type. */ | |
| if (mips_cpu_string == 0 | |
| - || !strcmp (mips_cpu_string, "default") | |
| - || !strcmp (mips_cpu_string, "DEFAULT")) | |
| + || ! strcmp (mips_cpu_string, "default") | |
| + || ! strcmp (mips_cpu_string, "DEFAULT")) | |
| { | |
| switch (mips_isa) | |
| { | |
| @@ -4776,7 +5052,6 @@ | |
| break; | |
| } | |
| } | |
| - | |
| else | |
| { | |
| const char *p = mips_cpu_string; | |
| @@ -4818,6 +5093,11 @@ | |
| mips_cpu = PROCESSOR_R4100; | |
| target_flags |= MASK_SOFT_FLOAT ; | |
| } | |
| + else if (!strcmp (p, "4111")) | |
| + { | |
| + mips_cpu = PROCESSOR_R4100; | |
| + target_flags |= MASK_SOFT_FLOAT ; | |
| + } | |
| /* The vr4300 is a standard ISA III processor, but with a different | |
| pipeline. */ | |
| else if (!strcmp (p, "4300")) | |
| @@ -4835,6 +5115,10 @@ | |
| case '5': | |
| if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K")) | |
| mips_cpu = PROCESSOR_R5000; | |
| + else if (!strcmp (p, "5400")) | |
| + mips_cpu = PROCESSOR_R5400; | |
| + else if (!strcmp (p, "5900")) | |
| + mips_cpu = PROCESSOR_R5900; | |
| break; | |
| case '6': | |
| @@ -4851,11 +5135,28 @@ | |
| if (!strcmp (p, "orion")) | |
| mips_cpu = PROCESSOR_R4600; | |
| break; | |
| + case 'm': | |
| + case 'M': | |
| + switch (atoi (p + 1)) | |
| + { | |
| + case 5200: | |
| + case 5230: | |
| + case 5231: | |
| + case 5261: | |
| + case 5721: | |
| + case 7000: | |
| + target_flags |= MASK_MAD; | |
| + mips_cpu = PROCESSOR_R5000; | |
| + break; | |
| + default: | |
| + break; | |
| + } | |
| } | |
| if (seen_v | |
| && mips_cpu != PROCESSOR_R4300 | |
| && mips_cpu != PROCESSOR_R4100 | |
| + && mips_cpu != PROCESSOR_R5400 | |
| && mips_cpu != PROCESSOR_R5000) | |
| mips_cpu = PROCESSOR_DEFAULT; | |
| @@ -5024,9 +5325,14 @@ | |
| mips_char_to_class['l'] = LO_REG; | |
| mips_char_to_class['a'] = HILO_REG; | |
| mips_char_to_class['x'] = MD_REGS; | |
| + mips_char_to_class['u'] = HI1_REG; | |
| + mips_char_to_class['v'] = LO1_REG; | |
| + mips_char_to_class['q'] = HILO1_REG; | |
| + mips_char_to_class['w'] = MD1_REGS; | |
| mips_char_to_class['b'] = ALL_REGS; | |
| mips_char_to_class['y'] = GR_REGS; | |
| mips_char_to_class['z'] = ST_REGS; | |
| + mips_char_to_class['A'] = ARGP_REGS; | |
| /* Set up array to map GCC register number to debug register number. | |
| Ignore the special purpose register numbers. */ | |
| @@ -5069,11 +5375,22 @@ | |
| || FP_REG_P (regno)); | |
| } | |
| + /* The general registers can hold 128-bit integer and vector | |
| + integer values on the r5900. So can HI and LO. */ | |
| + else if ((GP_REG_P (regno) || MD_REG_P (regno)) | |
| + && (class == MODE_INT || class == MODE_VECTOR_INT) | |
| + && size <= UNITS_PER_WORD * 2 | |
| + && TARGET_MIPS5900) | |
| + temp = 1; | |
| + /* General registers can hold SIMD vector mode values. */ | |
| + else if (GP_REG_P (regno) && SIMD_MODE_SUPPORTED_P (mode)) | |
| + temp = 1; | |
| else if (GP_REG_P (regno)) | |
| temp = ((regno & 1) == 0 || size <= UNITS_PER_WORD); | |
| else if (FP_REG_P (regno)) | |
| - temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)) | |
| + temp = ((TARGET_FLOAT64 || ((regno & 1) == 0) | |
| + ) | |
| && (class == MODE_FLOAT | |
| || class == MODE_COMPLEX_FLOAT | |
| || (TARGET_DEBUG_H_MODE && class == MODE_INT)) | |
| @@ -5085,6 +5402,12 @@ | |
| || (regno == MD_REG_FIRST | |
| && size == 2 * UNITS_PER_WORD))); | |
| + else if (MD1_REG_P (regno)) | |
| + temp = (class == MODE_INT | |
| + && (size <= UNITS_PER_WORD | |
| + || (regno == MD1_REG_FIRST | |
| + && size == 2 * UNITS_PER_WORD))) | |
| + || TARGET_SIMD; | |
| else | |
| temp = 0; | |
| @@ -5094,8 +5417,15 @@ | |
| /* Save GPR registers in word_mode sized hunks. word_mode hasn't been | |
| initialized yet, so we can't use that here. */ | |
| - gpr_mode = TARGET_64BIT ? DImode : SImode; | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) | |
| + mips_reg_mode[regno] = TARGET_64BIT ? DImode : SImode; | |
| + /* Saves/restores of general purpose registers on the r5900 use | |
| + a mode wider than word_mode. */ | |
| + if (TARGET_MIPS5900) | |
| + mips_reg_mode[0] = TImode; | |
| + /* END CYGNUS LOCAL */ | |
| /* Provide default values for align_* for 64-bit targets. */ | |
| if (TARGET_64BIT && !TARGET_MIPS16) | |
| { | |
| @@ -5157,7 +5487,7 @@ | |
| if (reg == stack_pointer_rtx || reg == frame_pointer_rtx | |
| || reg == hard_frame_pointer_rtx) | |
| { | |
| - HOST_WIDE_INT frame_size = (!current_frame_info.initialized) | |
| + HOST_WIDE_INT frame_size = (current_frame_info.state != fi_initialized) | |
| ? compute_frame_size (get_frame_size ()) | |
| : current_frame_info.total_size; | |
| @@ -5397,6 +5727,15 @@ | |
| default: | |
| abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%C"); | |
| } | |
| + else if (letter == 'H') | |
| + { | |
| + if (true_regnum (op) >= MD_REG_FIRST | |
| + && true_regnum (op) <= MD_REG_LAST) | |
| + ; | |
| + else if (true_regnum (op) >= MD1_REG_FIRST | |
| + && true_regnum (op) <= MD1_REG_LAST) | |
| + fputs ("1", file); | |
| + } | |
| else if (letter == 'N') | |
| switch (code) | |
| @@ -5455,6 +5794,15 @@ | |
| if (regnum != ST_REG_FIRST) | |
| fprintf (file, "%s,", reg_names[regnum]); | |
| } | |
| + else if ((letter == 'L' || letter == 'M') | |
| + && code == CONST_DOUBLE | |
| + && GET_MODE (op) == VOIDmode) | |
| + { | |
| + if (letter == 'L') | |
| + fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (op)); | |
| + else | |
| + fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_HIGH (op)); | |
| + } | |
| else if (code == REG || code == SUBREG) | |
| { | |
| @@ -5904,6 +6252,8 @@ | |
| mips_asm_file_start (stream) | |
| FILE *stream; | |
| { | |
| + const char * abi_string = NULL; | |
| + | |
| ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename); | |
| /* Versions of the MIPS assembler before 2.20 generate errors if a branch | |
| @@ -5914,6 +6264,32 @@ | |
| if (TARGET_MIPS_AS && optimize && flag_delayed_branch) | |
| fprintf (stream, "\t.set\tnobopt\n"); | |
| +#ifdef OBJECT_FORMAT_ELF | |
| + /* Generate a special section to describe the ABI switches used to produce | |
| + the resultant binary. This used to be done by the assembler setting bits | |
| + in the ELF header's flags field, but we have run out of bits. GDB needs | |
| + this information in order to be able to correctly debug these binaries. | |
| + See the function mips_gdbarch_init() in gdb/mips-tdep.c. */ | |
| + switch (mips_abi) | |
| + { | |
| + case ABI_32: abi_string = "abi32"; break; | |
| + case ABI_N32: abi_string = "abiN32"; break; | |
| + case ABI_64: abi_string = "abi64"; break; | |
| + case ABI_O64: abi_string = "abiO64"; break; | |
| + case ABI_EABI: abi_string = TARGET_64BIT ? "eabi64" : "eabi32"; break; | |
| + default: | |
| + abort (); | |
| + } | |
| + /* Note - we use fprintf directly rather than called named_section() | |
| + because in this way we can avoid creating an allocated section. We | |
| + do not want this section to take up any space in the running | |
| + executable. */ | |
| + fprintf (stream, "\t.section .mdebug.%s\n", abi_string); | |
| + | |
| + /* Restore the default section. */ | |
| + fprintf (stream, "\t.previous\n"); | |
| +#endif | |
| + | |
| /* Generate the pseudo ops that System V.4 wants. */ | |
| #ifndef ABICALLS_ASM_OP | |
| #define ABICALLS_ASM_OP ".abicalls" | |
| @@ -6138,13 +6514,19 @@ | |
| HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up */ | |
| HOST_WIDE_INT extra_size; /* # extra bytes */ | |
| HOST_WIDE_INT gp_reg_rounded; /* # bytes needed to store gp after rounding */ | |
| - HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs */ | |
| + HOST_WIDE_INT gp_quad_size; /* # bytes needed to store 128 bit gp regs */ | |
| + HOST_WIDE_INT gp_reg_size; /* # total bytes needed to store gp regs */ | |
| HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs */ | |
| long mask; /* mask of saved gp registers */ | |
| long fmask; /* mask of saved fp registers */ | |
| int fp_inc; /* 1 or 2 depending on the size of fp regs */ | |
| long fp_bits; /* bitmask to use for each fp register */ | |
| + int num_gp = 0; | |
| + | |
| + /* If we are called before reload, mips_reg_mode isn't final. */ | |
| + int tentative = current_frame_info.state < fi_modes_known; | |
| + gp_quad_size = 0; | |
| gp_reg_size = 0; | |
| fp_reg_size = 0; | |
| mask = 0; | |
| @@ -6187,20 +6569,26 @@ | |
| || (GET_MODE_SIZE (DECL_MODE (DECL_RESULT (current_function_decl))) | |
| <= 4)))) | |
| { | |
| - gp_reg_size += GET_MODE_SIZE (gpr_mode); | |
| + int this_size = GET_MODE_SIZE (tentative ? TImode : mips_reg_mode[regno]); | |
| + | |
| + gp_reg_size += this_size; | |
| + if (this_size == 16) | |
| + gp_quad_size += this_size; | |
| mask |= 1L << (regno - GP_REG_FIRST); | |
| + num_gp++; | |
| + } | |
| + } | |
| /* The entry and exit pseudo instructions can not save $17 | |
| without also saving $16. */ | |
| if (mips_entry | |
| - && regno == GP_REG_FIRST + 17 | |
| + && MUST_SAVE_REGISTER (GP_REG_FIRST + 17) | |
| && ! MUST_SAVE_REGISTER (GP_REG_FIRST + 16)) | |
| { | |
| + /* This is only for mips16, so we 'know' the register size. */ | |
| gp_reg_size += UNITS_PER_WORD; | |
| mask |= 1L << 16; | |
| } | |
| - } | |
| - } | |
| /* Calculate space needed for fp registers. */ | |
| if (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT) | |
| @@ -6228,7 +6616,13 @@ | |
| } | |
| gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); | |
| - total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size); | |
| + | |
| + /* On the 5900, gp registers are already 8 byte aligned, plenty for fp | |
| + registers. MIPS_STACK_ALIGN would force 16 byte alignment, often | |
| + wasting 8 bytes stack space. */ | |
| + if (TARGET_MIPS5900) | |
| + gp_reg_rounded = gp_reg_size; | |
| + total_size += MIPS_STACK_ALIGN (gp_reg_rounded + fp_reg_size); | |
| /* The gp reg is caller saved in the 32 bit ABI, so there is no need | |
| for leaf routines (total_size == extra_size) to save the gp reg. | |
| @@ -6264,11 +6658,13 @@ | |
| current_frame_info.args_size = args_size; | |
| current_frame_info.extra_size = extra_size; | |
| current_frame_info.gp_reg_size = gp_reg_size; | |
| + current_frame_info.gp_quad_size = gp_quad_size; | |
| current_frame_info.fp_reg_size = fp_reg_size; | |
| current_frame_info.mask = mask; | |
| current_frame_info.fmask = fmask; | |
| - current_frame_info.initialized = reload_completed; | |
| - current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD; | |
| + current_frame_info.state | |
| + = tentative ? fi_partially_initialized : fi_initialized; | |
| + current_frame_info.num_gp = num_gp; | |
| current_frame_info.num_fp = fp_reg_size / (fp_inc * UNITS_PER_FPREG); | |
| if (mask) | |
| @@ -6278,13 +6674,20 @@ | |
| /* When using mips_entry, the registers are always saved at the | |
| top of the stack. */ | |
| if (! mips_entry) | |
| - offset = (args_size + extra_size + var_size | |
| - + gp_reg_size - GET_MODE_SIZE (gpr_mode)); | |
| + offset = args_size + extra_size + var_size + gp_reg_size; | |
| else | |
| - offset = total_size - GET_MODE_SIZE (gpr_mode); | |
| + offset = total_size; | |
| current_frame_info.gp_sp_offset = offset; | |
| + current_frame_info.rap_offset | |
| + = (offset - GET_MODE_SIZE (mips_reg_mode[31]) | |
| + + (((UNITS_PER_WORD > 8 ? 8 : UNITS_PER_WORD) | |
| + - (POINTER_SIZE / BITS_PER_UNIT)) | |
| + * (BYTES_BIG_ENDIAN != 0))); | |
| current_frame_info.gp_save_offset = offset - total_size; | |
| + /* Point to last saved register. */ | |
| + current_frame_info.gp_save_offset | |
| + -= GET_MODE_SIZE (gp_reg_size == gp_quad_size ? TImode : DImode); | |
| } | |
| else | |
| { | |
| @@ -6317,6 +6720,34 @@ | |
| is not modified within save_restore_insns. */ | |
| #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0) | |
| +/* If modifying X uses a larger mode than in mips_reg_mode, | |
| + indicate that fact by setting mips_reg_mode. */ | |
| + | |
| +static void | |
| +mips_check_reg_mode (x, insn, data) | |
| + rtx x; | |
| + rtx insn ATTRIBUTE_UNUSED; | |
| + void * data ATTRIBUTE_UNUSED; | |
| +{ | |
| + enum machine_mode mode = GET_MODE (x); | |
| + | |
| + if (GET_CODE (x) == SUBREG) | |
| + { | |
| + x = SUBREG_REG (x); | |
| + } | |
| + /* QI clobbers are what asm() clobbers generate. We must | |
| + assume the whole register is clobbered. */ | |
| + if (GET_CODE (insn) == CLOBBER | |
| + && mode == QImode) | |
| + mode = TImode; | |
| + if (GET_CODE (x) == REG | |
| + && REGNO (x) <= GP_REG_LAST | |
| + && (GET_MODE_SIZE (mode) | |
| + > GET_MODE_SIZE (mips_reg_mode[REGNO (x)]))) | |
| + { | |
| + mips_reg_mode[REGNO (x)] = mode; | |
| + } | |
| +} | |
| static void | |
| save_restore_insns (store_p, large_reg, large_offset, file) | |
| @@ -6331,6 +6762,10 @@ | |
| rtx base_reg_rtx; | |
| HOST_WIDE_INT base_offset; | |
| HOST_WIDE_INT gp_offset; | |
| + HOST_WIDE_INT gp_start; | |
| + HOST_WIDE_INT gp_end; | |
| + HOST_WIDE_INT gp_quad_offset; | |
| + HOST_WIDE_INT gp_word_offset; | |
| HOST_WIDE_INT fp_offset; | |
| HOST_WIDE_INT end_offset; | |
| rtx insn; | |
| @@ -6356,29 +6791,30 @@ | |
| the constant created in the prologue/epilogue to adjust the stack | |
| frame. */ | |
| - gp_offset = current_frame_info.gp_sp_offset; | |
| - end_offset | |
| - = gp_offset - (current_frame_info.gp_reg_size | |
| - - GET_MODE_SIZE (gpr_mode)); | |
| - | |
| - if (gp_offset < 0 || end_offset < 0) | |
| - fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.", | |
| - (long) gp_offset, (long) end_offset); | |
| + gp_end = current_frame_info.gp_sp_offset; | |
| + gp_start = gp_end - current_frame_info.gp_reg_size; | |
| + gp_quad_offset = gp_start; | |
| + gp_word_offset = gp_start + current_frame_info.gp_quad_size; | |
| + | |
| + if (gp_end < 0 || gp_start < 0) | |
| + fatal ("gp_end (%ld) or gp_start (%ld) is less than zero.", | |
| + (long) gp_end , (long) gp_start); | |
| /* If we see a large frame in mips16 mode, we save the registers | |
| before adjusting the stack pointer, and load them afterward. */ | |
| else if (TARGET_MIPS16 && large_offset > 32767) | |
| base_reg_rtx = stack_pointer_rtx, base_offset = large_offset; | |
| - else if (gp_offset < 32768) | |
| + else if (gp_end <= 32768) | |
| base_reg_rtx = stack_pointer_rtx, base_offset = 0; | |
| else if (large_reg != 0 | |
| - && (unsigned HOST_WIDE_INT) (large_offset - gp_offset) < 32768 | |
| - && (unsigned HOST_WIDE_INT) (large_offset - end_offset) < 32768) | |
| + && (unsigned HOST_WIDE_INT) (large_offset - gp_end) <= 32768 | |
| + && (unsigned HOST_WIDE_INT) (large_offset - gp_start) < 32768) | |
| { | |
| base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM); | |
| base_offset = large_offset; | |
| + gp_offset = base_offset; | |
| if (file == 0) | |
| { | |
| if (Pmode == DImode) | |
| @@ -6402,10 +6838,10 @@ | |
| { | |
| base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM); | |
| base_offset = gp_offset; | |
| + gp_offset = base_offset; | |
| if (file == 0) | |
| { | |
| rtx gp_offset_rtx = GEN_INT (gp_offset); | |
| - | |
| /* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P | |
| bit, so make sure that we don't emit anything that can be | |
| split. */ | |
| @@ -6415,7 +6851,7 @@ | |
| && GET_MODE (base_reg_rtx) == SImode) | |
| { | |
| insn = emit_move_insn (base_reg_rtx, | |
| - GEN_INT (gp_offset & 0xffff0000)); | |
| + GEN_INT (gp_offset & 0xffff0000U)); | |
| if (store_p) | |
| RTX_FRAME_RELATED_P (insn) = 1; | |
| insn | |
| @@ -6466,14 +6902,31 @@ | |
| && large_offset <= 32767) | |
| base_offset += current_function_outgoing_args_size; | |
| - for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) | |
| + /* Process registers in forward order to improve burst reads from | |
| + memory. */ | |
| + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) | |
| if (BITSET_P (mask, regno - GP_REG_FIRST)) | |
| { | |
| + HOST_WIDE_INT gp_offset; | |
| + | |
| + if (GET_MODE_SIZE (mips_reg_mode[regno]) == 16) | |
| + { | |
| + gp_offset = gp_quad_offset; | |
| + gp_quad_offset += 16; | |
| + } | |
| + else | |
| + { | |
| + gp_offset = gp_word_offset; | |
| + gp_word_offset += GET_MODE_SIZE (mips_reg_mode[regno]); | |
| + } | |
| + | |
| if (file == 0) | |
| { | |
| rtx reg_rtx; | |
| rtx mem_rtx | |
| - = gen_rtx (MEM, gpr_mode, | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + = gen_rtx (MEM, mips_reg_mode[regno], | |
| + /* END CYGNUS LOCAL */ | |
| gen_rtx (PLUS, Pmode, base_reg_rtx, | |
| GEN_INT (gp_offset - base_offset))); | |
| @@ -6483,23 +6936,34 @@ | |
| $31, so we load $7 instead, and work things out | |
| in the caller. */ | |
| if (TARGET_MIPS16 && ! store_p && regno == GP_REG_FIRST + 31) | |
| - reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 7); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + reg_rtx = gen_rtx (REG, mips_reg_mode[7], GP_REG_FIRST + 7); | |
| + /* END CYGNUS LOCAL */ | |
| /* The mips16 sometimes needs to save $18. */ | |
| else if (TARGET_MIPS16 | |
| && regno != GP_REG_FIRST + 31 | |
| && ! M16_REG_P (regno)) | |
| { | |
| if (! store_p) | |
| - reg_rtx = gen_rtx (REG, gpr_mode, 6); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + reg_rtx = gen_rtx (REG, mips_reg_mode[6], 6); | |
| + /* END CYGNUS LOCAL */ | |
| else | |
| { | |
| - reg_rtx = gen_rtx (REG, gpr_mode, 3); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + reg_rtx = gen_rtx (REG, mips_reg_mode[3], 3); | |
| emit_move_insn (reg_rtx, | |
| - gen_rtx (REG, gpr_mode, regno)); | |
| + gen_rtx (REG, mips_reg_mode[regno], | |
| + regno)); | |
| + /* END CYGNUS LOCAL */ | |
| } | |
| } | |
| else | |
| - reg_rtx = gen_rtx (REG, gpr_mode, regno); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + reg_rtx = gen_rtx (REG, | |
| + mips_reg_mode[regno], | |
| + regno); | |
| + /* END CYGNUS LOCAL */ | |
| if (store_p) | |
| { | |
| @@ -6514,7 +6978,10 @@ | |
| if (TARGET_MIPS16 | |
| && regno != GP_REG_FIRST + 31 | |
| && ! M16_REG_P (regno)) | |
| - emit_move_insn (gen_rtx (REG, gpr_mode, regno), | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + emit_move_insn (gen_rtx (REG, mips_reg_mode[regno], | |
| + regno), | |
| + /* END CYGNUS LOCAL */ | |
| reg_rtx); | |
| } | |
| } | |
| @@ -6562,7 +7029,9 @@ | |
| } | |
| } | |
| - gp_offset -= GET_MODE_SIZE (gpr_mode); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + gp_offset -= GET_MODE_SIZE (mips_reg_mode[0]); | |
| + /* END CYGNUS LOCAL */ | |
| } | |
| } | |
| else | |
| @@ -6633,7 +7102,7 @@ | |
| && GET_MODE (base_reg_rtx) == SImode) | |
| { | |
| insn = emit_move_insn (base_reg_rtx, | |
| - GEN_INT (fp_offset & 0xffff0000)); | |
| + GEN_INT (fp_offset & 0xffff0000U)); | |
| if (store_p) | |
| RTX_FRAME_RELATED_P (insn) = 1; | |
| insn = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx, | |
| @@ -6835,9 +7304,9 @@ | |
| dest = SET_DEST (set); | |
| if (GET_CODE (dest) != MEM) | |
| continue; | |
| - if (GET_MODE_SIZE (GET_MODE (dest)) == UNITS_PER_WORD) | |
| + if (GET_MODE_SIZE (GET_MODE (dest)) == (unsigned) UNITS_PER_WORD) | |
| ; | |
| - else if (GET_MODE_SIZE (GET_MODE (dest)) == 2 * UNITS_PER_WORD | |
| + else if (GET_MODE_SIZE (GET_MODE (dest)) == (unsigned)2 * UNITS_PER_WORD | |
| && REGNO (src) < GP_REG_FIRST + 7) | |
| ; | |
| else | |
| @@ -6847,11 +7316,12 @@ | |
| if (GET_CODE (base) != REG | |
| || GET_CODE (offset) != CONST_INT) | |
| continue; | |
| - if (REGNO (base) == STACK_POINTER_REGNUM | |
| - && INTVAL (offset) == tsize + (REGNO (src) - 4) * UNITS_PER_WORD) | |
| + if (REGNO (base) == (unsigned) STACK_POINTER_REGNUM | |
| + && (unsigned HOST_WIDE_INT) INTVAL (offset) | |
| + == tsize + (REGNO (src) - 4) * UNITS_PER_WORD) | |
| ; | |
| - else if (REGNO (base) == HARD_FRAME_POINTER_REGNUM | |
| - && (INTVAL (offset) | |
| + else if (REGNO (base) == (unsigned) HARD_FRAME_POINTER_REGNUM | |
| + && ((unsigned HOST_WIDE_INT) INTVAL (offset) | |
| == (tsize | |
| + (REGNO (src) - 4) * UNITS_PER_WORD | |
| - current_function_outgoing_args_size))) | |
| @@ -7045,6 +7515,87 @@ | |
| } | |
| } | |
| + if (TARGET_MIPS5900) | |
| + { | |
| + static void mips_arg_pointer_elimination PARAMS ((rtx)); | |
| + int regno; | |
| + rtx first_insn, insn, sqnc_first_insn, sqnc_last_insn, set; | |
| + tree attr; | |
| + | |
| + /* We must end the existing sequence so that we can examine the RTL | |
| + chain for the entire function. When finished we will start a | |
| + new sequence for the prologue insns. | |
| + Make sure we have at least one insn in the sequence, lest | |
| + set_new_first_and_last_insn will set cur_insn_uid to 1. */ | |
| + | |
| + emit_note (NULL_PTR, NOTE_INSN_DELETED); | |
| + sqnc_first_insn = get_insns(); | |
| + sqnc_last_insn = get_last_insn(); | |
| + end_sequence(); | |
| + push_topmost_sequence (); | |
| + | |
| + first_insn = get_insns (); | |
| + | |
| + pop_topmost_sequence (); | |
| + | |
| + start_sequence(); | |
| + set_new_first_and_last_insn (sqnc_first_insn, sqnc_last_insn); | |
| + | |
| + if (current_frame_info.state == fi_blank || current_frame_info.mask) | |
| + { | |
| + if (current_function_has_nonlocal_label) | |
| + { | |
| + for (regno = GP_REG_LAST; regno >= 0; regno--) | |
| + mips_reg_mode[regno] = TImode; | |
| + } | |
| + else | |
| + { | |
| + for (regno = GP_REG_LAST; regno >= 0; regno--) | |
| + mips_reg_mode[regno] = DImode; | |
| + for (insn = first_insn; insn != NULL_RTX; insn = NEXT_INSN (insn)) | |
| + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') | |
| + note_stores (PATTERN (insn), mips_check_reg_mode, NULL); | |
| + } | |
| + /* The return address register cannot be variably sized, since | |
| + DWARF_FRAME_REGNUM is used on it before gen_prologue. The | |
| + unwinder thinks of it as 64 bit anyways, so just save 64 bit, | |
| + making the upper half call-clobbered. */ | |
| + mips_reg_mode[GP_REG_FIRST + 31] = DImode; | |
| + if ((attr = lookup_attribute | |
| + ("register_precision", | |
| + DECL_MACHINE_ATTRIBUTES (current_function_decl))) | |
| + != 0) | |
| + for (; attr; attr = TREE_CHAIN (attr)) | |
| + { | |
| + char *reg_expr | |
| + = IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (attr))); | |
| + tree reg_length = TREE_VALUE (TREE_CHAIN (TREE_VALUE (attr))); | |
| + enum machine_mode mode = VOIDmode; | |
| + int j; | |
| + switch (TREE_INT_CST_LOW (reg_length)) | |
| + { | |
| + case 32: | |
| + mode= SImode; | |
| + break; | |
| + case 64: | |
| + mode= DImode; | |
| + break; | |
| + case 128: | |
| + mode= TImode; | |
| + break; | |
| + } | |
| + | |
| + j = decode_reg_name (reg_expr); | |
| + if (j > 0) | |
| + mips_reg_mode[j] = mode; | |
| + } | |
| + } | |
| + current_frame_info.state = fi_modes_known; | |
| + tsize = compute_frame_size (get_frame_size ()); | |
| + | |
| + mips_arg_pointer_elimination (first_insn); | |
| + } | |
| + else | |
| tsize = compute_frame_size (get_frame_size ()); | |
| /* If this function is a varargs function, store any registers that | |
| @@ -7066,10 +7617,12 @@ | |
| { | |
| if (offset != 0) | |
| ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset)); | |
| - emit_move_insn (gen_rtx (MEM, gpr_mode, ptr), | |
| - gen_rtx (REG, gpr_mode, regno)); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + emit_move_insn (gen_rtx (MEM, mips_reg_mode[regno], ptr), | |
| + gen_rtx (REG, mips_reg_mode[regno], regno)); | |
| - offset += GET_MODE_SIZE (gpr_mode); | |
| + offset += GET_MODE_SIZE (mips_reg_mode[0]); | |
| + /* END CYGNUS LOCAL */ | |
| } | |
| } | |
| @@ -7114,7 +7667,10 @@ | |
| moment. */ | |
| if (TARGET_MIPS16 && BITSET_P (current_frame_info.mask, 18)) | |
| { | |
| - rtx reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 3); | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + rtx reg_rtx = gen_rtx (REG, mips_reg_mode[GP_REG_FIRST + 3], | |
| + GP_REG_FIRST + 3); | |
| + /* END CYGNUS LOCAL */ | |
| long gp_offset, base_offset; | |
| gp_offset = current_frame_info.gp_sp_offset; | |
| @@ -7130,12 +7686,15 @@ | |
| base_offset = 0; | |
| start_sequence (); | |
| emit_move_insn (reg_rtx, | |
| - gen_rtx (REG, gpr_mode, GP_REG_FIRST + 18)); | |
| - emit_move_insn (gen_rtx (MEM, gpr_mode, | |
| + /* CYGNUS LOCAL gpr_mode */ | |
| + gen_rtx (REG, mips_reg_mode[GP_REG_FIRST + 18], | |
| + GP_REG_FIRST + 18)); | |
| + emit_move_insn (gen_rtx (MEM, mips_reg_mode[GP_REG_FIRST + 18], | |
| gen_rtx (PLUS, Pmode, stack_pointer_rtx, | |
| GEN_INT (gp_offset | |
| - base_offset))), | |
| reg_rtx); | |
| + /* END CYGNUS LOCAL */ | |
| reg_18_save = gen_sequence (); | |
| end_sequence (); | |
| } | |
| @@ -7175,7 +7734,7 @@ | |
| && GET_MODE (tmp_rtx) == SImode) | |
| { | |
| insn = emit_move_insn (tmp_rtx, | |
| - GEN_INT (tsize & 0xffff0000)); | |
| + GEN_INT (tsize & 0xffff0000U)); | |
| RTX_FRAME_RELATED_P (insn) = 1; | |
| insn = emit_insn (gen_iorsi3 (tmp_rtx, tmp_rtx, | |
| GEN_INT (tsize & 0x0000ffff))); | |
| @@ -7294,7 +7853,7 @@ | |
| /* Do any necessary cleanup after a function to restore stack, frame, | |
| and regs. */ | |
| -#define RA_MASK ((long) 0x80000000) /* 1 << 31 */ | |
| +#define RA_MASK ((unsigned long) 0x80000000U) /* 1 << 31 */ | |
| #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) | |
| void | |
| @@ -7371,7 +7930,6 @@ | |
| num_refs[2] = 0; | |
| mips_load_reg = 0; | |
| mips_load_reg2 = 0; | |
| - current_frame_info = zero_frame_info; | |
| while (string_constants != NULL) | |
| { | |
| @@ -7392,14 +7950,16 @@ | |
| /* Expand the epilogue into a bunch of separate insns. */ | |
| +/* CYGNUS LOCAL sibcall/law */ | |
| void | |
| -mips_expand_epilogue () | |
| +mips_expand_epilogue (sibcall) | |
| + int sibcall; | |
| { | |
| HOST_WIDE_INT tsize = current_frame_info.total_size; | |
| rtx tsize_rtx = GEN_INT (tsize); | |
| rtx tmp_rtx = (rtx)0; | |
| - if (mips_can_use_return_insn ()) | |
| + if (!sibcall && mips_can_use_return_insn ()) | |
| { | |
| emit_insn (gen_return ()); | |
| return; | |
| @@ -7487,13 +8047,14 @@ | |
| } | |
| /* The mips16 loads the return address into $7, not $31. */ | |
| - if (TARGET_MIPS16 && (current_frame_info.mask & RA_MASK) != 0) | |
| + if (!sibcall && TARGET_MIPS16 && (current_frame_info.mask & RA_MASK) != 0) | |
| emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, | |
| GP_REG_FIRST + 7))); | |
| - else | |
| + else if (!sibcall) | |
| emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, | |
| GP_REG_FIRST + 31))); | |
| } | |
| +/* END CYGNUS LOCAL */ | |
| /* Return nonzero if this function is known to have a null epilogue. | |
| This allows the optimizer to omit jumps to jumps if no stack | |
| @@ -7521,7 +8082,7 @@ | |
| <= 4))) | |
| return 0; | |
| - if (current_frame_info.initialized) | |
| + if (current_frame_info.state == fi_initialized) | |
| return current_frame_info.total_size == 0; | |
| return compute_frame_size (get_frame_size ()) == 0; | |
| @@ -7576,7 +8137,7 @@ | |
| /* For hosted applications, always put constants in small data if | |
| possible, as this gives the best performance. */ | |
| - if (GET_MODE_SIZE (mode) <= mips_section_threshold | |
| + if (GET_MODE_SIZE (mode) <= (unsigned) mips_section_threshold | |
| && mips_section_threshold > 0) | |
| SMALL_DATA_SECTION (); | |
| else if (flag_pic && symbolic_expression_p (x)) | |
| @@ -7785,7 +8346,8 @@ | |
| to prevent it, or add code to function.c to properly handle the case. */ | |
| /* ??? cum can be NULL when called from mips_va_arg. The problem handled | |
| here hopefully is not relevant to mips_va_arg. */ | |
| - if (cum && MUST_PASS_IN_STACK (mode, type)) | |
| + if ( | |
| + cum && MUST_PASS_IN_STACK (mode, type)) | |
| { | |
| /* Don't pass the actual CUM to FUNCTION_ARG, because we would | |
| get double copies of any offsets generated for small structs | |
| @@ -7796,7 +8358,6 @@ | |
| return 1; | |
| } | |
| - | |
| /* Otherwise, we only do this if EABI is selected. */ | |
| if (mips_abi != ABI_EABI) | |
| return 0; | |
| @@ -7805,6 +8366,16 @@ | |
| if (type == NULL_TREE || mode == DImode || mode == DFmode) | |
| return 0; | |
| + /* The r5900 can pass TImode values in a single register, so | |
| + there is no need to pass it by reference. */ | |
| + if (mode == TImode && (TARGET_MIPS5900 | |
| + )) | |
| + return 0; | |
| + | |
| + /* SIMD vector modes can be passed in a single register, so | |
| + there is no need to pass it by reference. */ | |
| + if (SIMD_MODE_SUPPORTED_P (mode)) | |
| + return 0; | |
| size = int_size_in_bytes (type); | |
| return size == -1 || size > UNITS_PER_WORD; | |
| } | |
| @@ -7862,11 +8433,21 @@ | |
| && gp_reg_p | |
| && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode)) | |
| ? NO_REGS : gr_regs); | |
| + else if (class == HILO1_REG && regno != GP_REG_FIRST + 0) | |
| + return ((! in_p | |
| + && gp_reg_p | |
| + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode)) | |
| + ? NO_REGS : gr_regs); | |
| else if (regno == HILO_REGNUM) | |
| return ((in_p | |
| && class == gr_regs | |
| && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode)) | |
| ? NO_REGS : gr_regs); | |
| + else if (regno == HILO1_REGNUM) | |
| + return ((in_p | |
| + && class == gr_regs | |
| + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode)) | |
| + ? NO_REGS : gr_regs); | |
| /* Copying from HI or LO to anywhere other than a general register | |
| requires a general register. */ | |
| @@ -7879,6 +8460,15 @@ | |
| } | |
| return gp_reg_p ? NO_REGS : gr_regs; | |
| } | |
| + else if (class == HI1_REG || class == LO1_REG || class == MD1_REGS) | |
| + { | |
| + if (TARGET_MIPS16 && in_p) | |
| + { | |
| + /* We can't really copy to HI or LO at all in mips16 mode. */ | |
| + return M16_REGS; | |
| + } | |
| + return gp_reg_p ? NO_REGS : gr_regs; | |
| + } | |
| if (MD_REG_P (regno)) | |
| { | |
| if (TARGET_MIPS16 && ! in_p) | |
| @@ -7888,6 +8478,15 @@ | |
| } | |
| return class == gr_regs ? NO_REGS : gr_regs; | |
| } | |
| + else if (MD1_REG_P (regno)) | |
| + { | |
| + if (TARGET_MIPS16 && ! in_p) | |
| + { | |
| + /* We can't really copy to HI or LO at all in mips16 mode. */ | |
| + return M16_REGS; | |
| + } | |
| + return class == gr_regs ? NO_REGS : gr_regs; | |
| + } | |
| /* We can only copy a value to a condition code register from a | |
| floating point register, and even then we require a scratch | |
| @@ -8141,7 +8740,10 @@ | |
| knows how to handle this. We can always accept a string | |
| constant, which is the other case in which SYMBOL_REF_FLAG | |
| will be set. */ | |
| - if (! addr && ! addend && SYMBOL_REF_FLAG (x) && mode == Pmode) | |
| + if (! addr | |
| + && ! addend | |
| + && SYMBOL_REF_FLAG (x) | |
| + && mode == (enum machine_mode) Pmode) | |
| return 1; | |
| /* We can accept a string constant, which will have | |
| @@ -8695,7 +9297,7 @@ | |
| { | |
| rtx set; | |
| - if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') | |
| + if (! INSN_P (insn)) | |
| continue; | |
| set = PATTERN (insn); | |
| @@ -8712,14 +9314,14 @@ | |
| && GET_CODE (XEXP (SET_SRC (set), 0)) == REG | |
| && REGNO (XEXP (SET_SRC (set), 0)) == GP_REG_FIRST + 28 | |
| && GET_CODE (SET_DEST (set)) == REG | |
| - && GET_MODE (SET_DEST (set)) == Pmode) | |
| + && GET_MODE (SET_DEST (set)) == (unsigned) Pmode) | |
| gpcopy = SET_DEST (set); | |
| else if (slot == NULL_RTX | |
| && gpcopy != NULL_RTX | |
| && GET_CODE (SET_DEST (set)) == MEM | |
| && GET_CODE (SET_SRC (set)) == REG | |
| && REGNO (SET_SRC (set)) == REGNO (gpcopy) | |
| - && GET_MODE (SET_DEST (set)) == Pmode) | |
| + && GET_MODE (SET_DEST (set)) == (unsigned) Pmode) | |
| { | |
| rtx base, offset; | |
| @@ -8736,7 +9338,7 @@ | |
| && reg_overlap_mentioned_p (SET_DEST (set), gpcopy) | |
| && (GET_CODE (SET_DEST (set)) != REG | |
| || REGNO (SET_DEST (set)) != REGNO (gpcopy) | |
| - || GET_MODE (SET_DEST (set)) != Pmode | |
| + || GET_MODE (SET_DEST (set)) != (unsigned) Pmode | |
| || ((GET_CODE (SET_SRC (set)) != CONST | |
| || GET_CODE (XEXP (SET_SRC (set), 0)) != REG | |
| || (REGNO (XEXP (SET_SRC (set), 0)) | |
| @@ -8794,10 +9396,10 @@ | |
| if (next == NULL_RTX) | |
| break; | |
| - if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') | |
| + if (! INSN_P (insn)) | |
| continue; | |
| - if (GET_RTX_CLASS (GET_CODE (next)) != 'i') | |
| + if (! INSN_P (next)) | |
| continue; | |
| set1 = PATTERN (insn); | |
| @@ -8850,12 +9452,12 @@ | |
| { | |
| rtx set; | |
| - if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') | |
| + if (! INSN_P (insn)) | |
| continue; | |
| set = PATTERN (insn); | |
| if (GET_CODE (set) != SET | |
| - || GET_MODE (SET_DEST (set)) != Pmode) | |
| + || GET_MODE (SET_DEST (set)) != (unsigned) Pmode) | |
| continue; | |
| if (GET_CODE (SET_DEST (set)) == MEM | |
| @@ -9019,6 +9621,108 @@ | |
| return NULL_RTX; | |
| } | |
| + | |
| +/* On the R5900, we must ensure that the compiler never generates loops | |
| + that satisfy all of the following conditions: | |
| + | |
| + * a loop consists of less than equal to six instructions(includes | |
| + branch delay slot). | |
| + | |
| + * a loop contains only one conditional branch instruction at the | |
| + end of the loop. | |
| + | |
| + * a loop does not contain any other branch or jump instructions. | |
| + | |
| + We need to do this because of a bug in the chip. */ | |
| + | |
| +static void | |
| +mips_r5900_lengthen_loops (first) | |
| + rtx first; | |
| +{ | |
| + rtx insn; | |
| + int n = 1; | |
| + int max_uid = get_max_uid (); | |
| + int *seen_before = alloca (sizeof seen_before[0] * max_uid); | |
| + | |
| + bzero ((char *) seen_before, sizeof seen_before[0] * max_uid); | |
| + | |
| + for (insn = first; insn; insn = NEXT_INSN (insn)) | |
| + { | |
| + switch (GET_CODE (insn)) | |
| + { | |
| + case CODE_LABEL: | |
| + seen_before [INSN_UID (insn)] = n; | |
| + break; | |
| + | |
| + case INSN: | |
| + if (GET_CODE (PATTERN (insn)) == SEQUENCE) | |
| + { | |
| + rtx x = XVECEXP (PATTERN (insn), 0, 0); | |
| + if (condjump_p (x)) | |
| + { | |
| + rtx target = condjump_label (x); | |
| + | |
| + if (seen_before [INSN_UID (XEXP (target, 0))]) | |
| + { | |
| + int distance | |
| + = n - seen_before [INSN_UID (XEXP (target, 0))] + 2; | |
| + for (; distance <= 6; distance++) | |
| + emit_insn_before (gen_nop (), insn); | |
| + } | |
| + } | |
| + else if (GET_CODE (x) == CALL_INSN) | |
| + bzero ((char *) seen_before, sizeof seen_before[0] * max_uid); | |
| + else | |
| + n += XVECLEN (PATTERN (insn), 0); | |
| + } | |
| + else | |
| + n++; | |
| + break; | |
| + | |
| + case JUMP_INSN: | |
| + if (condjump_p (insn)) | |
| + { | |
| + rtx target = condjump_label (insn); | |
| + | |
| + if (seen_before [INSN_UID (XEXP (target, 0))]) | |
| + { | |
| + int distance | |
| + = n - seen_before [INSN_UID (XEXP (target, 0))]; | |
| + | |
| + for (; distance <= 6; distance++) | |
| + { | |
| + emit_insn_before (gen_nop (), insn); | |
| + } | |
| + } | |
| + } | |
| + | |
| + /* Falls through. */ | |
| + | |
| + case CALL_INSN: | |
| + bzero ((char *) seen_before, sizeof seen_before[0] * max_uid); | |
| + break; | |
| + | |
| + default: | |
| + break; | |
| + } | |
| + } | |
| +} | |
| + | |
| +/* Exported to toplev.c. | |
| + | |
| + Do a final pass over the function, just after delayed branch | |
| + scheduling. */ | |
| + | |
| +void | |
| +machine_dependent_reorg2 (first) | |
| + rtx first; | |
| +{ | |
| + /* Currently, this is only used to modify certain loops in order | |
| + to workaround problems in the defective 5900 component. */ | |
| + if (TARGET_MIPS5900) | |
| + mips_r5900_lengthen_loops (first); | |
| +} | |
| + | |
| /* Exported to toplev.c. | |
| Do a final pass over the function, just before delayed branch | |
| @@ -9250,6 +9954,351 @@ | |
| || code == ROTATE); | |
| } | |
| +/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific | |
| + attribute for DECL. The attributes in ATTRIBUTES have previously been | |
| + assigned to DECL. */ | |
| +int | |
| +mips_valid_decl_attribute_p (decl, attributes, identifier, args) | |
| + tree decl; | |
| + tree attributes ATTRIBUTE_UNUSED; | |
| + tree identifier; | |
| + tree args; | |
| +{ | |
| + /* The register_precision attribute is only useful on the r5900 | |
| + for functions and methods. It specifies what mode to save | |
| + registers on the stack with. */ | |
| + if (TARGET_MIPS5900 | |
| + && (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE | |
| + || TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) | |
| + && is_attribute_p ("register_precision", identifier) | |
| + && args | |
| + && TREE_CODE (args) == TREE_LIST) | |
| + { | |
| + int j; | |
| + char *reg_expr = IDENTIFIER_POINTER (TREE_VALUE (args)); | |
| + tree reg_length = TREE_VALUE (TREE_CHAIN (args)); | |
| + enum machine_mode mode = VOIDmode; | |
| + tree attr = DECL_MACHINE_ATTRIBUTES (decl); | |
| + | |
| + /* TREE_CHAIN (TREE_VALUE (args)) = TREE_CHAIN (args);*/ | |
| + /* TREE_CHAIN (args) = 0;*/ | |
| + if (attr) | |
| + chainon (attr, build_tree_list (NULL_TREE, args)); | |
| + | |
| + switch (TREE_INT_CST_LOW (reg_length)) | |
| + { | |
| + case 32: | |
| + mode= SImode; | |
| + break; | |
| + case 64: | |
| + mode= DImode; | |
| + break; | |
| + case 128: | |
| + mode= TImode; | |
| + break; | |
| + default: | |
| + error ("Register precision must be 32, 64, or 128, not `%d'", | |
| + TREE_INT_CST_LOW (reg_length)); | |
| + } | |
| + | |
| + if ((j = decode_reg_name (reg_expr)) == 0) | |
| + warning ("unknown register name: %s", reg_expr); | |
| + | |
| + return 1; | |
| + } | |
| + return 0; | |
| +} | |
| + | |
| +/* Reorder the ready list as needed to improve performance. */ | |
| + | |
| +void | |
| +mips_sched_reorder (stream, verbose, ready, n_ready) | |
| + FILE *stream ATTRIBUTE_UNUSED; | |
| + int verbose ATTRIBUTE_UNUSED; | |
| + rtx *ready; | |
| + int n_ready; | |
| +{ | |
| + static int imuldivunit = -1; | |
| + int i; | |
| + | |
| + /* Right now this is only used to improve a couple scheduling problems | |
| + for the r5900. There is also no point in trying these tweaks after | |
| + reload has completed. */ | |
| + if (!(TARGET_MIPS5900 | |
| + ) || reload_completed) | |
| + return; | |
| + | |
| + /* If there are less than three insns on the queue, then there's nothing | |
| + to do. */ | |
| + if (n_ready < 3) | |
| + return; | |
| + | |
| + /* We need to know what value will be returned by function_units_used for | |
| + the r5900's multiply/divide units. If we have not computed it yet, | |
| + do so now. */ | |
| + if (imuldivunit == -1) | |
| + { | |
| + for (i = 0; i < FUNCTION_UNITS_SIZE; i++) | |
| + { | |
| + if (!strcmp ("r5900imuldiv", function_units[i].name)) | |
| + { | |
| + imuldivunit = i; | |
| + break; | |
| + } | |
| + } | |
| + | |
| + if (imuldivunit == -1) | |
| + return; | |
| + } | |
| + | |
| + /* Loop through the instructions and try to pair up two instructions | |
| + which use the imuldiv pipelines. | |
| + | |
| + We want such instructions to appear back to back in the RTL chain | |
| + so that the register allocator will allocate a different HILO | |
| + register for the two imuldiv instructions. | |
| + | |
| + Note the ready list is ordered backwards. | |
| + | |
| + If we do not find an idivmul insn which could issue this cycle, quit | |
| + to save time. */ | |
| + for (i = n_ready - 1; i >= n_ready - 2; i--) | |
| + { | |
| + rtx insn = ready[i]; | |
| + enum rtx_code code; | |
| + | |
| + /* Ignore anything we do not understand. */ | |
| + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i' | |
| + || (code = GET_CODE (PATTERN (insn))) == USE | |
| + || code == CLOBBER || code == ADDR_VEC) | |
| + continue; | |
| + | |
| + /* We are looking for instructions that issue to the imuldiv | |
| + pipelines. */ | |
| + if (function_units_used (insn) == imuldivunit) | |
| + { | |
| + int j; | |
| + | |
| + /* We have found one insn that uses the imuldiv pipeline, so | |
| + now look for another imuldiv instruction. */ | |
| + for (j = i - 1; j >= 0; j--) | |
| + { | |
| + rtx temp = ready[j]; | |
| + | |
| + /* Ignore anything we do not understand. */ | |
| + if (GET_RTX_CLASS (GET_CODE (temp)) != 'i' | |
| + || (code = GET_CODE (PATTERN (temp))) == USE | |
| + || code == CLOBBER || code == ADDR_VEC) | |
| + continue; | |
| + | |
| + /* Again, we are looking for an imuldiv insn. */ | |
| + if (function_units_used (temp) == imuldivunit) | |
| + { | |
| + /* Make the idivmul insns consecutive if they were | |
| + not already consecutive. */ | |
| + if (i - j != 1) | |
| + { | |
| + rtx temp = ready[j]; | |
| + | |
| + bcopy (&ready[j+1], &ready[j], | |
| + (i - j - 1) * sizeof (rtx *)); | |
| + ready[i - 1] = temp; | |
| + } | |
| + | |
| + /* Now the imuldiv insns are consecutive. We can | |
| + still lose if they issue at different clocks, so | |
| + move them as a pair to the head of ready list. | |
| + | |
| + Note I must either be the head of the queue or | |
| + the second insn in the queue. */ | |
| + if (i != n_ready - 1) | |
| + { | |
| + rtx temp1, temp2; | |
| + | |
| + /* Rotate the first three elements in the | |
| + ready queue. */ | |
| + temp1 = ready[n_ready - 1]; | |
| + temp2 = ready[n_ready - 2]; | |
| + ready[n_ready - 2] = ready[n_ready - 3]; | |
| + ready[n_ready - 3] = temp1; | |
| + ready[n_ready - 1] = temp2; | |
| + } | |
| + return; | |
| + } | |
| + } | |
| + } | |
| + } | |
| +} | |
| + | |
| +/* Return nonzero if INSN, which is a valid madd pattern is profitable | |
| + to implement as a madd instruction. | |
| + | |
| + The r5900 has dual integer multiply pipelines which allows independent | |
| + integer multiplies to run in parallel with each other. | |
| + | |
| + Thus it is not profitable to generate an madd if doing so creates a data | |
| + dependency which prevents running two multiplies in parallel. | |
| + | |
| + We have access to any feeding insn via LOG_LINKS. If it is a multiply or | |
| + multiply-add insn which feeds the register operand of the PLUS, then it | |
| + is not profitable to generate an madd instruction. | |
| + | |
| + It is also probably not profitable if the second operand of this PLUS | |
| + is fed by any insns since we will have to generate a mtlo. So we reject | |
| + all cases where an earlier insn feeds into the second operand of the | |
| + PLUS in the candidate madd insn. */ | |
| + | |
| +int | |
| +r5900_madd_profitable_p (insn) | |
| + rtx insn; | |
| +{ | |
| + rtx temp, madd_reg, link; | |
| + | |
| + temp = PATTERN (insn); | |
| + | |
| + /* Verify we have an madd pattern and that the second operand to the | |
| + PLUS is a register. */ | |
| + if (GET_CODE (temp) == PARALLEL) | |
| + temp = XVECEXP (temp, 0, 0); | |
| + | |
| + if (GET_CODE (temp) != SET | |
| + || GET_CODE (SET_SRC (temp)) != PLUS | |
| + || GET_CODE (XEXP (SET_SRC (temp), 0)) != MULT | |
| + || ! REG_P (XEXP (SET_SRC (temp), 1))) | |
| + return 0; | |
| + | |
| + madd_reg = XEXP (SET_SRC (temp), 1); | |
| + | |
| + /* Now examine the insn which feed INSN. */ | |
| + for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) | |
| + { | |
| + rtx dep_insn = XEXP (link, 0); | |
| + | |
| + if (reg_set_p (madd_reg, dep_insn)) | |
| + return 0; | |
| + } | |
| + | |
| + return 1; | |
| +} | |
| + | |
| +/* Expand RTL for a call which does not return a a value. If SIBCALL is | |
| + nonzero, then this is a sibling call, else it is a normal call. */ | |
| + | |
| +void | |
| +mips_expand_call (operands, sibcall) | |
| + rtx *operands; | |
| + int sibcall; | |
| +{ | |
| + rtx addr; | |
| + | |
| + addr = XEXP (operands[0], 0); | |
| + if ((GET_CODE (addr) != REG | |
| + && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS)) | |
| + || ! call_insn_operand (addr, VOIDmode)) | |
| + XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr); | |
| + | |
| + /* In order to pass small structures by value in registers | |
| + compatibly with the MIPS compiler, we need to shift the value | |
| + into the high part of the register. Function_arg has encoded | |
| + a PARALLEL rtx, holding a vector of adjustments to be made | |
| + as the next_arg_reg variable, so we split up the insns, | |
| + and emit them separately. */ | |
| + if (operands[2] != NULL_RTX && GET_CODE (operands[2]) == PARALLEL) | |
| + { | |
| + rtvec adjust = XVEC (operands[2], 0); | |
| + int num = GET_NUM_ELEM (adjust); | |
| + int i; | |
| + | |
| + for (i = 0; i < num; i++) | |
| + emit_insn (RTVEC_ELT (adjust, i)); | |
| + } | |
| + | |
| + if (TARGET_MIPS16 | |
| + && mips16_hard_float | |
| + && operands[2] != 0 | |
| + && (int) GET_MODE (operands[2]) != 0) | |
| + { | |
| + if (build_mips16_call_stub (NULL_RTX, operands[0], operands[1], | |
| + (int) GET_MODE (operands[2]))) | |
| + return; | |
| + } | |
| + | |
| + if (sibcall) | |
| + emit_call_insn (gen_sibcall_internal0 (operands[0], operands[1])); | |
| + else | |
| + emit_call_insn (gen_call_internal0 (operands[0], operands[1], | |
| + gen_rtx (REG, SImode, | |
| + GP_REG_FIRST + 31))); | |
| +} | |
| + | |
| +/* Expand RTL for a call which returns a value. If SIBCALL is nonzero, | |
| + then this is a sibling call, else it is a normal call. */ | |
| +void | |
| +mips_expand_call_value (operands, sibcall) | |
| + rtx *operands; | |
| + int sibcall; | |
| +{ | |
| + rtx addr = XEXP (operands[1], 0); | |
| + | |
| + if ((GET_CODE (addr) != REG | |
| + && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS)) | |
| + || ! call_insn_operand (addr, VOIDmode)) | |
| + XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr); | |
| + | |
| + /* In order to pass small structures by value in registers | |
| + compatibly with the MIPS compiler, we need to shift the value | |
| + into the high part of the register. Function_arg has encoded | |
| + a PARALLEL rtx, holding a vector of adjustments to be made | |
| + as the next_arg_reg variable, so we split up the insns, | |
| + and emit them separately. */ | |
| + if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL) | |
| + { | |
| + rtvec adjust = XVEC (operands[3], 0); | |
| + int num = GET_NUM_ELEM (adjust); | |
| + int i; | |
| + | |
| + for (i = 0; i < num; i++) | |
| + emit_insn (RTVEC_ELT (adjust, i)); | |
| + } | |
| + | |
| + if (TARGET_MIPS16 | |
| + && mips16_hard_float | |
| + && ((operands[3] != 0 | |
| + && (int) GET_MODE (operands[3]) != 0) | |
| + || GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT)) | |
| + { | |
| + if (build_mips16_call_stub (operands[0], operands[1], operands[2], | |
| + (operands[3] == 0 ? 0 | |
| + : (int) GET_MODE (operands[3])))) | |
| + return; | |
| + } | |
| + | |
| + /* Handle Irix6 function calls that have multiple non-contiguous | |
| + results. */ | |
| + if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1) | |
| + { | |
| + emit_call_insn (gen_call_value_multiple_internal0 | |
| + (XEXP (XVECEXP (operands[0], 0, 0), 0), | |
| + operands[1], operands[2], | |
| + XEXP (XVECEXP (operands[0], 0, 1), 0), | |
| + gen_rtx (REG, SImode, GP_REG_FIRST + 31))); | |
| + return; | |
| + } | |
| + | |
| + /* We have a call returning a DImode structure in an FP reg. | |
| + Strip off the now unnecessary PARALLEL. */ | |
| + if (GET_CODE (operands[0]) == PARALLEL) | |
| + operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0); | |
| + | |
| + if (sibcall) | |
| + emit_call_insn (gen_sibcall_value_internal0 (operands[0], operands[1], | |
| + operands[2])); | |
| + else | |
| + emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], | |
| + operands[2], | |
| + gen_rtx (REG, SImode, | |
| + GP_REG_FIRST + 31))); | |
| +} | |
| /* Return the length of INSN. LENGTH is the initial length computed by | |
| attributes in the machine-description file. */ | |
| @@ -9318,6 +10367,9 @@ | |
| const char *comp = (float_p ? "%F0" : "%C0"); | |
| /* The operand-printing string for the inverted comparison. */ | |
| const char *inverted_comp = (float_p ? "%W0" : "%N0"); | |
| + /* GAS warns about branches that are always false so avoid | |
| + producing them. */ | |
| + int always_false = 0; | |
| /* The MIPS processors (for levels of the ISA at least two), have | |
| "likely" variants of each branch instruction. These instructions | |
| @@ -9351,6 +10403,7 @@ | |
| case LTU: | |
| /* A condition which will always be false. */ | |
| + always_false = 1; | |
| code = NE; | |
| op1 = "%."; | |
| break; | |
| @@ -9379,6 +10432,9 @@ | |
| case 4: | |
| case 8: | |
| /* Just a simple conditional branch. */ | |
| + if (always_false) /* nop */ | |
| + sprintf (buffer, "nop\t\t# branch always false"); | |
| + else | |
| if (float_p) | |
| sprintf (buffer, "%%*b%s%%?\t%%Z2%%1", | |
| inverted_p ? inverted_comp : comp); | |
| @@ -9558,3 +10614,945 @@ | |
| ggc_add_rtx_root (&embedded_pic_fnaddr_rtx, 1); | |
| ggc_add_rtx_root (&mips16_gp_pseudo_rtx, 1); | |
| } | |
| + | |
| +#define def_builtin(NAME, TYPE, CODE) \ | |
| + builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL_PTR) | |
| + | |
| +/* Table describing builtin functions which are unary operations. */ | |
| +static struct builtin_description bdesc_1arg[] = | |
| +{ | |
| + { CODE_FOR_mips5900_pabsh, "__builtin_mips5900_pabsh", | |
| + MIPS5900_BUILTIN_PABSH | |
| + }, | |
| + { CODE_FOR_mips5900_pabsw, "__builtin_mips5900_pabsw", | |
| + MIPS5900_BUILTIN_PABSW | |
| + }, | |
| + { CODE_FOR_mips5900_pcpyh, "__builtin_mips5900_pcpyh", | |
| + MIPS5900_BUILTIN_PCPYH | |
| + }, | |
| + { CODE_FOR_mips5900_pexch, "__builtin_mips5900_pexch", | |
| + MIPS5900_BUILTIN_PEXCH | |
| + }, | |
| + { CODE_FOR_mips5900_pexcw, "__builtin_mips5900_pexcw", | |
| + MIPS5900_BUILTIN_PEXCW | |
| + }, | |
| + { CODE_FOR_mips5900_pexeh, "__builtin_mips5900_pexeh", | |
| + MIPS5900_BUILTIN_PEXEH | |
| + }, | |
| + { CODE_FOR_mips5900_pexew, "__builtin_mips5900_pexew", | |
| + MIPS5900_BUILTIN_PEXEW | |
| + }, | |
| + { CODE_FOR_mips5900_pext5, "__builtin_mips5900_pext5", | |
| + MIPS5900_BUILTIN_PEXT5 | |
| + }, | |
| + { CODE_FOR_mips5900_plzcw, "__builtin_mips5900_plzcw", | |
| + MIPS5900_BUILTIN_PLZCW | |
| + }, | |
| + { CODE_FOR_mips5900_ppac5, "__builtin_mips5900_ppac5", | |
| + MIPS5900_BUILTIN_PPAC5 | |
| + }, | |
| + { CODE_FOR_mips5900_prevh, "__builtin_mips5900_prevh", | |
| + MIPS5900_BUILTIN_PREVH | |
| + }, | |
| + { CODE_FOR_mips5900_prot3w, "__builtin_mips5900_prot3w", | |
| + MIPS5900_BUILTIN_PROT3W | |
| + } | |
| +}; | |
| + | |
| +/* Table describing builtin functions which are binary operations. */ | |
| +static struct builtin_description bdesc_2arg[] = | |
| +{ | |
| + { CODE_FOR_mips5900_paddb, "__builtin_mips5900_paddb", | |
| + MIPS5900_BUILTIN_PADDB | |
| + }, | |
| + { CODE_FOR_mips5900_paddh, "__builtin_mips5900_paddh", | |
| + MIPS5900_BUILTIN_PADDH | |
| + }, | |
| + { CODE_FOR_mips5900_paddsb, "__builtin_mips5900_paddsb", | |
| + MIPS5900_BUILTIN_PADDSB | |
| + }, | |
| + { CODE_FOR_mips5900_paddsh, "__builtin_mips5900_paddsh", | |
| + MIPS5900_BUILTIN_PADDSH | |
| + }, | |
| + { CODE_FOR_mips5900_paddsw, "__builtin_mips5900_paddsw", | |
| + MIPS5900_BUILTIN_PADDSW | |
| + }, | |
| + { CODE_FOR_mips5900_paddub, "__builtin_mips5900_paddub", | |
| + MIPS5900_BUILTIN_PADDUB | |
| + }, | |
| + { CODE_FOR_mips5900_padduh, "__builtin_mips5900_padduh", | |
| + MIPS5900_BUILTIN_PADDUH | |
| + }, | |
| + { CODE_FOR_mips5900_padduw, "__builtin_mips5900_padduw", | |
| + MIPS5900_BUILTIN_PADDUW | |
| + }, | |
| + { CODE_FOR_mips5900_paddw, "__builtin_mips5900_paddw", | |
| + MIPS5900_BUILTIN_PADDW | |
| + }, | |
| + { CODE_FOR_mips5900_padsbh, "__builtin_mips5900_padsbh", | |
| + MIPS5900_BUILTIN_PADSBH | |
| + }, | |
| + { CODE_FOR_mips5900_pand, "__builtin_mips5900_pand", | |
| + MIPS5900_BUILTIN_PAND | |
| + }, | |
| + { CODE_FOR_mips5900_pceqb, "__builtin_mips5900_pceqb", | |
| + MIPS5900_BUILTIN_PCEQB | |
| + }, | |
| + { CODE_FOR_mips5900_pceqh, "__builtin_mips5900_pceqh", | |
| + MIPS5900_BUILTIN_PCEQH | |
| + }, | |
| + { CODE_FOR_mips5900_pceqw, "__builtin_mips5900_pceqw", | |
| + MIPS5900_BUILTIN_PCEQW | |
| + }, | |
| + { CODE_FOR_mips5900_pcgtb, "__builtin_mips5900_pcgtb", | |
| + MIPS5900_BUILTIN_PCGTB | |
| + }, | |
| + { CODE_FOR_mips5900_pcgth, "__builtin_mips5900_pcgth", | |
| + MIPS5900_BUILTIN_PCGTH | |
| + }, | |
| + { CODE_FOR_mips5900_pcgtw, "__builtin_mips5900_pcgtw", | |
| + MIPS5900_BUILTIN_PCGTW | |
| + }, | |
| + { CODE_FOR_mips5900_pcpyld, "__builtin_mips5900_pcpyld", | |
| + MIPS5900_BUILTIN_PCPYLD | |
| + }, | |
| + { CODE_FOR_mips5900_pcpyud, "__builtin_mips5900_pcpyud", | |
| + MIPS5900_BUILTIN_PCPYUD | |
| + }, | |
| + { CODE_FOR_mips5900_pextlb, "__builtin_mips5900_pextlb", | |
| + MIPS5900_BUILTIN_PEXTLB | |
| + }, | |
| + { CODE_FOR_mips5900_pextlh, "__builtin_mips5900_pextlh", | |
| + MIPS5900_BUILTIN_PEXTLH | |
| + }, | |
| + { CODE_FOR_mips5900_pextlw, "__builtin_mips5900_pextlw", | |
| + MIPS5900_BUILTIN_PEXTLW | |
| + }, | |
| + { CODE_FOR_mips5900_pextub, "__builtin_mips5900_pextub", | |
| + MIPS5900_BUILTIN_PEXTUB | |
| + }, | |
| + { CODE_FOR_mips5900_pextuh, "__builtin_mips5900_pextuh", | |
| + MIPS5900_BUILTIN_PEXTUH | |
| + }, | |
| + { CODE_FOR_mips5900_pextuw, "__builtin_mips5900_pextuw", | |
| + MIPS5900_BUILTIN_PEXTUW | |
| + }, | |
| + { CODE_FOR_mips5900_pinth, "__builtin_mips5900_pinth", | |
| + MIPS5900_BUILTIN_PINTH | |
| + }, | |
| + { CODE_FOR_mips5900_pinteh, "__builtin_mips5900_pinteh", | |
| + MIPS5900_BUILTIN_PINTEH | |
| + }, | |
| + { CODE_FOR_mips5900_pmaxh, "__builtin_mips5900_pmaxh", | |
| + MIPS5900_BUILTIN_PMAXH | |
| + }, | |
| + { CODE_FOR_mips5900_pmaxw, "__builtin_mips5900_pmaxw", | |
| + MIPS5900_BUILTIN_PMAXW | |
| + }, | |
| + { CODE_FOR_mips5900_pminh, "__builtin_mips5900_pminh", | |
| + MIPS5900_BUILTIN_PMINH | |
| + }, | |
| + { CODE_FOR_mips5900_pminw, "__builtin_mips5900_pminw", | |
| + MIPS5900_BUILTIN_PMINW | |
| + }, | |
| + { CODE_FOR_mips5900_pnor, "__builtin_mips5900_pnor", | |
| + MIPS5900_BUILTIN_PNOR | |
| + }, | |
| + { CODE_FOR_mips5900_por, "__builtin_mips5900_por", | |
| + MIPS5900_BUILTIN_POR | |
| + }, | |
| + { CODE_FOR_mips5900_ppacb, "__builtin_mips5900_ppacb", | |
| + MIPS5900_BUILTIN_PPACB | |
| + }, | |
| + { CODE_FOR_mips5900_ppach, "__builtin_mips5900_ppach", | |
| + MIPS5900_BUILTIN_PPACH | |
| + }, | |
| + { CODE_FOR_mips5900_ppacw, "__builtin_mips5900_ppacw", | |
| + MIPS5900_BUILTIN_PPACW | |
| + }, | |
| + { CODE_FOR_mips5900_psllvw, "__builtin_mips5900_psllvw", | |
| + MIPS5900_BUILTIN_PSLLVW | |
| + }, | |
| + { CODE_FOR_mips5900_psravw, "__builtin_mips5900_psravw", | |
| + MIPS5900_BUILTIN_PSRAVW | |
| + }, | |
| + { CODE_FOR_mips5900_psrlvw, "__builtin_mips5900_psrlvw", | |
| + MIPS5900_BUILTIN_PSRLVW | |
| + }, | |
| + { CODE_FOR_mips5900_psubb, "__builtin_mips5900_psubb", | |
| + MIPS5900_BUILTIN_PSUBB | |
| + }, | |
| + { CODE_FOR_mips5900_psubh, "__builtin_mips5900_psubh", | |
| + MIPS5900_BUILTIN_PSUBH | |
| + }, | |
| + { CODE_FOR_mips5900_psubsb, "__builtin_mips5900_psubsb", | |
| + MIPS5900_BUILTIN_PSUBSB | |
| + }, | |
| + { CODE_FOR_mips5900_psubsh, "__builtin_mips5900_psubsh", | |
| + MIPS5900_BUILTIN_PSUBSH | |
| + }, | |
| + { CODE_FOR_mips5900_psubsw, "__builtin_mips5900_psubsw", | |
| + MIPS5900_BUILTIN_PSUBSW | |
| + }, | |
| + { CODE_FOR_mips5900_psubub, "__builtin_mips5900_psubub", | |
| + MIPS5900_BUILTIN_PSUBUB | |
| + }, | |
| + { CODE_FOR_mips5900_psubuh, "__builtin_mips5900_psubuh", | |
| + MIPS5900_BUILTIN_PSUBUH | |
| + }, | |
| + { CODE_FOR_mips5900_psubuw, "__builtin_mips5900_psubuw", | |
| + MIPS5900_BUILTIN_PSUBUW | |
| + }, | |
| + { CODE_FOR_mips5900_psubw, "__builtin_mips5900_psubw", | |
| + MIPS5900_BUILTIN_PSUBW | |
| + }, | |
| + { CODE_FOR_mips5900_pxor, "__builtin_mips5900_pxor", | |
| + MIPS5900_BUILTIN_PXOR | |
| + }, | |
| + { CODE_FOR_mips5900_qfsrv, "__builtin_mips5900_qfsrv", | |
| + MIPS5900_BUILTIN_QFSRV | |
| + }, | |
| + { CODE_FOR_mips5900_pdivbw, "__builtin_mips5900_pdivbw", | |
| + MIPS5900_BUILTIN_PDIVBW | |
| + }, | |
| + { CODE_FOR_mips5900_pdivuw, "__builtin_mips5900_pdivuw", | |
| + MIPS5900_BUILTIN_PDIVUW | |
| + }, | |
| + { CODE_FOR_mips5900_pdivw, "__builtin_mips5900_pdivw", | |
| + MIPS5900_BUILTIN_PDIVW | |
| + }, | |
| + { CODE_FOR_mips5900_phmadh, "__builtin_mips5900_phmadh", | |
| + MIPS5900_BUILTIN_PHMADH | |
| + }, | |
| + { CODE_FOR_mips5900_phmsbh, "__builtin_mips5900_phmsbh", | |
| + MIPS5900_BUILTIN_PHMSBH | |
| + }, | |
| + { CODE_FOR_mips5900_pmaddh, "__builtin_mips5900_pmaddh", | |
| + MIPS5900_BUILTIN_PMADDH | |
| + }, | |
| + { CODE_FOR_mips5900_pmadduw, "__builtin_mips5900_pmadduw", | |
| + MIPS5900_BUILTIN_PMADDUW | |
| + }, | |
| + { CODE_FOR_mips5900_pmaddw, "__builtin_mips5900_pmaddw", | |
| + MIPS5900_BUILTIN_PMADDW | |
| + }, | |
| + { CODE_FOR_mips5900_pmsubh, "__builtin_mips5900_pmsubh", | |
| + MIPS5900_BUILTIN_PMSUBH | |
| + }, | |
| + { CODE_FOR_mips5900_pmsubw, "__builtin_mips5900_pmsubw", | |
| + MIPS5900_BUILTIN_PMSUBW | |
| + }, | |
| + { CODE_FOR_mips5900_pmulth, "__builtin_mips5900_pmulth", | |
| + MIPS5900_BUILTIN_PMULTH | |
| + }, | |
| + { CODE_FOR_mips5900_pmultuw, "__builtin_mips5900_pmultuw", | |
| + MIPS5900_BUILTIN_PMULTUW | |
| + }, | |
| + { CODE_FOR_mips5900_pmultw, "__builtin_mips5900_pmultw", | |
| + MIPS5900_BUILTIN_PMULTW | |
| + }, | |
| +}; | |
| + | |
| +/* Table describing builtin functions which are shift-by-constant operations. */ | |
| +static struct builtin_description bdesc_shiftc[] = | |
| +{ | |
| + { CODE_FOR_mips5900_psllh, "__builtin_mips5900_psllh", | |
| + MIPS5900_BUILTIN_PSLLH | |
| + }, | |
| + { CODE_FOR_mips5900_psllw, "__builtin_mips5900_psllw", | |
| + MIPS5900_BUILTIN_PSLLW | |
| + }, | |
| + { CODE_FOR_mips5900_psrah, "__builtin_mips5900_psrah", | |
| + MIPS5900_BUILTIN_PSRAH | |
| + }, | |
| + { CODE_FOR_mips5900_psraw, "__builtin_mips5900_psraw", | |
| + MIPS5900_BUILTIN_PSRAW | |
| + }, | |
| + { CODE_FOR_mips5900_psrlh, "__builtin_mips5900_psrlh", | |
| + MIPS5900_BUILTIN_PSRLH | |
| + }, | |
| + { CODE_FOR_mips5900_psrlw, "__builtin_mips5900_psrlw", | |
| + MIPS5900_BUILTIN_PSRLW | |
| + } | |
| +}; | |
| + | |
| +/* Table describing builtin functions which are move-to-sa-size operations. */ | |
| +static struct builtin_description bdesc_mtsax[] = | |
| +{ | |
| + { CODE_FOR_mips5900_mtsab, "__builtin_mips5900_mtsab", | |
| + MIPS5900_BUILTIN_MTSAB | |
| + }, | |
| + { CODE_FOR_mips5900_mtsah, "__builtin_mips5900_mtsah", | |
| + MIPS5900_BUILTIN_MTSAH | |
| + } | |
| +}; | |
| + | |
| +/* Table describing builtin functions which are move-to-special-purpose-register | |
| + operations. */ | |
| +static struct builtin_description bdesc_mfspr[] = | |
| +{ | |
| + { CODE_FOR_mips5900_mfsa, "__builtin_mips5900_mfsa", | |
| + MIPS5900_BUILTIN_MFSA | |
| + }, | |
| + { CODE_FOR_mips5900_pmfhi, "__builtin_mips5900_pmfhi", | |
| + MIPS5900_BUILTIN_PMFHI | |
| + }, | |
| + { CODE_FOR_mips5900_pmflo, "__builtin_mips5900_pmflo", | |
| + MIPS5900_BUILTIN_PMFLO | |
| + }, | |
| + { CODE_FOR_mips5900_pmfhl_lw, "__builtin_mips5900_pmfhl_lw", | |
| + MIPS5900_BUILTIN_PMFHL_LW | |
| + }, | |
| + { CODE_FOR_mips5900_pmfhl_uw, "__builtin_mips5900_pmfhl_uw", | |
| + MIPS5900_BUILTIN_PMFHL_UW | |
| + }, | |
| + { CODE_FOR_mips5900_pmfhl_slw, "__builtin_mips5900_pmfhl_slw", | |
| + MIPS5900_BUILTIN_PMFHL_SLW | |
| + }, | |
| + { CODE_FOR_mips5900_pmfhl_lh, "__builtin_mips5900_pmfhl_lh", | |
| + MIPS5900_BUILTIN_PMFHL_LH | |
| + }, | |
| + { CODE_FOR_mips5900_pmfhl_sh, "__builtin_mips5900_pmfhl_sh", | |
| + MIPS5900_BUILTIN_PMFHL_SH | |
| + } | |
| +}; | |
| + | |
| +/* Table describing builtin functions which are | |
| + move-from-special-purpose-register operations. */ | |
| +static struct builtin_description bdesc_mtspr[] = | |
| +{ | |
| + { CODE_FOR_mips5900_mtsa, "__builtin_mips5900_mtsa", | |
| + MIPS5900_BUILTIN_MTSA | |
| + }, | |
| + { CODE_FOR_mips5900_pmthi, "__builtin_mips5900_pmthi", | |
| + MIPS5900_BUILTIN_PMTHI | |
| + }, | |
| + { CODE_FOR_mips5900_pmtlo, "__builtin_mips5900_pmtlo", | |
| + MIPS5900_BUILTIN_PMTLO | |
| + }, | |
| + { CODE_FOR_mips5900_pmthl_lw, "__builtin_mips5900_pmthl_lw", | |
| + MIPS5900_BUILTIN_PMTHL_LW | |
| + } | |
| +}; | |
| + | |
| +void | |
| +mips_init_builtins () | |
| +{ | |
| + tree endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE); | |
| + struct builtin_description *d; | |
| + unsigned int i; | |
| + | |
| + /* Type nodes for unary builtin functions. */ | |
| + tree v8hi_ftype_v8hi | |
| + = build_function_type (V8HI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + endlink)); | |
| + | |
| + tree v8hi_ftype_v4si | |
| + = build_function_type (V8HI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + endlink)); | |
| + | |
| + tree v4si_ftype_v4si | |
| + = build_function_type (V4SI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + endlink)); | |
| + | |
| + tree v4si_ftype_v8hi | |
| + = build_function_type (V4SI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + endlink)); | |
| + | |
| + tree v2si_ftype_v2si | |
| + = build_function_type (V2SI_type_node, | |
| + tree_cons (NULL_TREE, V2SI_type_node, | |
| + endlink)); | |
| + | |
| + /* Type nodes for binary builtin functions. */ | |
| + tree v16qi_ftype_v16qi_v16qi | |
| + = build_function_type (V16QI_type_node, | |
| + tree_cons (NULL_TREE, V16QI_type_node, | |
| + tree_cons (NULL_TREE, V16QI_type_node, | |
| + endlink))); | |
| + tree v8hi_ftype_v8hi_v8hi | |
| + = build_function_type (V8HI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + endlink))); | |
| + tree v4si_ftype_v8hi_v8hi | |
| + = build_function_type (V4SI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + endlink))); | |
| + tree v4si_ftype_v4si_v4si | |
| + = build_function_type (V4SI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + endlink))); | |
| + tree v2di_ftype_v4si_v4si | |
| + = build_function_type (V2DI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + endlink))); | |
| + tree v2di_ftype_v2di_v2di | |
| + = build_function_type (V2DI_type_node, | |
| + tree_cons (NULL_TREE, V2DI_type_node, | |
| + tree_cons (NULL_TREE, V2DI_type_node, | |
| + endlink))); | |
| + tree void_ftype_v4si_v8hi | |
| + = build_function_type (void_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + endlink))); | |
| + /* Type nodes for shift-by-constant functions. */ | |
| + tree v8hi_ftype_v8hi_int | |
| + = build_function_type (V8HI_type_node, | |
| + tree_cons (NULL_TREE, V8HI_type_node, | |
| + tree_cons (NULL_TREE, integer_type_node, | |
| + endlink))); | |
| + tree v4si_ftype_v4si_int | |
| + = build_function_type (V4SI_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + tree_cons (NULL_TREE, integer_type_node, | |
| + endlink))); | |
| + /* Type nodes used by the funnel shift builtins. */ | |
| + tree void_ftype_int_int | |
| + = build_function_type (void_type_node, | |
| + tree_cons (NULL_TREE, integer_type_node, | |
| + tree_cons (NULL_TREE, integer_type_node, | |
| + endlink))); | |
| + tree void_ftype_di | |
| + = build_function_type (void_type_node, | |
| + tree_cons (NULL_TREE, long_integer_type_node, | |
| + endlink)); | |
| + tree di_ftype_void | |
| + = build_function_type (long_integer_type_node, | |
| + tree_cons (NULL_TREE, void_type_node, | |
| + endlink)); | |
| + tree ti_ftype_ti_ti | |
| + = build_function_type (intTI_type_node, | |
| + tree_cons (NULL_TREE, intTI_type_node, | |
| + tree_cons (NULL_TREE, intTI_type_node, | |
| + endlink))); | |
| + /* Moves to and from HI and LO */ | |
| + tree v2di_ftype_void | |
| + = build_function_type (V2DI_type_node, | |
| + tree_cons (NULL_TREE, void_type_node, | |
| + endlink)); | |
| + tree v4si_ftype_void | |
| + = build_function_type (V4SI_type_node, | |
| + tree_cons (NULL_TREE, void_type_node, | |
| + endlink)); | |
| + tree v8hi_ftype_void | |
| + = build_function_type (V8HI_type_node, | |
| + tree_cons (NULL_TREE, void_type_node, | |
| + endlink)); | |
| + tree void_ftype_v4si | |
| + = build_function_type (void_type_node, | |
| + tree_cons (NULL_TREE, V4SI_type_node, | |
| + endlink)); | |
| + tree void_ftype_v2di | |
| + = build_function_type (void_type_node, | |
| + tree_cons (NULL_TREE, V2DI_type_node, | |
| + endlink)); | |
| + /* Now define the builtins. */ | |
| + /* Add all builtins that are simple operations on one operand. */ | |
| + for (i = 0, d = bdesc_1arg; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++) | |
| + { | |
| + /* Use one of the operands; the target can have a different mode for | |
| + mask-generating compares. */ | |
| + enum machine_mode mode; | |
| + tree type; | |
| + | |
| + if (d->name == 0) | |
| + continue; | |
| + | |
| + mode = insn_data[d->icode].operand[1].mode; | |
| + | |
| + switch (mode) | |
| + { | |
| + case V8HImode: | |
| + if (d->icode == CODE_FOR_mips5900_ppac5) | |
| + type = v8hi_ftype_v4si; | |
| + else | |
| + type = v8hi_ftype_v8hi; | |
| + break; | |
| + case V4SImode: | |
| + if (d->icode == CODE_FOR_mips5900_pext5) | |
| + type = v4si_ftype_v8hi; | |
| + else | |
| + type = v4si_ftype_v4si; | |
| + break; | |
| + case V2SImode: | |
| + type = v2si_ftype_v2si; | |
| + break; | |
| + default: | |
| + abort (); | |
| + } | |
| + def_builtin (d->name, type, d->code); | |
| + } | |
| + | |
| + /* Add all builtins that are simple operations on two operands. */ | |
| + for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++) | |
| + { | |
| + /* Use one of the operands; the target can have a different mode for | |
| + mask-generating compares. */ | |
| + enum machine_mode mode; | |
| + tree type; | |
| + | |
| + if (d->name == 0) | |
| + continue; | |
| + | |
| + mode = insn_data[d->icode].operand[1].mode; | |
| + | |
| + switch (mode) | |
| + { | |
| + case V16QImode: | |
| + type = v16qi_ftype_v16qi_v16qi; | |
| + break; | |
| + case V8HImode: | |
| + if (insn_data[d->icode].operand[0].mode == V4SImode) | |
| + type = v4si_ftype_v8hi_v8hi; | |
| + else | |
| + type = v8hi_ftype_v8hi_v8hi; | |
| + break; | |
| + case V4SImode: | |
| + if (d->icode == CODE_FOR_mips5900_pdivbw) | |
| + type = void_ftype_v4si_v8hi; | |
| + else if (insn_data[d->icode].operand[0].mode == V2DImode) | |
| + type = v2di_ftype_v4si_v4si; | |
| + else | |
| + type = v4si_ftype_v4si_v4si; | |
| + break; | |
| + case V2DImode: | |
| + type = v2di_ftype_v2di_v2di; | |
| + break; | |
| + case TImode: | |
| + type = ti_ftype_ti_ti; | |
| + break; | |
| + default: | |
| + abort (); | |
| + } | |
| + def_builtin (d->name, type, d->code); | |
| + } | |
| + | |
| + /* Add all builtins that are shift-by-constant operations. */ | |
| + for (i = 0, d = bdesc_shiftc; i < sizeof (bdesc_shiftc) / sizeof *d; i++, d++) | |
| + { | |
| + /* Use one of the operands; the target can have a different mode for | |
| + mask-generating compares. */ | |
| + enum machine_mode mode; | |
| + tree type; | |
| + | |
| + if (d->name == 0) | |
| + continue; | |
| + | |
| + mode = insn_data[d->icode].operand[1].mode; | |
| + | |
| + switch (mode) | |
| + { | |
| + case V8HImode: | |
| + type = v8hi_ftype_v8hi_int; | |
| + break; | |
| + case V4SImode: | |
| + type = v4si_ftype_v4si_int; | |
| + break; | |
| + default: | |
| + abort (); | |
| + } | |
| + def_builtin (d->name, type, d->code); | |
| + } | |
| + | |
| + /* Add all builtins that are move-to-sa-size operations. */ | |
| + for (i = 0, d = bdesc_mtsax; i < sizeof (bdesc_mtsax) / sizeof *d; i++, d++) | |
| + { | |
| + /* Use one of the operands; the target can have a different mode for | |
| + mask-generating compares. */ | |
| + if (d->name == 0) | |
| + continue; | |
| + | |
| + def_builtin (d->name, void_ftype_int_int, d->code); | |
| + } | |
| + | |
| + /* Add all builtins that are move-from-special-purpose-register operations. */ | |
| + for (i = 0, d = bdesc_mfspr; i < sizeof (bdesc_mfspr) / sizeof *d; i++, d++) | |
| + { | |
| + /* Use one of the operands; the target can have a different mode for | |
| + mask-generating compares. */ | |
| + enum machine_mode mode; | |
| + tree type; | |
| + | |
| + if (d->name == 0) | |
| + continue; | |
| + | |
| + mode = insn_data[d->icode].operand[0].mode; | |
| + | |
| + switch (mode) | |
| + { | |
| + case DImode: | |
| + type = di_ftype_void; | |
| + break; | |
| + case V2DImode: | |
| + type = v2di_ftype_void; | |
| + break; | |
| + case V4SImode: | |
| + type = v4si_ftype_void; | |
| + break; | |
| + case V8HImode: | |
| + type = v8hi_ftype_void; | |
| + break; | |
| + default: | |
| + abort (); | |
| + } | |
| + def_builtin (d->name, type, d->code); | |
| + } | |
| + | |
| + /* Add all builtins that are move-to-special-purpose-register operations. */ | |
| + for (i = 0, d = bdesc_mtspr; i < sizeof (bdesc_mtspr) / sizeof *d; i++, d++) | |
| + { | |
| + /* Use one of the operands; the target can have a different mode for | |
| + mask-generating compares. */ | |
| + enum machine_mode mode; | |
| + tree type; | |
| + | |
| + if (d->name == 0) | |
| + continue; | |
| + | |
| + mode = insn_data[d->icode].operand[0].mode; | |
| + | |
| + switch (mode) | |
| + { | |
| + case DImode: | |
| + type = void_ftype_di; | |
| + break; | |
| + case V4SImode: | |
| + type = void_ftype_v4si; | |
| + break; | |
| + case V2DImode: | |
| + type = void_ftype_v2di; | |
| + break; | |
| + default: | |
| + abort (); | |
| + } | |
| + | |
| + def_builtin (d->name, type, d->code); | |
| + } | |
| +} | |
| + | |
| +/* Errors in the source file can cause expand_expr to return const0_rtx | |
| + where we expect a vector. To avoid crashing, use one of the vector | |
| + clear instructions. */ | |
| + | |
| +static rtx | |
| +safe_vector_operand (x, mode) | |
| + rtx x; | |
| + enum machine_mode mode; | |
| +{ | |
| + if (x != const0_rtx) | |
| + return x; | |
| + return gen_reg_rtx (mode); | |
| +} | |
| + | |
| +static rtx | |
| +mips_expand_unop_builtin (icode, arglist, target) | |
| + enum insn_code icode; | |
| + tree arglist; | |
| + rtx target; | |
| +{ | |
| + tree arg0; | |
| + rtx op0; | |
| + rtx pat; | |
| + enum machine_mode tmode, mode0; | |
| + | |
| + arg0 = TREE_VALUE (arglist); | |
| + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); | |
| + tmode = insn_data[icode].operand[0].mode; | |
| + mode0 = insn_data[icode].operand[1].mode; | |
| + | |
| + if (VECTOR_MODE_P (mode0)) | |
| + op0 = safe_vector_operand (op0, mode0); | |
| + | |
| + if (target == 0 | |
| + || GET_MODE (target) != tmode | |
| + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) | |
| + target = gen_reg_rtx (tmode); | |
| + | |
| + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) | |
| + op0 = copy_to_mode_reg (mode0, op0); | |
| + | |
| + pat = GEN_FCN (icode) (target, op0); | |
| + | |
| + if (! pat) | |
| + return safe_vector_operand (const0_rtx, tmode); | |
| + | |
| + emit_insn (pat); | |
| + return target; | |
| +} | |
| + | |
| +static rtx | |
| +mips_expand_binop_builtin (d, arglist, target) | |
| + struct builtin_description *d; | |
| + tree arglist; | |
| + rtx target; | |
| +{ | |
| + rtx pat; | |
| + tree arg0 = TREE_VALUE (arglist); | |
| + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
| + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); | |
| + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); | |
| + enum insn_code icode = d->icode; | |
| + enum machine_mode tmode = insn_data[d->icode].operand[0].mode; | |
| + enum machine_mode mode0 = insn_data[d->icode].operand[1].mode; | |
| + enum machine_mode mode1 = insn_data[d->icode].operand[2].mode; | |
| + | |
| + if (VECTOR_MODE_P (mode0)) | |
| + op0 = safe_vector_operand (op0, mode0); | |
| + if (VECTOR_MODE_P (mode1)) | |
| + op1 = safe_vector_operand (op1, mode1); | |
| + | |
| + if (! target | |
| + || GET_MODE (target) != tmode | |
| + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) | |
| + target = gen_reg_rtx (tmode); | |
| + | |
| + /* In case the insn wants input operands in modes different from | |
| + the result, abort. */ | |
| + if (GET_MODE (op0) != mode0 || GET_MODE (op1) != mode1) | |
| + abort (); | |
| + | |
| + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) | |
| + op0 = copy_to_mode_reg (mode0, op0); | |
| + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) | |
| + op1 = copy_to_mode_reg (mode1, op1); | |
| + | |
| + pat = GEN_FCN (icode) (target, op0, op1); | |
| + if (! pat) | |
| + return safe_vector_operand (const0_rtx, tmode); | |
| + emit_insn (pat); | |
| + | |
| + return target; | |
| +} | |
| + | |
| +static rtx | |
| +mips_expand_shiftc_builtin (d, arglist, target) | |
| + struct builtin_description *d; | |
| + tree arglist; | |
| + rtx target; | |
| +{ | |
| + rtx pat; | |
| + tree arg0 = TREE_VALUE (arglist); | |
| + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
| + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); | |
| + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); | |
| + enum insn_code icode = d->icode; | |
| + enum machine_mode tmode = insn_data[d->icode].operand[0].mode; | |
| + enum machine_mode mode0 = insn_data[d->icode].operand[1].mode; | |
| + | |
| + if (VECTOR_MODE_P (mode0)) | |
| + op0 = safe_vector_operand (op0, mode0); | |
| + | |
| + if (! target | |
| + || GET_MODE (target) != tmode | |
| + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) | |
| + target = gen_reg_rtx (tmode); | |
| + | |
| + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) | |
| + op0 = copy_to_mode_reg (mode0, op0); | |
| + | |
| + /* In case the insn wants input operands in modes different from | |
| + the result, abort. */ | |
| + if (GET_MODE (op0) != mode0) | |
| + abort (); | |
| + | |
| + if (GET_CODE (op1) != CONST_INT) | |
| + { | |
| + error ("second argument of '%s' must be an integer constant", d->name); | |
| + return safe_vector_operand (const0_rtx, tmode); | |
| + } | |
| + | |
| + pat = GEN_FCN (icode) (target, op0, op1); | |
| + if (! pat) | |
| + return safe_vector_operand (const0_rtx, tmode); | |
| + emit_insn (pat); | |
| + | |
| + return target; | |
| +} | |
| + | |
| +static rtx | |
| +mips_expand_mtsax_builtin (d, arglist) | |
| + struct builtin_description *d; | |
| + tree arglist; | |
| +{ | |
| + rtx pat; | |
| + tree arg0 = TREE_VALUE (arglist); | |
| + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
| + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); | |
| + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); | |
| + enum insn_code icode = d->icode; | |
| + enum machine_mode mode0 = insn_data[d->icode].operand[0].mode; | |
| + | |
| + if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) | |
| + op0 = copy_to_mode_reg (mode0, op0); | |
| + | |
| + /* In case the insn wants input operands in modes different from | |
| + the result, abort. */ | |
| + if (GET_MODE (op0) != mode0) | |
| + abort (); | |
| + | |
| + if (GET_CODE (op1) != CONST_INT) | |
| + { | |
| + error ("second argument of '%s' must be an integer constant", d->name); | |
| + return NULL_RTX; | |
| + } | |
| + | |
| + pat = GEN_FCN (icode) (op0, op1); | |
| + if (pat) | |
| + emit_insn (pat); | |
| + | |
| + return NULL_RTX; | |
| +} | |
| + | |
| +static rtx | |
| +mips_expand_mfspr_builtin (icode, target) | |
| + enum insn_code icode; | |
| + rtx target; | |
| +{ | |
| + rtx pat; | |
| + enum machine_mode tmode = insn_data[icode].operand[0].mode; | |
| + | |
| + if (target == 0 | |
| + || GET_MODE (target) != tmode | |
| + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) | |
| + target = gen_reg_rtx (tmode); | |
| + | |
| + pat = GEN_FCN (icode) (target, GEN_INT(0)); | |
| + if (! pat) | |
| + return const0_rtx; | |
| + emit_insn (pat); | |
| + | |
| + return target; | |
| +} | |
| + | |
| +static rtx | |
| +mips_expand_mtspr_builtin (icode, arglist) | |
| + enum insn_code icode; | |
| + tree arglist; | |
| +{ | |
| + rtx pat; | |
| + tree arg0 = TREE_VALUE (arglist); | |
| + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); | |
| + enum machine_mode mode0 = insn_data[icode].operand[0].mode; | |
| + | |
| + if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) | |
| + op0 = copy_to_mode_reg (mode0, op0); | |
| + | |
| + /* In case the insn wants input operands in modes different from | |
| + the result, abort. */ | |
| + if (GET_MODE (op0) != mode0) | |
| + abort (); | |
| + | |
| + pat = GEN_FCN (icode) (op0); | |
| + if (pat) | |
| + emit_insn (pat); | |
| + | |
| + return NULL_RTX; | |
| +} | |
| + | |
| +/* 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. */ | |
| + | |
| +rtx | |
| +mips_expand_builtin (exp, target, subtarget, mode, ignore) | |
| + tree exp; | |
| + rtx target; | |
| + rtx subtarget ATTRIBUTE_UNUSED; | |
| + enum machine_mode mode ATTRIBUTE_UNUSED; | |
| + int ignore ATTRIBUTE_UNUSED; | |
| +{ | |
| + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); | |
| + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); | |
| + tree arglist = TREE_OPERAND (exp, 1); | |
| + struct builtin_description *d; | |
| + unsigned int i; | |
| + | |
| + for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++) | |
| + if (d->code == fcode) | |
| + return mips_expand_binop_builtin (d, arglist, target); | |
| + | |
| + for (i = 0, d = bdesc_1arg; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++) | |
| + if (d->code == fcode) | |
| + return mips_expand_unop_builtin (d->icode, arglist, target); | |
| + | |
| + for (i = 0, d = bdesc_shiftc; i < sizeof (bdesc_shiftc) / sizeof *d; i++, d++) | |
| + if (d->code == fcode) | |
| + return mips_expand_shiftc_builtin (d, arglist, target); | |
| + | |
| + for (i = 0, d = bdesc_mtsax; i < sizeof (bdesc_mtsax) / sizeof *d; i++, d++) | |
| + if (d->code == fcode) | |
| + return mips_expand_mtsax_builtin (d, arglist); | |
| + | |
| + for (i = 0, d = bdesc_mfspr; i < sizeof (bdesc_mfspr) / sizeof *d; i++, d++) | |
| + if (d->code == fcode) | |
| + return mips_expand_mfspr_builtin (d->icode, target); | |
| + | |
| + for (i = 0, d = bdesc_mtspr; i < sizeof (bdesc_mtspr) / sizeof *d; i++, d++) | |
| + if (d->code == fcode) | |
| + return mips_expand_mtspr_builtin (d->icode, arglist); | |
| + | |
| + /* @@@ Should really do something sensible here. */ | |
| + abort (); | |
| + return const0_rtx; | |
| +} | |
| + | |
| +static int | |
| +mips_arg_pointer_elimination1 (addrp, data) | |
| + rtx *addrp; | |
| + void *data; | |
| +{ | |
| + rtx addr = *addrp; | |
| + rtx eliminate_to | |
| + = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx; | |
| + | |
| + if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == arg_pointer_rtx) | |
| + *addrp = gen_rtx_PLUS (Pmode, eliminate_to, | |
| + plus_constant (XEXP (addr, 1), | |
| + current_frame_info.total_size)); | |
| + else if (addr == arg_pointer_rtx) | |
| + *addrp = gen_rtx_PLUS (Pmode, eliminate_to, | |
| + GEN_INT (current_frame_info.total_size)); | |
| + else if (GET_CODE (addr) == PLUS | |
| + && XEXP (addr, 0) == return_address_pointer_rtx) | |
| + *addrp = gen_rtx_PLUS (Pmode, eliminate_to, | |
| + plus_constant (XEXP (addr, 1), | |
| + current_frame_info.rap_offset)); | |
| + else if (addr == return_address_pointer_rtx) | |
| + *addrp = gen_rtx_PLUS (Pmode, eliminate_to, | |
| + GEN_INT (current_frame_info.rap_offset)); | |
| + else return 0; | |
| + | |
| + *(int *) data = 1; | |
| + return -1; | |
| +} | |
| + | |
| +static void | |
| +mips_arg_pointer_elimination (first) | |
| + rtx first; | |
| +{ | |
| + HOST_WIDE_INT offset = current_frame_info.total_size; | |
| + for (; first; first = NEXT_INSN (first)) | |
| + { | |
| + int tmp_flag; | |
| + | |
| + if (GET_CODE (first) != INSN) | |
| + continue; | |
| + | |
| + tmp_flag = 0; | |
| + for_each_rtx (&PATTERN (first), mips_arg_pointer_elimination1, | |
| + &tmp_flag); | |
| + if (tmp_flag) | |
| + INSN_CODE (first) = -1; | |
| + } | |
| +} | |
| --- gcc-2.96-20000731/gcc/config/mips/mips.md 2000-07-15 18:53:05.000000000 -0500 | |
| +++ ee/gcc/src/gcc/config/mips/mips.md 2000-11-06 22:30:04.000000000 -0600 | |
| @@ -41,11 +41,14 @@ | |
| ;; load load instruction(s) | |
| ;; store store instruction(s) | |
| ;; move data movement within same register set | |
| +;; cmove conditional move instructions | |
| ;; xfer transfer to/from coprocessor | |
| ;; hilo transfer of hi/lo registers | |
| -;; arith integer arithmetic instruction | |
| +;; arith integer arithmetic instruction (that aren't shifts) | |
| ;; darith double precision integer arithmetic instructions | |
| +;; shift integer shift instructions | |
| ;; imul integer multiply | |
| +;; imul3 integer multiply 3 operand | |
| ;; idiv integer divide | |
| ;; icmp integer compare | |
| ;; fadd floating point add/subtract | |
| @@ -57,15 +60,16 @@ | |
| ;; fcmp floating point compare | |
| ;; fcvt floating point convert | |
| ;; fsqrt floating point square root | |
| +;; frsqrt floating point reciprocal square root | |
| ;; multi multiword sequence (or user asm statements) | |
| ;; nop no operation | |
| (define_attr "type" | |
| - "unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop" | |
| + "unknown,branch,jump,call,load,store,move,cmove,xfer,hilo,arith,darith,shift,imul,imul3,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop,simd" ; CYGNUS LOCAL vr5400/raeburn | |
| (const_string "unknown")) | |
| ;; Main data type used by the insn | |
| -(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF,FPSW" (const_string "unknown")) | |
| +(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,FPSW,V16QI,V8HI,V4SI,V2DI,V2SI" (const_string "unknown")) | |
| ;; Length (in # of bytes). A conditional branch is allowed only to a | |
| ;; location within a signed 18-bit offset of the delay slot. If that | |
| @@ -98,7 +102,7 @@ | |
| ;; ??? Fix everything that tests this attribute. | |
| (define_attr "cpu" | |
| - "default,r3000,r3900,r6000,r4000,r4100,r4300,r4600,r4650,r5000,r8000" | |
| + "default,r3000,r3900,r6000,r4000,r4100,r4300,r4600,r4650,r5000,r5400,r5900,r8000,r4kc,r5kc,r20kc" ; CYGNUS LOCAL vr5400/raeburn | |
| (const (symbol_ref "mips_cpu_attr"))) | |
| ;; Does the instruction have a mandatory delay slot? | |
| @@ -169,28 +173,33 @@ | |
| (define_function_unit "memory" 1 0 | |
| (and (eq_attr "type" "load") | |
| - (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4100,r4300,r5000")) | |
| + (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4100,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn | |
| 3 0) | |
| (define_function_unit "memory" 1 0 | |
| (and (eq_attr "type" "load") | |
| - (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4300,r5000")) | |
| + (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4300,r5000,r5400")) ; CYGNUS LOCAL vr5400/raeburn | |
| 2 0) | |
| -(define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0) | |
| +;; CYGNUS LOCAL law | |
| +(define_function_unit "memory" 1 0 | |
| + (and (eq_attr "type" "store") (eq_attr "cpu" "!r5900")) 1 0) | |
| -(define_function_unit "memory" 1 0 (eq_attr "type" "xfer") 2 0) | |
| +(define_function_unit "memory" 1 0 | |
| + (and (eq_attr "type" "xfer") (eq_attr "cpu" "!r5900")) 2 0) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (eq_attr "type" "hilo") | |
| + (and (eq_attr "type" "hilo") | |
| + (eq_attr "cpu" "!r5900")) | |
| 1 3) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") | |
| - (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000")) | |
| + (and (eq_attr "type" "imul,imul3") | |
| + (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn | |
| 17 17) | |
| +;; END CYGNUS LOCAL | |
| -;; On them mips16, we want to stronly discourage a mult from appearing | |
| +;; On them mips16, we want to strongly discourage a mult from appearing | |
| ;; after an mflo, since that requires explicit nop instructions. We | |
| ;; do this by pretending that mflo ties up the function unit for long | |
| ;; enough that the scheduler will ignore load stalls and the like when | |
| @@ -201,45 +210,57 @@ | |
| 1 5) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") (eq_attr "cpu" "r3000,r3900")) | |
| + (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r3000,r3900")) | |
| 12 12) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") (eq_attr "cpu" "r4000,r4600")) | |
| + (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r4000,r4600")) | |
| 10 10) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") (eq_attr "cpu" "r4650")) | |
| + (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r4650")) | |
| 4 4) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") | |
| + (and (eq_attr "type" "imul,imul3") | |
| (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100"))) | |
| 1 1) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") | |
| + (and (eq_attr "type" "imul,imul3") | |
| (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100"))) | |
| 4 4) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") | |
| + (and (eq_attr "type" "imul,imul3") | |
| (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300,r5000"))) | |
| 5 5) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") | |
| + (and (eq_attr "type" "imul,imul3") | |
| (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300"))) | |
| 8 8) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (eq_attr "type" "imul") | |
| + (and (eq_attr "type" "imul,imul3") | |
| (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000"))) | |
| 9 9) | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| +(define_function_unit "imuldiv" 1 0 | |
| + (and (eq_attr "type" "imul,imul3") | |
| + (and (eq_attr "mode" "SI") (eq_attr "cpu" "r5400"))) | |
| + 3 1) | |
| + | |
| +(define_function_unit "imuldiv" 1 0 | |
| + (and (eq_attr "type" "imul,imul3") | |
| + (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5400"))) | |
| + 4 2) | |
| +;; END CYGNUS LOCAL | |
| + | |
| (define_function_unit "imuldiv" 1 0 | |
| (and (eq_attr "type" "idiv") | |
| - (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000")) | |
| + (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn | |
| 38 38) | |
| (define_function_unit "imuldiv" 1 0 | |
| @@ -288,6 +309,18 @@ | |
| (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000"))) | |
| 68 68) | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| +(define_function_unit "imuldiv" 1 0 | |
| + (and (eq_attr "type" "idiv") | |
| + (and (eq_attr "mode" "SI") (eq_attr "cpu" "r5400"))) | |
| + 34 34) | |
| + | |
| +(define_function_unit "imuldiv" 1 0 | |
| + (and (eq_attr "type" "idiv") | |
| + (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5400"))) | |
| + 66 66) | |
| +;; END CYGNUS LOCAL | |
| + | |
| ;; 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 | |
| @@ -296,7 +329,7 @@ | |
| ;; 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,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn | |
| 3 0) | |
| (define_function_unit "adder" 1 1 | |
| @@ -308,7 +341,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,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn | |
| 4 0) | |
| (define_function_unit "adder" 1 1 | |
| @@ -321,7 +354,7 @@ | |
| (define_function_unit "adder" 1 1 | |
| (and (eq_attr "type" "fabs,fneg") | |
| - (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4300,r5000")) | |
| + (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn | |
| 2 0) | |
| (define_function_unit "adder" 1 1 | |
| @@ -331,7 +364,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,r5400,r5900"))) ; CYGNUS LOCAL vr5400/raeburn | |
| 7 0) | |
| (define_function_unit "mult" 1 1 | |
| @@ -351,7 +384,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,r5400"))) ; CYGNUS LOCAL vr5400/raeburn | |
| 8 0) | |
| (define_function_unit "mult" 1 1 | |
| @@ -367,7 +400,7 @@ | |
| (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,r5400,r5900"))) ; CYGNUS LOCAL vr5400/raeburn | |
| 23 0) | |
| (define_function_unit "divide" 1 1 | |
| @@ -393,7 +426,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,r5400"))) ; CYGNUS LOCAL vr5400/raeburn | |
| 36 0) | |
| (define_function_unit "divide" 1 1 | |
| @@ -413,33 +446,33 @@ | |
| ;;; ??? Is this number right? | |
| (define_function_unit "divide" 1 1 | |
| - (and (eq_attr "type" "fsqrt") | |
| - (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000"))) | |
| + (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| + (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000,r5400,r5900"))) ; CYGNUS LOCAL vr5400/raeburn | |
| 54 0) | |
| (define_function_unit "divide" 1 1 | |
| - (and (eq_attr "type" "fsqrt") | |
| + (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650"))) | |
| 31 0) | |
| (define_function_unit "divide" 1 1 | |
| - (and (eq_attr "type" "fsqrt") | |
| + (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| (and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000"))) | |
| 21 0) | |
| ;;; ??? Is this number right? | |
| (define_function_unit "divide" 1 1 | |
| - (and (eq_attr "type" "fsqrt") | |
| - (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000"))) | |
| + (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| + (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000,r5400"))) ; CYGNUS LOCAL vr5400/raeburn | |
| 112 0) | |
| (define_function_unit "divide" 1 1 | |
| - (and (eq_attr "type" "fsqrt") | |
| + (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650"))) | |
| 60 0) | |
| (define_function_unit "divide" 1 1 | |
| - (and (eq_attr "type" "fsqrt") | |
| + (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| (and (eq_attr "mode" "DF") (eq_attr "cpu" "r5000"))) | |
| 36 0) | |
| @@ -462,14 +495,144 @@ | |
| 8 8) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt")) | |
| + (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt,frsqrt")) ; CYGNUS LOCAL vr5400/raeburn | |
| (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4300"))) | |
| 29 29) | |
| (define_function_unit "imuldiv" 1 0 | |
| - (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt")) | |
| + (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt,frsqrt")) ; CYGNUS LOCAL vr5400/raeburn | |
| (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4300"))) | |
| 58 58) | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (eq_attr "type" "move,cmove,arith,darith,shift,icmp,nop") | |
| + (eq_attr "cpu" "r5400")) | |
| + 1 0) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (eq_attr "type" "fadd") | |
| + (eq_attr "cpu" "r5400")) | |
| + 4 3) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (eq_attr "type" "fcmp,fabs,fneg") | |
| + (eq_attr "cpu" "r5400")) | |
| + 2 1) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "fmul") | |
| + (eq_attr "mode" "SF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 5 4) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "fmul") | |
| + (eq_attr "mode" "DF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 6 5) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "fdiv,fsqrt") | |
| + (eq_attr "mode" "SF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 31 30) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "fdiv,fsqrt") | |
| + (eq_attr "mode" "DF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 59 58) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "frsqrt") | |
| + (eq_attr "mode" "SF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 61 60) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "frsqrt") | |
| + (eq_attr "mode" "DF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 121 120) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "fmadd") | |
| + (eq_attr "mode" "SF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 9 8) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (and (eq_attr "type" "fmadd") | |
| + (eq_attr "mode" "DF")) | |
| + (eq_attr "cpu" "r5400")) | |
| + 10 9) | |
| + | |
| +(define_function_unit "alu_5400" 2 0 | |
| + (and (eq_attr "type" "fcvt") | |
| + (eq_attr "cpu" "r5400")) | |
| + 6 5) | |
| +;; END CYGNUS LOCAL | |
| + | |
| +;; Using a value immediately after a load causes a one cycle delay. | |
| +(define_function_unit "memory" 1 0 | |
| + (and (eq_attr "type" "load") (eq_attr "cpu" "r5900")) 2 0) | |
| + | |
| +;; The r5900 has a store buffer which can cause an interlock for | |
| +;; consecutive stores in some cases. So try to separate stores. | |
| +(define_function_unit "memory" 1 0 | |
| + (and (eq_attr "type" "store") (eq_attr "cpu" "r5900")) 2 1) | |
| + | |
| +;; Transfer to/from coprocessor. This is just a guess. There may or | |
| +;; may not be an interlock for such transfers. | |
| +(define_function_unit "memory" 1 0 | |
| + (and (eq_attr "type" "xfer") (eq_attr "cpu" "r5900")) 2 0) | |
| + | |
| +;; The r5900 has two independent ALUs. | |
| +(define_function_unit "alu" 2 0 | |
| + (and (eq_attr "type" "move,cmove,arith,darith,shift,icmp,nop,branch,jump,call") | |
| + (eq_attr "cpu" "r5900")) 1 0) | |
| + | |
| +;; XXX There is differing data between the architecture manual | |
| +;; about what these values should be. | |
| +(define_function_unit "r5900imuldiv" 2 0 | |
| + (and (eq_attr "type" "hilo") (eq_attr "cpu" "r5900")) 1 0) | |
| + | |
| +(define_function_unit "r5900imuldiv" 2 0 | |
| + (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r5900")) 4 1) | |
| + | |
| +(define_function_unit "r5900imuldiv" 2 0 | |
| + (and (eq_attr "type" "idiv") (eq_attr "cpu" "r5900")) 37 36) | |
| + | |
| +;; The r5900 FP unit has three independent units. | |
| +;; fmac -- all computational instructions except fdiv, fsqrt, rsqrt | |
| +;; fdiv -- fdiv, fsqrt, rsqrt | |
| +;; load/store -- load store and transfer unit | |
| +;; | |
| +;; It appears that fmac/fdiv can dual issue with load/store. | |
| +(define_function_unit "fmac" 1 0 | |
| + (and (eq_attr "type" "fadd,fmul,fmadd,fabs,fneg,fcmp,fcvt") | |
| + (eq_attr "cpu" "r5900")) 4 0) | |
| + | |
| +(define_function_unit "fdiv" 1 1 | |
| + (and (eq_attr "type" "fdiv,fsqrt") (eq_attr "cpu" "r5900")) 8 6) | |
| + | |
| +(define_function_unit "fdiv" 1 1 | |
| + (and (eq_attr "type" "frsqrt") (eq_attr "cpu" "r5900")) 14 12) | |
| + | |
| + | |
| +;; And now a few fake units to encourage dual issue. | |
| +;; We can only issue one operation to the FPU per cycle. | |
| +(define_function_unit "flop" 1 0 | |
| + (and (eq_attr "type" | |
| + "fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,xfer") | |
| + (eq_attr "cpu" "r5900")) 1 0) | |
| + | |
| +;; I don't think we need any other fake units to describe common | |
| +;; cases. | |
| + | |
| +;; | |
| + | |
| + | |
| ;; The following functional units do not use the cpu type, and use | |
| ;; much less memory in genattrtab.c. | |
| @@ -481,7 +644,7 @@ | |
| ;; (define_function_unit "transfer" 1 0 (eq_attr "type" "xfer") 2 0) | |
| ;; (define_function_unit "transfer" 1 0 (eq_attr "type" "hilo") 3 0) | |
| ;; | |
| -;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "imul") 17 0) | |
| +;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "imul,imul3") 17 0) | |
| ;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "idiv") 38 0) | |
| ;; | |
| ;; (define_function_unit "adder" 1 1 (eq_attr "type" "fadd") 4 0) | |
| @@ -493,8 +656,12 @@ | |
| ;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "SF")) 23 0) | |
| ;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "DF")) 36 0) | |
| ;; | |
| -;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 0) | |
| -;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 0) | |
| +;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (eq_attr "mode" "SF")) 54 0) CYGNUS LOCAL vr5400/raeburn | |
| +;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (eq_attr "mode" "DF")) 112 0) CYGNUS LOCAL vr5400/raeburn | |
| + | |
| + | |
| + | |
| + | |
| ;; | |
| @@ -542,7 +709,7 @@ | |
| (define_insn "addsi3_internal" | |
| [(set (match_operand:SI 0 "register_operand" "=d") | |
| - (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") | |
| + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJA") | |
| (match_operand:SI 2 "arith_operand" "dI")))] | |
| "! TARGET_MIPS16 | |
| && (TARGET_GAS | |
| @@ -582,7 +749,7 @@ | |
| (define_insn "" | |
| [(set (match_operand:SI 0 "register_operand" "=d,d,d") | |
| - (plus:SI (match_operand:SI 1 "register_operand" "0,d,d") | |
| + (plus:SI (match_operand:SI 1 "register_operand" "0,dA,dA") | |
| (match_operand:SI 2 "arith_operand" "IQ,O,d")))] | |
| "TARGET_MIPS16 | |
| && (GET_CODE (operands[1]) != REG | |
| @@ -1043,6 +1210,104 @@ | |
| (const_int 8)) | |
| (const_int 4)])]) | |
| +(define_expand "addvsi3" | |
| + [(parallel [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") | |
| + (match_operand:SI 2 "arith_operand" "dI"))) | |
| + (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1)) | |
| + (sign_extend:DI (match_dup 2))) | |
| + (sign_extend:DI (plus:SI (match_dup 1) | |
| + (match_dup 2)))) | |
| + (const_int 0))])] | |
| + "" | |
| + " | |
| +{ | |
| + /* The mips16 assembler handles -32768 correctly, and so does gas, | |
| + but some other MIPS assemblers think that -32768 needs to be | |
| + loaded into a register before it can be added in. */ | |
| + if (! TARGET_MIPS16 | |
| + && ! TARGET_GAS | |
| + && GET_CODE (operands[2]) == CONST_INT | |
| + && INTVAL (operands[2]) == -32768) | |
| + operands[2] = force_reg (SImode, operands[2]); | |
| + | |
| + emit_insn (gen_addvsi3_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "addvsi3_internal" | |
| + [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") | |
| + (match_operand:SI 2 "arith_operand" "dI"))) | |
| + (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1)) | |
| + (sign_extend:DI (match_dup 2))) | |
| + (sign_extend:DI (plus:SI (match_dup 1) (match_dup 2)))) | |
| + (const_int 0))] | |
| + "! TARGET_MIPS16 | |
| + && flag_trapv | |
| + && (TARGET_GAS | |
| + || GET_CODE (operands[2]) != CONST_INT | |
| + || INTVAL (operands[2]) != -32768)" | |
| + "add\\t%0,%z1,%2" | |
| + [(set_attr "type" "arith") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "addvdi3" | |
| + [(parallel [(set (match_operand:DI 0 "register_operand" "") | |
| + (plus:DI (match_operand:DI 1 "se_register_operand" "") | |
| + (match_operand:DI 2 "se_arith_operand" ""))) | |
| + (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1)) | |
| + (sign_extend:TI (match_dup 2))) | |
| + (sign_extend:TI (plus:DI (match_dup 1) | |
| + (match_dup 2)))) | |
| + (const_int 0)) | |
| + (clobber (match_dup 3))])] | |
| + "TARGET_64BIT || (! TARGET_DEBUG_G_MODE && ! TARGET_MIPS16)" | |
| + " | |
| +{ | |
| + /* The mips16 assembler handles -32768 correctly, and so does gas, | |
| + but some other MIPS assemblers think that -32768 needs to be | |
| + loaded into a register before it can be added in. */ | |
| + if (! TARGET_MIPS16 | |
| + && ! TARGET_GAS | |
| + && GET_CODE (operands[2]) == CONST_INT | |
| + && INTVAL (operands[2]) == -32768) | |
| + operands[2] = force_reg (DImode, operands[2]); | |
| + | |
| + if (TARGET_64BIT) | |
| + { | |
| + emit_insn (gen_addvdi3_internal_3 (operands[0], operands[1], | |
| + operands[2])); | |
| + DONE; | |
| + } | |
| + | |
| + operands[3] = gen_reg_rtx (SImode); | |
| +}") | |
| + | |
| +(define_insn "addvdi3_internal_3" | |
| + [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (plus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ") | |
| + (match_operand:DI 2 "se_arith_operand" "dI"))) | |
| + (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1)) | |
| + (sign_extend:TI (match_dup 2))) | |
| + (sign_extend:TI (plus:DI (match_dup 1) | |
| + (match_dup 2)))) | |
| + (const_int 0))] | |
| + "TARGET_64BIT | |
| + && ! TARGET_MIPS16 | |
| + && (TARGET_GAS | |
| + || GET_CODE (operands[2]) != CONST_INT | |
| + || INTVAL (operands[2]) != -32768)" | |
| + "* | |
| +{ | |
| + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) | |
| + ? \"dsub\\t%0,%z1,%n2\" | |
| + : \"dadd\\t%0,%z1,%2\"; | |
| +}" | |
| + [(set_attr "type" "darith") | |
| + (set_attr "mode" "DI") | |
| + (set_attr "length" "1")]) | |
| ;; | |
| ;; .................... | |
| @@ -1544,6 +1809,82 @@ | |
| (const_int 4)])]) | |
| +(define_expand "subvsi3" | |
| + [(parallel [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") | |
| + (match_operand:SI 2 "arith_operand" "dI"))) | |
| + (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1)) | |
| + (sign_extend:DI (match_dup 2))) | |
| + (sign_extend:DI (minus:DI (match_dup 1) | |
| + (match_dup 2)))) | |
| + (const_int 0))])] | |
| + "" | |
| + " | |
| +{ | |
| + if (GET_CODE (operands[2]) == CONST_INT | |
| + && (INTVAL (operands[2]) == -32768 | |
| + || (TARGET_MIPS16 | |
| + && INTVAL (operands[2]) == -0x4000))) | |
| + operands[2] = force_reg (SImode, operands[2]); | |
| +}") | |
| + | |
| +(define_insn "subvsi3_internal" | |
| + [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") | |
| + (match_operand:SI 2 "arith_operand" "dI"))) | |
| + (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1)) | |
| + (sign_extend:DI (match_dup 2))) | |
| + (sign_extend:DI (minus:DI (match_dup 1) (match_dup 2)))) | |
| + (const_int 0))] | |
| + "! TARGET_MIPS16 | |
| + && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" | |
| + "sub\\t%0,%z1,%2" | |
| + [(set_attr "type" "arith") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "subvdi3" | |
| + [(parallel [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (minus:DI (match_operand:DI 1 "se_register_operand" "d") | |
| + (match_operand:DI 2 "se_register_operand" "d"))) | |
| + (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1)) | |
| + (sign_extend:TI (match_dup 2))) | |
| + (sign_extend:TI (minus:DI (match_dup 1) (match_dup 2) | |
| +))) | |
| + (const_int 0)) | |
| + (clobber (match_dup 3))])] | |
| + "TARGET_64BIT || (! TARGET_DEBUG_G_MODE && ! TARGET_MIPS16)" | |
| + " | |
| +{ | |
| + if (TARGET_64BIT) | |
| + { | |
| + emit_insn (gen_subvdi3_internal_3 (operands[0], operands[1], | |
| + operands[2])); | |
| + DONE; | |
| + } | |
| + | |
| + operands[3] = gen_reg_rtx (SImode); | |
| +}") | |
| + | |
| +(define_insn "subvdi3_internal_3" | |
| + [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (minus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ") | |
| + (match_operand:DI 2 "se_arith_operand" "dI"))) | |
| + (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1)) | |
| + (sign_extend:TI (match_dup 2))) | |
| + (sign_extend:TI (minus:DI (match_dup 1) (match_dup 2)))) | |
| + (const_int 0))] | |
| + "TARGET_64BIT && ! TARGET_MIPS16 | |
| + && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" | |
| + "* | |
| +{ | |
| + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) | |
| + ? \"dadd\\t%0,%z1,%n2\" | |
| + : \"dsub\\t%0,%z1,%2\"; | |
| +}" | |
| + [(set_attr "type" "darith") | |
| + (set_attr "mode" "DI") | |
| + (set_attr "length" "1")]) | |
| ;; | |
| ;; .................... | |
| @@ -1649,6 +1990,21 @@ | |
| "" | |
| " | |
| { | |
| + /* mulsi3_mult3_r5900 is just like the other mulsi3_mult3 pattern, except | |
| + that it has additional alternatives, slightly different output | |
| + templates and clobbers pseudos instead of scratches. | |
| + | |
| + We generate a different pattern merely to keep the sanitize issues from | |
| + driving us crazy. Long term we may want the other multiply patterns to | |
| + clobber pseudos instead of scratches. */ | |
| + if (HAVE_mulsi3_mult3_r5900) | |
| + { | |
| + emit_insn (gen_mulsi3_mult3_r5900 (operands[0], operands[1], operands[2], | |
| + gen_reg_rtx (SImode), | |
| + gen_reg_rtx (SImode), | |
| + gen_reg_rtx (SImode))); | |
| + DONE; | |
| + } | |
| if (HAVE_mulsi3_mult3) | |
| emit_insn (gen_mulsi3_mult3 (operands[0], operands[1], operands[2])); | |
| else if (mips_cpu != PROCESSOR_R4000 || TARGET_MIPS16) | |
| @@ -1658,6 +2014,24 @@ | |
| DONE; | |
| }") | |
| +(define_insn "mulsi3_mult3_r5900" | |
| + [(set (match_operand:SI 0 "register_operand" "=d,l,d,v") | |
| + (mult:SI (match_operand:SI 1 "register_operand" "d,d,d,d") | |
| + (match_operand:SI 2 "register_operand" "d,d,d,d"))) | |
| + (clobber (match_operand:SI 3 "register_operand" "=h,h,u,u")) | |
| + (clobber (match_operand:SI 4 "register_operand" "=l,X,v,X")) | |
| + (clobber (match_operand:SI 5 "register_operand" "=a,a,q,q"))] | |
| + "TARGET_MIPS5900 && GENERATE_MULT3" | |
| + "* | |
| +{ | |
| + if (which_alternative == 1 || which_alternative == 3) | |
| + return \"mult%H5\\t%1,%2\"; | |
| + return \"mult%H5\\t%0,%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| (define_insn "mulsi3_mult3" | |
| [(set (match_operand:SI 0 "register_operand" "=d,l") | |
| (mult:SI (match_operand:SI 1 "register_operand" "d,d") | |
| @@ -1665,18 +2039,21 @@ | |
| (clobber (match_scratch:SI 3 "=h,h")) | |
| (clobber (match_scratch:SI 4 "=l,X")) | |
| (clobber (match_scratch:SI 5 "=a,a"))] | |
| - "GENERATE_MULT3 | |
| - || TARGET_MAD" | |
| + "(GENERATE_MULT3 | |
| + || TARGET_MIPS5400 /* CYGNUS LOCAL vr5400/raeburn */ | |
| + || TARGET_MAD) | |
| + && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "* | |
| { | |
| if (which_alternative == 1) | |
| return \"mult\\t%1,%2\"; | |
| - if (TARGET_MAD) | |
| + if (TARGET_MIPS5400 /* CYGNUS LOCAL vr5400/raeburn */ | |
| + || TARGET_MAD) | |
| return \"mul\\t%0,%1,%2\"; | |
| return \"mult\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "imul") | |
| - (set_attr "mode" "SI")]) | |
| + [(set_attr "type" "imul3,imul") | |
| + (set_attr "mode" "SI,SI")]) | |
| (define_insn "mulsi3_internal" | |
| [(set (match_operand:SI 0 "register_operand" "=l") | |
| @@ -1713,8 +2090,8 @@ | |
| (set_attr "length" "12")]) ;; mult + mflo + delay | |
| ;; Multiply-accumulate patterns | |
| - | |
| -;; For processors that can copy the output to a general register: | |
| +; | |
| +; For processors that can copy the output to a general register: | |
| ;; | |
| ;; The all-d alternative is needed because the combiner will find this | |
| ;; pattern and then register alloc/reload will move registers around to | |
| @@ -1724,6 +2101,29 @@ | |
| ;; "?" to the constraint is too strong, and causes values to be loaded into | |
| ;; LO even when that's more costly. For now, using "*d" mostly does the | |
| ;; trick. | |
| +;; Like the standard multiply-accumulate, except with more alternatives and | |
| +;; works with both pipelines. Temporarily disabled. */ | |
| +(define_insn "*mul_acc_si_r5900" | |
| + [(set (match_operand:SI 0 "register_operand" "=l,*d,*d,v,*d,*d") | |
| + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d,d,d,d") | |
| + (match_operand:SI 2 "register_operand" "d,d,d,d,d,d")) | |
| + (match_operand:SI 3 "register_operand" "0,l,*d,0,v,*d"))) | |
| + (clobber (match_scratch:SI 4 "=h,h,h,u,u,u")) | |
| + (clobber (match_scratch:SI 5 "=X,3,l,X,3,v")) | |
| + (clobber (match_scratch:SI 6 "=a,a,a,q,q,q")) | |
| + (clobber (match_scratch:SI 7 "=X,X,d,X,X,d"))] | |
| + "(TARGET_MIPS5900 && !TARGET_MIPS16) && r5900_madd_profitable_p (insn)" | |
| + "* | |
| +{ | |
| + static char *const madd[] = { \"madd%H6\\t%1,%2\", | |
| + \"madd%H6\\t%0,%1,%2\", | |
| + \"#\" }; | |
| + return madd[which_alternative % 3]; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4,4,8,4,4,8")]) | |
| + | |
| (define_insn "*mul_acc_si" | |
| [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") | |
| (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d") | |
| @@ -1733,13 +2133,19 @@ | |
| (clobber (match_scratch:SI 5 "=X,3,l")) | |
| (clobber (match_scratch:SI 6 "=a,a,a")) | |
| (clobber (match_scratch:SI 7 "=X,X,d"))] | |
| - "TARGET_MIPS3900 | |
| + "(TARGET_MIPS3900 | |
| + || TARGET_MIPS5400) /* CYGNUS LOCAL vr5400/raeburn */ | |
| && !TARGET_MIPS16" | |
| "* | |
| { | |
| static const char *const madd[] = { \"madd\\t%1,%2\", \"madd\\t%0,%1,%2\" }; | |
| + static const char *const macc[] = { \"macc\\t$0,%1,%2\", \"macc\\t%0,%1,%2\" }; /* CYGNUS LOCAL vr5400/raeburn */ | |
| if (which_alternative == 2) | |
| return \"#\"; | |
| + /* CYGNUS LOCAL vr5400/raeburn */ | |
| + if (TARGET_MIPS5400) | |
| + return macc[which_alternative]; | |
| + /* END CYGNUS LOCAL */ | |
| return madd[which_alternative]; | |
| }" | |
| [(set_attr "type" "imul,imul,multi") | |
| @@ -1765,6 +2171,43 @@ | |
| (set (match_dup 0) (plus:SI (match_dup 7) (match_dup 3)))] | |
| "") | |
| + | |
| + | |
| + | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| +(define_insn "*muls_r5400" | |
| + [(set (match_operand:SI 0 "register_operand" "=l,d") | |
| + (neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") | |
| + (match_operand:SI 2 "register_operand" "d,d")))) | |
| + (clobber (match_scratch:SI 3 "=h,h")) | |
| + (clobber (match_scratch:SI 4 "=a,a")) | |
| + (clobber (match_scratch:SI 5 "=X,l"))] | |
| + "TARGET_MIPS5400" | |
| + "@ | |
| + muls\\t$0,%1,%2 | |
| + muls\\t%0,%1,%2" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI")]) | |
| + | |
| +;; See comments above for mul_acc_si. | |
| +(define_insn "*msac_r5400" | |
| + [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") | |
| + (minus:SI (match_operand:SI 1 "register_operand" "0,l,*d") | |
| + (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") | |
| + (match_operand:SI 3 "register_operand" "d,d,d")))) | |
| + (clobber (match_scratch:SI 4 "=h,h,h")) | |
| + (clobber (match_scratch:SI 5 "=X,1,l")) | |
| + (clobber (match_scratch:SI 6 "=a,a,a")) | |
| + (clobber (match_scratch:SI 7 "=X,X,d"))] | |
| + "TARGET_MIPS5400" | |
| + "@ | |
| + msac\\t$0,%2,%3 | |
| + msac\\t%0,%2,%3 | |
| + #" | |
| + [(set_attr "type" "imul,imul,multi") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4,4,8")]) | |
| + | |
| (define_split | |
| [(set (match_operand:SI 0 "register_operand" "") | |
| (minus:SI (match_operand:SI 1 "register_operand" "") | |
| @@ -1782,6 +2225,7 @@ | |
| (clobber (match_dup 6))]) | |
| (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 7)))] | |
| "") | |
| +;; END CYGNUS LOCAL | |
| (define_expand "muldi3" | |
| [(set (match_operand:DI 0 "register_operand" "=l") | |
| @@ -1789,7 +2233,7 @@ | |
| (match_operand:DI 2 "register_operand" "d"))) | |
| (clobber (match_scratch:DI 3 "=h")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT" | |
| + "TARGET_64BIT && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| @@ -1811,7 +2255,7 @@ | |
| (match_operand:DI 2 "register_operand" "d"))) | |
| (clobber (match_scratch:DI 3 "=h")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT && mips_cpu != PROCESSOR_R4000 && !TARGET_MIPS16" | |
| + "TARGET_64BIT && mips_cpu != PROCESSOR_R4000 && !TARGET_MIPS16 && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "dmult\\t%1,%2" | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "DI")]) | |
| @@ -1823,7 +2267,7 @@ | |
| (clobber (match_scratch:DI 3 "=h")) | |
| (clobber (match_scratch:DI 4 "=l")) | |
| (clobber (match_scratch:DI 5 "=a"))] | |
| - "TARGET_64BIT && (GENERATE_MULT3 || mips_cpu == PROCESSOR_R4000 || TARGET_MIPS16)" | |
| + "TARGET_64BIT && (GENERATE_MULT3 || mips_cpu == PROCESSOR_R4000 || TARGET_MIPS16) && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "* | |
| { | |
| if (GENERATE_MULT3) | |
| @@ -1857,6 +2301,15 @@ | |
| " | |
| { | |
| rtx dummy = gen_rtx (SIGN_EXTEND, DImode, const0_rtx); | |
| + if (TARGET_64BIT && TARGET_MIPS5900) | |
| + { | |
| + emit_insn (gen_mulsidi3_64bit_r5900 (operands[0], operands[1], | |
| + operands[2], | |
| + dummy, dummy, | |
| + gen_reg_rtx (DImode), | |
| + gen_reg_rtx (DImode))); | |
| + DONE; | |
| + } | |
| if (TARGET_64BIT) | |
| emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2], | |
| dummy, dummy)); | |
| @@ -1874,6 +2327,15 @@ | |
| " | |
| { | |
| rtx dummy = gen_rtx (ZERO_EXTEND, DImode, const0_rtx); | |
| + if (TARGET_64BIT && TARGET_MIPS5900) | |
| + { | |
| + emit_insn (gen_mulsidi3_64bit_r5900 (operands[0], operands[1], | |
| + operands[2], | |
| + dummy, dummy, | |
| + gen_reg_rtx (DImode), | |
| + gen_reg_rtx (DImode))); | |
| + DONE; | |
| + } | |
| if (TARGET_64BIT) | |
| emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2], | |
| dummy, dummy)); | |
| @@ -1900,6 +2362,26 @@ | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "SI")]) | |
| +(define_insn "mulsidi3_64bit_r5900" | |
| + [(set (match_operand:DI 0 "register_operand" "=a,q") | |
| + (mult:DI (match_operator:DI 3 "extend_operator" | |
| + [(match_operand:SI 1 "register_operand" "d,d")]) | |
| + (match_operator:DI 4 "extend_operator" | |
| + [(match_operand:SI 2 "register_operand" "d,d")]))) | |
| + (clobber (match_operand:DI 5 "register_operand" "=l,v")) | |
| + (clobber (match_operand:DI 6 "register_operand" "=h,u"))] | |
| + "TARGET_64BIT && TARGET_MIPS5900 | |
| + && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "* | |
| +{ | |
| + if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| + return \"mult%H0\\t%1,%2\"; | |
| + return \"multu%H0\\t%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| (define_insn "mulsidi3_64bit" | |
| [(set (match_operand:DI 0 "register_operand" "=a") | |
| (mult:DI (match_operator:DI 3 "extend_operator" | |
| @@ -1908,7 +2390,7 @@ | |
| [(match_operand:SI 2 "register_operand" "d")]))) | |
| (clobber (match_scratch:DI 5 "=l")) | |
| (clobber (match_scratch:DI 6 "=h"))] | |
| - "TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "TARGET_64BIT && !TARGET_MIPS5900 && GET_CODE (operands[3]) == GET_CODE (operands[4])" ;; CYGNUS LOCAL law | |
| "* | |
| { | |
| if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| @@ -1918,6 +2400,56 @@ | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "SI")]) | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| + | |
| +;; widening multiply with accumulator and/or negation | |
| +;; These don't match yet for zero-extending; too complex for combine? | |
| +;; Possible additions we should have: | |
| +;; "=x" variants for when !TARGET_64BIT ? | |
| +;; all-d alternatives with splits like pure SImode versions | |
| +(define_insn "*muls_r5400_di" | |
| + [(set (match_operand:DI 0 "register_operand" "=a") | |
| + (neg:DI | |
| + (mult:DI (match_operator:DI 3 "extend_operator" | |
| + [(match_operand:SI 1 "register_operand" "d")]) | |
| + (match_operator:DI 4 "extend_operator" | |
| + [(match_operand:SI 2 "register_operand" "d")])))) | |
| + (clobber (match_scratch:SI 5 "=h")) | |
| + (clobber (match_scratch:SI 6 "=l"))] | |
| + "TARGET_64BIT && TARGET_MIPS5400 && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "* | |
| +{ | |
| + if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| + return \"muls\\t$0,%1,%2\"; | |
| + else | |
| + return \"mulsu\\t$0,%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "length" "4") | |
| + (set_attr "mode" "SI")]) | |
| + | |
| +(define_insn "*msac_r5400_di" | |
| + [(set (match_operand:DI 0 "register_operand" "=a") | |
| + (minus:DI (match_operand:DI 3 "register_operand" "0") | |
| + (mult:DI (match_operator:DI 4 "extend_operator" | |
| + [(match_operand:SI 1 "register_operand" "d")]) | |
| + (match_operator:DI 5 "extend_operator" | |
| + [(match_operand:SI 2 "register_operand" "d")])))) | |
| + (clobber (match_scratch:SI 6 "=h")) | |
| + (clobber (match_scratch:SI 7 "=l"))] | |
| + "TARGET_64BIT && TARGET_MIPS5400 && GET_CODE (operands[4]) == GET_CODE (operands[5])" | |
| + "* | |
| +{ | |
| + if (GET_CODE (operands[4]) == SIGN_EXTEND) | |
| + return \"msac\\t$0,%1,%2\"; | |
| + else | |
| + return \"msacu\\t$0,%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "length" "4") | |
| + (set_attr "mode" "SI")]) | |
| +;; END CYGNUS LOCAL | |
| + | |
| ;; _highpart patterns | |
| (define_expand "smulsi3_highpart" | |
| [(set (match_operand:SI 0 "register_operand" "=h") | |
| @@ -1936,6 +2468,12 @@ | |
| rtx (*genfn) (); | |
| #endif | |
| genfn = gen_xmulsi3_highpart_internal; | |
| + /* CYGNUS LOCAL vr5400/raeburn */ | |
| + if (TARGET_MIPS5400) | |
| + genfn = gen_xmulsi3_highpart_5400; | |
| + /* END CYGNUS LOCAL */ | |
| + if (TARGET_MIPS5900) | |
| + genfn = gen_xmulsi3_highpart_r5900; | |
| emit_insn ((*genfn) (operands[0], operands[1], operands[2], dummy, | |
| dummy, dummy2)); | |
| DONE; | |
| @@ -1958,11 +2496,40 @@ | |
| rtx (*genfn) (); | |
| #endif | |
| genfn = gen_xmulsi3_highpart_internal; | |
| + /* CYGNUS LOCAL vr5400/raeburn */ | |
| + if (TARGET_MIPS5400) | |
| + genfn = gen_xmulsi3_highpart_5400; | |
| + /* END CYGNUS LOCAL */ | |
| + if (TARGET_MIPS5900) | |
| + genfn = gen_xmulsi3_highpart_r5900; | |
| emit_insn ((*genfn) (operands[0], operands[1], operands[2], dummy, | |
| dummy, dummy2)); | |
| DONE; | |
| }") | |
| +(define_insn "xmulsi3_highpart_r5900" | |
| + [(set (match_operand:SI 0 "register_operand" "=h,u") | |
| + (truncate:SI | |
| + (match_operator:DI 5 "highpart_shift_operator" | |
| + [(mult:DI (match_operator:DI 3 "extend_operator" | |
| + [(match_operand:SI 1 "register_operand" "d,d")]) | |
| + (match_operator:DI 4 "extend_operator" | |
| + [(match_operand:SI 2 "register_operand" "d,d")])) | |
| + (const_int 32)]))) | |
| + (clobber (match_scratch:SI 6 "=l,v")) | |
| + (clobber (match_scratch:SI 7 "=a,q"))] | |
| + "TARGET_MIPS5900 && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "* | |
| +{ | |
| + if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| + return \"mult%H0\\t%1,%2\"; | |
| + else | |
| + return \"multu%H0\\t%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| (define_insn "xmulsi3_highpart_internal" | |
| [(set (match_operand:SI 0 "register_operand" "=h") | |
| (truncate:SI | |
| @@ -1974,7 +2541,7 @@ | |
| (const_int 32)]))) | |
| (clobber (match_scratch:SI 6 "=l")) | |
| (clobber (match_scratch:SI 7 "=a"))] | |
| - "GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "! TARGET_MIPS5400 && !TARGET_MIPS5900 && GET_CODE (operands[3]) == GET_CODE (operands[4])" ;; CYGNUS LOCAL vr5400/raeburn ;; CYGNUS LOCAL law | |
| "* | |
| { | |
| if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| @@ -1985,6 +2552,61 @@ | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "SI")]) | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| +(define_insn "xmulsi3_highpart_5400" | |
| + [(set (match_operand:SI 0 "register_operand" "=h,d") | |
| + (truncate:SI | |
| + (match_operator:DI 5 "highpart_shift_operator" | |
| + [(mult:DI (match_operator:DI 3 "extend_operator" | |
| + [(match_operand:SI 1 "register_operand" "d,d")]) | |
| + (match_operator:DI 4 "extend_operator" | |
| + [(match_operand:SI 2 "register_operand" "d,d")])) | |
| + (const_int 32)]))) | |
| + (clobber (match_scratch:SI 6 "=l,l")) | |
| + (clobber (match_scratch:SI 7 "=a,a")) | |
| + (clobber (match_scratch:SI 8 "=X,h"))] | |
| + "TARGET_MIPS5400 && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "* | |
| +{ | |
| + char *const sign[] = { \"mult\\t%1,%2\", \"mulhi\\t%0,%1,%2\" }; | |
| + char *const zero[] = { \"multu\\t%1,%2\", \"mulhiu\\t%0,%1,%2\" }; | |
| + if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| + return sign[which_alternative]; | |
| + else | |
| + return zero[which_alternative]; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| +(define_insn "*xmulsi3_neg_highpart_5400" | |
| + [(set (match_operand:SI 0 "register_operand" "=h,d") | |
| + (truncate:SI | |
| + (match_operator:DI 5 "highpart_shift_operator" | |
| + [(neg:DI | |
| + (mult:DI (match_operator:DI 3 "extend_operator" | |
| + [(match_operand:SI 1 "register_operand" "d,d")]) | |
| + (match_operator:DI 4 "extend_operator" | |
| + [(match_operand:SI 2 "register_operand" "d,d")]))) | |
| + (const_int 32)]))) | |
| + (clobber (match_scratch:SI 6 "=l,l")) | |
| + (clobber (match_scratch:SI 7 "=a,a")) | |
| + (clobber (match_scratch:SI 8 "=X,h"))] | |
| + "TARGET_MIPS5400 && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "* | |
| +{ | |
| + char *const sign[] = { \"mulshi\\t$0,%1,%2\", \"mulshi\\t%0,%1,%2\" }; | |
| + char *const zero[] = { \"mulshiu\\t$0,%1,%2\", \"mulshiu\\t%0,%1,%2\" }; | |
| + if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| + return sign[which_alternative]; | |
| + else | |
| + return zero[which_alternative]; | |
| +}" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| +;; END CYGNUS LOCAL | |
| + | |
| (define_insn "smuldi3_highpart" | |
| [(set (match_operand:DI 0 "register_operand" "=h") | |
| (truncate:DI | |
| @@ -1993,7 +2615,7 @@ | |
| (const_int 64)))) | |
| (clobber (match_scratch:DI 3 "=l")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT" | |
| + "TARGET_64BIT && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "dmult\\t%1,%2" | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "DI")]) | |
| @@ -2006,7 +2628,7 @@ | |
| (const_int 64)))) | |
| (clobber (match_scratch:DI 3 "=l")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT" | |
| + "TARGET_64BIT && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "dmultu\\t%1,%2" | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "DI")]) | |
| @@ -2056,15 +2678,28 @@ | |
| (match_dup 0))) | |
| (clobber (match_scratch:SI 5 "=h")) | |
| (clobber (match_scratch:SI 6 "=l"))] | |
| - "TARGET_MAD | |
| - && TARGET_64BIT | |
| - && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| + "(TARGET_MAD || TARGET_MIPS5400) /* CYGNUS LOCAL vr5400/raeburn */ | |
| + && TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" | |
| "* | |
| { | |
| + if (TARGET_MAD) | |
| + { | |
| if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| return \"mad\\t%1,%2\"; | |
| else | |
| return \"madu\\t%1,%2\"; | |
| + } | |
| + /* CYGNUS LOCAL vr5400/raeburn */ | |
| + else if (TARGET_MIPS5400) | |
| + { | |
| + if (GET_CODE (operands[3]) == SIGN_EXTEND) | |
| + return \"macc\\t$0,%1,%2\"; | |
| + else | |
| + return \"maccu\\t$0,%1,%2\"; | |
| + } | |
| + /* END CYGNUS LOCAL */ | |
| + else | |
| + abort (); | |
| }" | |
| [(set_attr "type" "imul") | |
| (set_attr "mode" "SI")]) | |
| @@ -2152,6 +2787,128 @@ | |
| [(set_attr "type" "fmadd") | |
| (set_attr "mode" "SF")]) | |
| +(define_expand "mulvsi3" | |
| + [(parallel [(set (match_operand:SI 0 "register_operand" "=l") | |
| + (mult:SI (match_operand:SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_operand" "d"))) | |
| + (trap_if (ne (mult:DI (sign_extend:DI (match_dup 1)) | |
| + (sign_extend:DI (match_dup 2))) | |
| + (sign_extend:DI (mult:SI (match_dup 1) (match_dup 2)) | |
| +)) | |
| + (const_int 0)) | |
| + (clobber (match_scratch:SI 3 "=h")) | |
| + (clobber (match_scratch:SI 4 "=l")) | |
| + (clobber (match_scratch:SI 5 "=a"))])] | |
| + "HAVE_mulvsi3_mult3_r5900" | |
| + " | |
| +{ | |
| + /* mulvsi3_mult3_r5900 is just like the other mulsi3_mult3 pattern, except | |
| + that it has additional alternatives, slightly different output | |
| + templates and clobbers pseudos instead of scratches. | |
| + | |
| + We generate a different pattern merely to keep the sanitize issues from | |
| + driving us crazy. Long term we may want the other multiply patterns to | |
| + clobber pseudos instead of scratches. */ | |
| + if (HAVE_mulvsi3_mult3_r5900) | |
| + { | |
| + emit_insn (gen_mulvsi3_mult3_r5900 (operands[0], operands[1], | |
| + operands[2])); | |
| + DONE; | |
| + } | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mulvsi3_mult3_r5900" | |
| + | |
| + [(set (match_operand:SI 0 "register_operand" "=d,l") | |
| + (mult:SI (match_operand:SI 1 "register_operand" "d,d") | |
| + (match_operand:SI 2 "register_operand" "d,d"))) | |
| + (trap_if (ne (mult:DI (sign_extend:DI (match_dup 1)) | |
| + (sign_extend:DI (match_dup 2))) | |
| + (sign_extend:DI (mult:SI (match_dup 1) (match_dup 2)))) | |
| + (const_int 0)) | |
| + (clobber (match_scratch:SI 3 "=d,d")) | |
| + (clobber (match_scratch:SI 4 "=h,h")) | |
| + (clobber (match_scratch:SI 5 "=l,d")) | |
| + (clobber (match_scratch:SI 6 "=a,a"))] | |
| + "TARGET_MIPS5900 && GENERATE_MULT3" | |
| + "@ | |
| + mult\\t%0,%1,%2\\n\\tpmfhl.lw\\t%3\\n\\ttne\\t%0,%3 | |
| + mult\\t%5,%1,%2\\n\\tpmfhl.lw\\t%3\\n\\ttne\\t%4,%3" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "3")]) | |
| + | |
| +(define_expand "mulvdi3" | |
| + [(parallel [(set (match_operand:DI 0 "register_operand" "=&r") | |
| + (mult:DI (match_operand:DI 1 "register_operand" "r") | |
| + (match_operand:DI 2 "register_operand" "r"))) | |
| + (trap_if (ne (mult:TI (sign_extend:TI (match_dup 1)) | |
| + (sign_extend:TI (match_dup 2))) | |
| + (sign_extend:TI (mult:DI (match_dup 1) (match_dup 2)) | |
| +)) | |
| + (const_int 0)) | |
| + (clobber (match_scratch:TI 3 "=&r")) | |
| + (clobber (match_scratch:TI 4 "=&r")) | |
| + (clobber (match_scratch:TI 5 "=&r")) | |
| + (clobber (match_scratch:SI 6 "=&h")) | |
| + (clobber (match_scratch:SI 7 "=&l")) | |
| + (clobber (match_scratch:SI 8 "=&a"))])] | |
| + "TARGET_64BIT && TARGET_MIPS5900" | |
| + " | |
| +{ | |
| + emit_insn (gen_mulvdi3_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mulvdi3_internal" | |
| + [(set (match_operand:DI 0 "register_operand" "=&r") | |
| + (mult:DI (match_operand:DI 1 "register_operand" "r") | |
| + (match_operand:DI 2 "register_operand" "r"))) | |
| + (trap_if (ne (mult:TI (sign_extend:TI (match_dup 1)) | |
| + (sign_extend:TI (match_dup 2))) | |
| + (sign_extend:TI (mult:DI (match_dup 1) (match_dup 2)))) | |
| + (const_int 0)) | |
| + (clobber (match_scratch:TI 3 "=&r")) | |
| + (clobber (match_scratch:TI 4 "=&r")) | |
| + (clobber (match_scratch:TI 5 "=&r")) | |
| + (clobber (match_scratch:SI 6 "=&h")) | |
| + (clobber (match_scratch:SI 7 "=&l")) | |
| + (clobber (match_scratch:SI 8 "=&a")) | |
| + (clobber (subreg:TI (match_dup 0) 0))] | |
| + | |
| + "TARGET_64BIT && TARGET_MIPS5900" | |
| + "pextlw\\t%3,%1,%1 \ | |
| +\\tpextlw\\t%4,%2,%2 \ | |
| +\\tpsravw\\t%3,%3,$0 \ | |
| +\\tpsravw\\t%4,%4,$0 \ | |
| +\\tpmultuw\\t%0,%3,%4 \ | |
| +\\tmtsah\\t$0,4 \ | |
| +\\tqfsrv\\t%3,%3,%3 \ | |
| +\\tpmultuw\\t%3,%3,%4 \ | |
| +\\tdsrl32\\t%5,%0,0 \ | |
| +\\tqfsrv\\t%4,$0,%0 \ | |
| +\\tdaddu\\t%3,%3,%5 \ | |
| +\\tdsrl32\\t%5,%3,0 \ | |
| +\\tdaddu\\t%4,%4,%5 \ | |
| +\\tpextlw\\t%5,$0,%3 \ | |
| +\\tqfsrv\\t%3,$0,%3 \ | |
| +\\tdaddu\\t%3,%3,%5 \ | |
| +\\tdsrl32\\t%5,%3,0 \ | |
| +\\tdaddu\\t%4,%4,%5 \ | |
| +\\tpextlw\\t%0,%3,%0 \ | |
| +\\tdsra32\\t%5,%1,31 \ | |
| +\\tdsra32\\t%3,%2,31 \ | |
| +\\tand\\t%5,%5,%2 \ | |
| +\\tand\\t%3,%3,%1 \ | |
| +\\tdsubu\\t%4,%4,%5 \ | |
| +\\tdsra32\\t%5,%0,31 \ | |
| +\\tdsubu\\t%4,%4,%3 \ | |
| +\\ttne\\t%4,%5" | |
| + [(set_attr "type" "imul") | |
| + (set_attr "mode" "DI") | |
| + (set_attr "length" "27")]) | |
| + | |
| ;; | |
| ;; .................... | |
| ;; | |
| @@ -2174,9 +2931,19 @@ | |
| (div:SF (match_operand:SF 1 "register_operand" "f") | |
| (match_operand:SF 2 "register_operand" "f")))] | |
| "TARGET_HARD_FLOAT" | |
| - "div.s\\t%0,%1,%2" | |
| + "* | |
| +{ | |
| + if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG) | |
| + return \"%(nop\;nop\;div.s\\t%0,%1,%2%)\"; | |
| + return \"div.s\\t%0,%1,%2\"; | |
| +}" | |
| [(set_attr "type" "fdiv") | |
| - (set_attr "mode" "SF")]) | |
| + (set_attr "mode" "SF") | |
| + (set (attr "length") | |
| + (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG") | |
| + (const_int 0)) | |
| + (const_int 4) | |
| + (const_int 12)))]) | |
| (define_insn "" | |
| [(set (match_operand:DF 0 "register_operand" "=f") | |
| @@ -2222,8 +2989,16 @@ | |
| "optimize" | |
| " | |
| { | |
| + if (TARGET_MIPS5900) | |
| + { | |
| + emit_insn (gen_divmodsi4_internal_r5900 (operands[0], operands[1], | |
| + operands[2], operands[3])); | |
| + goto zero_div_check; | |
| + } | |
| + | |
| emit_insn (gen_divmodsi4_internal (operands[0], operands[1], operands[2], | |
| operands[3])); | |
| + zero_div_check: | |
| if (!TARGET_NO_CHECK_ZERO_DIV) | |
| { | |
| emit_insn (gen_div_trap (operands[2], | |
| @@ -2243,6 +3018,20 @@ | |
| DONE; | |
| }") | |
| +(define_insn "divmodsi4_internal_r5900" | |
| + [(set (match_operand:SI 0 "register_operand" "=l,v") | |
| + (div:SI (match_operand:SI 1 "register_operand" "d,d") | |
| + (match_operand:SI 2 "register_operand" "d,d"))) | |
| + (set (match_operand:SI 3 "register_operand" "=h,u") | |
| + (mod:SI (match_dup 1) | |
| + (match_dup 2))) | |
| + (clobber (match_scratch:SI 6 "=a,q"))] | |
| + "optimize && TARGET_MIPS5900" | |
| + "div%H0\\t$0,%1,%2" | |
| + [(set_attr "type" "idiv") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| (define_insn "divmodsi4_internal" | |
| [(set (match_operand:SI 0 "register_operand" "=l") | |
| (div:SI (match_operand:SI 1 "register_operand" "d") | |
| @@ -2251,7 +3040,7 @@ | |
| (mod:SI (match_dup 1) | |
| (match_dup 2))) | |
| (clobber (match_scratch:SI 6 "=a"))] | |
| - "optimize" | |
| + "optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "div\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "SI")]) | |
| @@ -2266,7 +3055,7 @@ | |
| (clobber (match_scratch:DI 4 "=l")) | |
| (clobber (match_scratch:DI 5 "=h")) | |
| (clobber (match_scratch:DI 6 "=a"))] | |
| - "TARGET_64BIT && optimize" | |
| + "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| emit_insn (gen_divmoddi4_internal (operands[0], operands[1], operands[2], | |
| @@ -2298,7 +3087,7 @@ | |
| (mod:DI (match_dup 1) | |
| (match_dup 2))) | |
| (clobber (match_scratch:DI 6 "=a"))] | |
| - "TARGET_64BIT && optimize" | |
| + "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "ddiv\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "SI")]) | |
| @@ -2316,8 +3105,15 @@ | |
| "optimize" | |
| " | |
| { | |
| + if (TARGET_MIPS5900) | |
| + { | |
| + emit_insn (gen_udivmodsi4_internal_r5900 (operands[0], operands[1], | |
| + operands[2], operands[3])); | |
| + goto zero_div_check; | |
| + } | |
| emit_insn (gen_udivmodsi4_internal (operands[0], operands[1], operands[2], | |
| operands[3])); | |
| + zero_div_check: | |
| if (!TARGET_NO_CHECK_ZERO_DIV) | |
| { | |
| emit_insn (gen_div_trap (operands[2], | |
| @@ -2328,6 +3124,20 @@ | |
| DONE; | |
| }") | |
| +(define_insn "udivmodsi4_internal_r5900" | |
| + [(set (match_operand:SI 0 "register_operand" "=l,v") | |
| + (udiv:SI (match_operand:SI 1 "register_operand" "d,d") | |
| + (match_operand:SI 2 "register_operand" "d,d"))) | |
| + (set (match_operand:SI 3 "register_operand" "=h,u") | |
| + (umod:SI (match_dup 1) | |
| + (match_dup 2))) | |
| + (clobber (match_scratch:SI 6 "=a,q"))] | |
| + "optimize && TARGET_MIPS5900" | |
| + "divu%H0\\t$0,%1,%2" | |
| + [(set_attr "type" "idiv") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| (define_insn "udivmodsi4_internal" | |
| [(set (match_operand:SI 0 "register_operand" "=l") | |
| (udiv:SI (match_operand:SI 1 "register_operand" "d") | |
| @@ -2336,7 +3146,7 @@ | |
| (umod:SI (match_dup 1) | |
| (match_dup 2))) | |
| (clobber (match_scratch:SI 6 "=a"))] | |
| - "optimize" | |
| + "optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "divu\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "SI")]) | |
| @@ -2351,7 +3161,7 @@ | |
| (clobber (match_scratch:DI 4 "=l")) | |
| (clobber (match_scratch:DI 5 "=h")) | |
| (clobber (match_scratch:DI 6 "=a"))] | |
| - "TARGET_64BIT && optimize" | |
| + "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| emit_insn (gen_udivmoddi4_internal (operands[0], operands[1], operands[2], | |
| @@ -2374,7 +3184,7 @@ | |
| (umod:DI (match_dup 1) | |
| (match_dup 2))) | |
| (clobber (match_scratch:DI 6 "=a"))] | |
| - "TARGET_64BIT && optimize" | |
| + "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "ddivu\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "SI")]) | |
| @@ -2518,7 +3328,7 @@ | |
| (match_operand:DI 2 "se_register_operand" "d"))) | |
| (clobber (match_scratch:DI 3 "=h")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| emit_insn (gen_divdi3_internal (operands[0], operands[1], operands[2])); | |
| @@ -2547,7 +3357,7 @@ | |
| (match_operand:DI 2 "se_nonmemory_operand" "di"))) | |
| (clobber (match_scratch:SI 3 "=h")) | |
| (clobber (match_scratch:SI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "ddiv\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "DI")]) | |
| @@ -2598,7 +3408,7 @@ | |
| (match_operand:DI 2 "se_register_operand" "d"))) | |
| (clobber (match_scratch:DI 3 "=l")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| emit_insn (gen_moddi3_internal (operands[0], operands[1], operands[2])); | |
| @@ -2627,7 +3437,7 @@ | |
| (match_operand:DI 2 "se_nonmemory_operand" "di"))) | |
| (clobber (match_scratch:SI 3 "=l")) | |
| (clobber (match_scratch:SI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "ddiv\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "DI")]) | |
| @@ -2669,7 +3479,7 @@ | |
| (match_operand:DI 2 "se_register_operand" "di"))) | |
| (clobber (match_scratch:DI 3 "=h")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| emit_insn (gen_udivdi3_internal (operands[0], operands[1], operands[2])); | |
| @@ -2689,7 +3499,7 @@ | |
| (match_operand:DI 2 "se_nonmemory_operand" "di"))) | |
| (clobber (match_scratch:SI 3 "=h")) | |
| (clobber (match_scratch:SI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "ddivu\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "DI")]) | |
| @@ -2731,7 +3541,7 @@ | |
| (match_operand:DI 2 "se_register_operand" "di"))) | |
| (clobber (match_scratch:DI 3 "=l")) | |
| (clobber (match_scratch:DI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| " | |
| { | |
| emit_insn (gen_umoddi3_internal (operands[0], operands[1], operands[2])); | |
| @@ -2751,7 +3561,7 @@ | |
| (match_operand:DI 2 "se_nonmemory_operand" "di"))) | |
| (clobber (match_scratch:SI 3 "=l")) | |
| (clobber (match_scratch:SI 4 "=a"))] | |
| - "TARGET_64BIT && !optimize" | |
| + "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law | |
| "ddivu\\t$0,%1,%2" | |
| [(set_attr "type" "idiv") | |
| (set_attr "mode" "DI")]) | |
| @@ -2775,9 +3585,19 @@ | |
| [(set (match_operand:SF 0 "register_operand" "=f") | |
| (sqrt:SF (match_operand:SF 1 "register_operand" "f")))] | |
| "TARGET_HARD_FLOAT && HAVE_SQRT_P()" | |
| - "sqrt.s\\t%0,%1" | |
| +"* | |
| +{ | |
| +if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG) | |
| + return \"%(nop\;nop\;sqrt.s\\t%0,%1%)\"; | |
| + return \"sqrt.s\\t%0,%1\"; | |
| +}" | |
| [(set_attr "type" "fsqrt") | |
| - (set_attr "mode" "SF")]) | |
| + (set_attr "mode" "SF") | |
| + (set (attr "length") | |
| + (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG") | |
| + (const_int 0)) | |
| + (const_int 4) | |
| + (const_int 12)))]) | |
| (define_insn "" | |
| [(set (match_operand:DF 0 "register_operand" "=f") | |
| @@ -2785,7 +3605,7 @@ | |
| (sqrt:DF (match_operand:DF 2 "register_operand" "f"))))] | |
| "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_fast_math" | |
| "rsqrt.d\\t%0,%2" | |
| - [(set_attr "type" "fsqrt") | |
| + [(set_attr "type" "frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| (set_attr "mode" "DF")]) | |
| (define_insn "" | |
| @@ -2793,10 +3613,37 @@ | |
| (div:SF (match_operand:SF 1 "const_float_1_operand" "") | |
| (sqrt:SF (match_operand:SF 2 "register_operand" "f"))))] | |
| "ISA_HAS_FP4 && TARGET_HARD_FLOAT && flag_fast_math" | |
| - "rsqrt.s\\t%0,%2" | |
| - [(set_attr "type" "fsqrt") | |
| - (set_attr "mode" "SF")]) | |
| +"* | |
| +{ | |
| +if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG) | |
| + return \"%(nop\;nop\;rsqrt.s\\t%0,%2%)\"; | |
| + return \"rsqrt.s\\t%0,%2\"; | |
| +}" | |
| + [(set_attr "type" "frsqrt") ; CYGNUS LOCAL vr5400/raeburn | |
| + (set_attr "mode" "SF") | |
| + (set (attr "length") | |
| + (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG") | |
| + (const_int 0)) | |
| + (const_int 4) | |
| + (const_int 12)))]) | |
| +(define_insn "" | |
| + [(set (match_operand:SF 0 "register_operand" "=f") | |
| + (div:SF (match_operand:SF 1 "register_operand" "f") | |
| + (sqrt:SF (match_operand:SF 2 "register_operand" "f"))))] | |
| + "TARGET_MIPS5900 && TARGET_HARD_FLOAT && flag_fast_math" | |
| +"* | |
| +{if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG) | |
| + return \"%(nop\;nop\;rsqrt.s\\t%0,%1,%2%)\"; | |
| + return \"rsqrt.s\\t%0,%2\"; | |
| +}" | |
| + [(set_attr "type" "frsqrt") | |
| + (set_attr "mode" "SF") | |
| + (set (attr "length") | |
| + (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG") | |
| + (const_int 0)) | |
| + (const_int 4) | |
| + (const_int 12)))]) | |
| ;; | |
| ;; .................... | |
| @@ -2857,6 +3704,81 @@ | |
| (set_attr "mode" "DI") | |
| (set_attr "length" "12")]) | |
| +(define_expand "absvsi2" | |
| + [(parallel [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (abs:SI (match_operand:SI 1 "register_operand" "d"))) | |
| + (trap_if (ne (abs:DI (sign_extend:DI (match_dup 1))) | |
| + (sign_extend:DI (abs:SI (match_dup 1)))) | |
| + (const_int 0))])] | |
| +"! TARGET_MIPS16" | |
| + " | |
| +{ | |
| + emit_insn (gen_absvsi2_internal (operands[0], operands[1])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "absvsi2_internal" | |
| + [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (abs:SI (match_operand:SI 1 "register_operand" "d"))) | |
| + (trap_if (ne (abs:DI (sign_extend:DI (match_dup 1))) | |
| + (sign_extend:DI (abs:SI (match_dup 1)))) | |
| + (const_int 0))] | |
| + "! TARGET_MIPS16" | |
| + "* | |
| +{ | |
| + dslots_jump_total++; | |
| + dslots_jump_filled++; | |
| + operands[2] = const0_rtx; | |
| + | |
| + if (REGNO (operands[0]) == REGNO (operands[1])) | |
| + { | |
| + if (GENERATE_BRANCHLIKELY) | |
| + return \"%(bltzl\\t%1,1f\\n\\tsub\\t%0,%z2,%0\\n1:%)\"; | |
| + else | |
| + return \"bgez\\t%1,1f%#\\n\\tsub\\t%0,%z2,%0\\n1:\"; | |
| + } | |
| + else | |
| + return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tsub\\t%0,%z2,%0\\n1:%)\"; | |
| +}" | |
| + [(set_attr "type" "multi") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "4")]) | |
| + | |
| +(define_expand "absvdi2" | |
| + [(parallel [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (abs:DI (match_operand:DI 1 "se_register_operand" "d"))) | |
| + (trap_if (ne (abs:TI (sign_extend:TI (match_dup 1))) | |
| + (sign_extend:TI (abs:DI (match_dup 1)))) | |
| + (const_int 0))])] | |
| + "TARGET_64BIT && ! TARGET_MIPS16" | |
| + " | |
| +{ | |
| + emit_insn (gen_absvdi2_internal (operands[0], operands[1])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "absvdi2_internal" | |
| + [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (abs:DI (match_operand:DI 1 "se_register_operand" "d"))) | |
| + (trap_if (ne (abs:TI (sign_extend:TI (match_dup 1))) | |
| + (sign_extend:TI (abs:DI (match_dup 1)))) | |
| + (const_int 0))] | |
| + "TARGET_64BIT" | |
| + "* | |
| +{ | |
| + dslots_jump_total++; | |
| + dslots_jump_filled++; | |
| + operands[2] = const0_rtx; | |
| + | |
| + if (REGNO (operands[0]) == REGNO (operands[1])) | |
| + return \"%(bltzl\\t%1,1f\\n\\tdsub\\t%0,%z2,%0\\n1:%)\"; | |
| + else | |
| + return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tdsub\\t%0,%z2,%0\\n1:%)\"; | |
| +}" | |
| + [(set_attr "type" "multi") | |
| + (set_attr "mode" "DI") | |
| + (set_attr "length" "4")]) | |
| + | |
| (define_insn "absdf2" | |
| [(set (match_operand:DF 0 "register_operand" "=f") | |
| (abs:DF (match_operand:DF 1 "register_operand" "f")))] | |
| @@ -2877,6 +3799,41 @@ | |
| ;; | |
| ;; .................... | |
| ;; | |
| +;; MIN & MAX | |
| +;; | |
| +;; .................... | |
| +;; | |
| + | |
| +(define_insn "minsf3" | |
| + [(set (match_operand:SF 0 "register_operand" "=f") | |
| + (if_then_else (lt:SF | |
| + (match_operand:SF 1 "register_operand" "f") | |
| + (match_operand:SF 2 "register_operand" "f")) | |
| + (match_dup 1) | |
| + (match_dup 2)))] | |
| + "TARGET_HARD_FLOAT && TARGET_MIPS5900" | |
| + "min.s\\t%0,%1,%2" | |
| + [(set_attr "type" "move") | |
| + (set_attr "mode" "SF") | |
| + (set_attr "length" "4")]) | |
| + | |
| +(define_insn "maxsf3" | |
| + [(set (match_operand:SF 0 "register_operand" "=f") | |
| + (if_then_else (gt:SF | |
| + (match_operand:SF 1 "register_operand" "f") | |
| + (match_operand:SF 2 "register_operand" "f")) | |
| + (match_dup 1) | |
| + (match_dup 2)))] | |
| + "TARGET_HARD_FLOAT && TARGET_MIPS5900" | |
| + "max.s\\t%0,%1,%2" | |
| + [(set_attr "type" "move") | |
| + (set_attr "mode" "SF") | |
| + (set_attr "length" "4")]) | |
| + | |
| + | |
| +;; | |
| +;; .................... | |
| +;; | |
| ;; FIND FIRST BIT INSTRUCTION | |
| ;; | |
| ;; .................... | |
| @@ -3018,6 +3975,59 @@ | |
| [(set_attr "type" "arith") | |
| (set_attr "mode" "DI")]) | |
| +(define_insn "negvsi2" | |
| + [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (neg:SI (match_operand:SI 1 "register_operand" "d"))) | |
| + (trap_if (ne (neg:DI (sign_extend:DI (match_dup 1))) | |
| + (sign_extend:DI (neg:SI (match_dup 1)))) | |
| + (const_int 0))] | |
| + "" | |
| + "* | |
| +{ | |
| + if (TARGET_MIPS16) | |
| + return \"neg\\t%0,%1\"; | |
| + operands[2] = const0_rtx; | |
| + return \"sub\\t%0,%z2,%1\"; | |
| +}" | |
| + [(set_attr "type" "arith") | |
| + (set_attr "mode" "SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "negvdi2" | |
| + [(parallel [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (neg:DI (match_operand:DI 1 "se_register_operand" "d"))) | |
| + (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1))) | |
| + (sign_extend:TI (neg:DI (match_dup 1)))) | |
| + (const_int 0)) | |
| + (clobber (match_dup 2))])] | |
| + "(TARGET_64BIT || ! TARGET_DEBUG_G_MODE) && ! TARGET_MIPS16" | |
| + " | |
| +{ | |
| + if (TARGET_64BIT) | |
| + { | |
| + emit_insn (gen_negvdi2_internal_2 (operands[0], operands[1])); | |
| + DONE; | |
| + } | |
| + | |
| + operands[2] = gen_reg_rtx (SImode); | |
| +}") | |
| + | |
| +(define_insn "negvdi2_internal_2" | |
| + [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (neg:DI (match_operand:DI 1 "se_register_operand" "d"))) | |
| + (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1))) | |
| + (sign_extend:TI (neg:DI (match_dup 1)))) | |
| + (const_int 0))] | |
| + "TARGET_64BIT && ! TARGET_MIPS16" | |
| + "* | |
| +{ | |
| + operands[2] = const0_rtx; | |
| + return \"dsub\\t%0,%z2,%1\"; | |
| +}" | |
| + [(set_attr "type" "arith") | |
| + (set_attr "mode" "DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| (define_insn "negdf2" | |
| [(set (match_operand:DF 0 "register_operand" "=f") | |
| (neg:DF (match_operand:DF 1 "register_operand" "f")))] | |
| @@ -3879,9 +4889,10 @@ | |
| ;; general register, we can sign extend from SImode to DImode just by | |
| ;; doing a move. | |
| +;; CYGNUS LOCAL law | |
| (define_insn "extendsidi2" | |
| [(set (match_operand:DI 0 "register_operand" "=d,y,d,*d,d,d") | |
| - (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,d,y,*x,R,m")))] | |
| + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,d,y,*x*w,R,m")))] | |
| "TARGET_64BIT" | |
| "* return mips_move_1word (operands, insn, FALSE);" | |
| [(set_attr "type" "move,move,move,hilo,load,load") | |
| @@ -4107,6 +5118,21 @@ | |
| { | |
| rtx xoperands[10]; | |
| + /* ??? trunc.w.s isn't implemented on the r5900, but cvt.w.s */ | |
| + /* truncates, so use it here. */ | |
| + if (TARGET_MIPS5900) | |
| + { | |
| + if (which_alternative == 1) | |
| + return \"cvt.w.s %0,%1\"; | |
| + | |
| + output_asm_insn (\"cvt.w.s %3,%1\", operands); | |
| + | |
| + xoperands[0] = operands[0]; | |
| + xoperands[1] = operands[3]; | |
| + output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands); | |
| + return \"\"; | |
| + } | |
| + | |
| if (which_alternative == 1) | |
| return \"trunc.w.s %0,%1,%2\"; | |
| @@ -4718,6 +5744,386 @@ | |
| [(set_attr "type" "arith") | |
| (set_attr "mode" "SI")]) | |
| +;; 128bit integer moves | |
| + | |
| +;; Unlike most other insns, the move insns can't be split with | |
| +;; different predicates, because register spilling and other parts of | |
| +;; the compiler, have memoized the insn number already. | |
| + | |
| +(define_expand "movti" | |
| + [(set (match_operand:TI 0 "nonimmediate_operand" "") | |
| + (match_operand:TI 1 "general_operand" ""))] | |
| + "TARGET_MIPS5900" | |
| + " | |
| +{ | |
| + /* I think this code is unnecessary since we'll never split when | |
| + the mode is larger than UNITS_PER_WORD. */ | |
| + if (mips_split_addresses && mips_check_split (operands[1], TImode)) | |
| + { | |
| + enum machine_mode mode = GET_MODE (operands[0]); | |
| + rtx tem = ((reload_in_progress | reload_completed) | |
| + ? operands[0] : gen_reg_rtx (mode)); | |
| + | |
| + emit_insn (gen_rtx (SET, VOIDmode, tem, | |
| + gen_rtx (HIGH, mode, operands[1]))); | |
| + | |
| + operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]); | |
| + } | |
| + | |
| + /* If we are generating embedded PIC code, and we are referring to a | |
| + symbol in the .text section, we must use an offset from the start | |
| + of the function. | |
| + | |
| + For now we abort this case on the R5900. */ | |
| + if (TARGET_EMBEDDED_PIC | |
| + && (GET_CODE (operands[1]) == LABEL_REF | |
| + || (GET_CODE (operands[1]) == SYMBOL_REF | |
| + && ! SYMBOL_REF_FLAG (operands[1])))) | |
| + abort (); | |
| + | |
| + /* If operands[1] is a constant address illegal for pic, then we need to | |
| + handle it just like LEGITIMIZE_ADDRESS does. | |
| + For now we abort this case on the R5900. */ | |
| + if (flag_pic && pic_address_needs_scratch (operands[1])) | |
| + abort (); | |
| + | |
| + /* Make operand1 a register if it isn't already. */ | |
| + if ((reload_in_progress | reload_completed) == 0 | |
| + && !register_operand (operands[0], TImode) | |
| + && !register_operand (operands[1], TImode) | |
| + && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) | |
| + && operands[1] != CONST0_RTX (TImode)) | |
| + { | |
| + rtx temp = force_reg (TImode, operands[1]); | |
| + emit_move_insn (operands[0], temp); | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| +(define_insn "movti_internal" | |
| + [(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d") | |
| + (match_operand:TI 1 "movti_operand" "d,R,m,d,d,J,K,L,M,i"))] | |
| + "TARGET_MIPS5900 | |
| + && (register_operand (operands[0], TImode) | |
| + || se_register_operand (operands[1], TImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (TImode))" | |
| + "@ | |
| + por %0,$0,%1 | |
| + lq %0,%1 | |
| + lq %0,%1 | |
| + sq %1,%0 | |
| + sq %1,%0 | |
| + por %0,%.,%. | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui | |
| + por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro | |
| + dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1" | |
| + [(set_attr "type" "move,load,load,store,store,move,move,move,move,move") | |
| +;; Really DI, but not important for the cases we care about. | |
| + (set_attr "mode" "DI") | |
| +;; The general li macro on a 64 bit machine can be up to 7 instructions long. | |
| + (set_attr "length" "4,4,4,4,4,4,8,8,32,60")]) | |
| + | |
| +(define_expand "movv16qi" | |
| + [(set (match_operand:V16QI 0 "nonimmediate_operand" "") | |
| + (match_operand:V16QI 1 "general_operand" ""))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + /* I think this code is unnecessary since we'll never split when | |
| + the mode is larger than UNITS_PER_WORD. */ | |
| + if (mips_split_addresses && mips_check_split (operands[1], V16QImode)) | |
| + { | |
| + enum machine_mode mode = GET_MODE (operands[0]); | |
| + rtx tem = ((reload_in_progress | reload_completed) | |
| + ? operands[0] : gen_reg_rtx (mode)); | |
| + | |
| + emit_insn (gen_rtx (SET, VOIDmode, tem, | |
| + gen_rtx (HIGH, mode, operands[1]))); | |
| + | |
| + operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]); | |
| + } | |
| + | |
| + /* If we are generating embedded PIC code, and we are referring to a | |
| + symbol in the .text section, we must use an offset from the start | |
| + of the function. | |
| + | |
| + For now we abort this case on the R5900. */ | |
| + if (TARGET_EMBEDDED_PIC | |
| + && (GET_CODE (operands[1]) == LABEL_REF | |
| + || (GET_CODE (operands[1]) == SYMBOL_REF | |
| + && ! SYMBOL_REF_FLAG (operands[1])))) | |
| + abort (); | |
| + | |
| + /* If operands[1] is a constant address illegal for pic, then we need to | |
| + handle it just like LEGITIMIZE_ADDRESS does. | |
| + For now we abort this case on the R5900. */ | |
| + if (flag_pic && pic_address_needs_scratch (operands[1])) | |
| + abort (); | |
| + | |
| + /* Make operand1 a register if it isn't already. */ | |
| + if ((reload_in_progress | reload_completed) == 0 | |
| + && !register_operand (operands[0], V16QImode) | |
| + && !register_operand (operands[1], V16QImode) | |
| + && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) | |
| + && operands[1] != CONST0_RTX (V16QImode)) | |
| + { | |
| + rtx temp = force_reg (V16QImode, operands[1]); | |
| + emit_move_insn (operands[0], temp); | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| +(define_expand "movv8hi" | |
| + [(set (match_operand:V8HI 0 "nonimmediate_operand" "") | |
| + (match_operand:V8HI 1 "general_operand" ""))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + /* I think this code is unnecessary since we'll never split when | |
| + the mode is larger than UNITS_PER_WORD. */ | |
| + if (mips_split_addresses && mips_check_split (operands[1], V8HImode)) | |
| + { | |
| + enum machine_mode mode = GET_MODE (operands[0]); | |
| + rtx tem = ((reload_in_progress | reload_completed) | |
| + ? operands[0] : gen_reg_rtx (mode)); | |
| + | |
| + emit_insn (gen_rtx (SET, VOIDmode, tem, | |
| + gen_rtx (HIGH, mode, operands[1]))); | |
| + | |
| + operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]); | |
| + } | |
| + | |
| + /* If we are generating embedded PIC code, and we are referring to a | |
| + symbol in the .text section, we must use an offset from the start | |
| + of the function. | |
| + | |
| + For now we abort this case on the R5900. */ | |
| + if (TARGET_EMBEDDED_PIC | |
| + && (GET_CODE (operands[1]) == LABEL_REF | |
| + || (GET_CODE (operands[1]) == SYMBOL_REF | |
| + && ! SYMBOL_REF_FLAG (operands[1])))) | |
| + abort (); | |
| + | |
| + /* If operands[1] is a constant address illegal for pic, then we need to | |
| + handle it just like LEGITIMIZE_ADDRESS does. | |
| + For now we abort this case on the R5900. */ | |
| + if (flag_pic && pic_address_needs_scratch (operands[1])) | |
| + abort (); | |
| + | |
| + /* Make operand1 a register if it isn't already. */ | |
| + if ((reload_in_progress | reload_completed) == 0 | |
| + && !register_operand (operands[0], V8HImode) | |
| + && !register_operand (operands[1], V8HImode) | |
| + && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) | |
| + && operands[1] != CONST0_RTX (V8HImode)) | |
| + { | |
| + rtx temp = force_reg (V8HImode, operands[1]); | |
| + emit_move_insn (operands[0], temp); | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| +(define_expand "movv4si" | |
| + [(set (match_operand:V4SI 0 "nonimmediate_operand" "") | |
| + (match_operand:V4SI 1 "general_operand" ""))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + /* I think this code is unnecessary since we'll never split when | |
| + the mode is larger than UNITS_PER_WORD. */ | |
| + if (mips_split_addresses && mips_check_split (operands[1], V4SImode)) | |
| + { | |
| + enum machine_mode mode = GET_MODE (operands[0]); | |
| + rtx tem = ((reload_in_progress | reload_completed) | |
| + ? operands[0] : gen_reg_rtx (mode)); | |
| + | |
| + emit_insn (gen_rtx (SET, VOIDmode, tem, | |
| + gen_rtx (HIGH, mode, operands[1]))); | |
| + | |
| + operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]); | |
| + } | |
| + | |
| + /* If we are generating embedded PIC code, and we are referring to a | |
| + symbol in the .text section, we must use an offset from the start | |
| + of the function. | |
| + | |
| + For now we abort this case on the R5900. */ | |
| + if (TARGET_EMBEDDED_PIC | |
| + && (GET_CODE (operands[1]) == LABEL_REF | |
| + || (GET_CODE (operands[1]) == SYMBOL_REF | |
| + && ! SYMBOL_REF_FLAG (operands[1])))) | |
| + abort (); | |
| + | |
| + /* If operands[1] is a constant address illegal for pic, then we need to | |
| + handle it just like LEGITIMIZE_ADDRESS does. | |
| + For now we abort this case on the R5900. */ | |
| + if (flag_pic && pic_address_needs_scratch (operands[1])) | |
| + abort (); | |
| + | |
| + /* Make operand1 a register if it isn't already. */ | |
| + if ((reload_in_progress | reload_completed) == 0 | |
| + && !register_operand (operands[0], V4SImode) | |
| + && !register_operand (operands[1], V4SImode) | |
| + && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) | |
| + && operands[1] != CONST0_RTX (V4SImode)) | |
| + { | |
| + rtx temp = force_reg (V4SImode, operands[1]); | |
| + emit_move_insn (operands[0], temp); | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| +(define_expand "movv2di" | |
| + [(set (match_operand:V2DI 0 "nonimmediate_operand" "") | |
| + (match_operand:V2DI 1 "general_operand" ""))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + /* I think this code is unnecessary since we'll never split when | |
| + the mode is larger than UNITS_PER_WORD. */ | |
| + if (mips_split_addresses && mips_check_split (operands[1], V2DImode)) | |
| + { | |
| + enum machine_mode mode = GET_MODE (operands[0]); | |
| + rtx tem = ((reload_in_progress | reload_completed) | |
| + ? operands[0] : gen_reg_rtx (mode)); | |
| + | |
| + emit_insn (gen_rtx (SET, VOIDmode, tem, | |
| + gen_rtx (HIGH, mode, operands[1]))); | |
| + | |
| + operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]); | |
| + } | |
| + | |
| + /* If we are generating embedded PIC code, and we are referring to a | |
| + symbol in the .text section, we must use an offset from the start | |
| + of the function. | |
| + | |
| + For now we abort this case on the R5900. */ | |
| + if (TARGET_EMBEDDED_PIC | |
| + && (GET_CODE (operands[1]) == LABEL_REF | |
| + || (GET_CODE (operands[1]) == SYMBOL_REF | |
| + && ! SYMBOL_REF_FLAG (operands[1])))) | |
| + abort (); | |
| + | |
| + /* If operands[1] is a constant address illegal for pic, then we need to | |
| + handle it just like LEGITIMIZE_ADDRESS does. | |
| + For now we abort this case on the R5900. */ | |
| + if (flag_pic && pic_address_needs_scratch (operands[1])) | |
| + abort (); | |
| + | |
| + /* Make operand1 a register if it isn't already. */ | |
| + if ((reload_in_progress | reload_completed) == 0 | |
| + && !register_operand (operands[0], V2DImode) | |
| + && !register_operand (operands[1], V2DImode) | |
| + && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) | |
| + && operands[1] != CONST0_RTX (V2DImode)) | |
| + { | |
| + rtx temp = force_reg (V2DImode, operands[1]); | |
| + emit_move_insn (operands[0], temp); | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| +(define_insn "movv16qi_internal" | |
| + [(set (match_operand:V16QI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d") | |
| + (match_operand:V16QI 1 "movv16qi_operand" "d,R,m,d,d,J,K,L,M,i"))] | |
| + "TARGET_SIMD | |
| + && (register_operand (operands[0], V16QImode) | |
| + || se_register_operand (operands[1], V16QImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (V16QImode))" | |
| + "@ | |
| + por %0,$0,%1 | |
| + lq %0,%1 | |
| + lq %0,%1 | |
| + sq %1,%0 | |
| + sq %1,%0 | |
| + por %0,%.,%. | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui | |
| + por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro | |
| + dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1" | |
| + [(set_attr "type" "move,load,load,store,store,move,move,move,move,move") | |
| +;; Really DI, but not important for the cases we care about. | |
| + (set_attr "mode" "DI") | |
| +;; The general li macro on a 64 bit machine can be up to 7 instructions long. | |
| + (set_attr "length" "1,1,1,1,1,1,2,2,8,15")]) | |
| + | |
| +(define_insn "movv8hi_internal" | |
| + [(set (match_operand:V8HI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d") | |
| + (match_operand:V8HI 1 "movv8hi_operand" "d,R,m,d,d,J,K,L,M,i"))] | |
| + "TARGET_SIMD | |
| + && (register_operand (operands[0], V8HImode) | |
| + || se_register_operand (operands[1], V8HImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (V8HImode))" | |
| + "@ | |
| + por %0,$0,%1 | |
| + lq %0,%1 | |
| + lq %0,%1 | |
| + sq %1,%0 | |
| + sq %1,%0 | |
| + por %0,%.,%. | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui | |
| + por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro | |
| + dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1" | |
| + [(set_attr "type" "move,load,load,store,store,move,move,move,move,move") | |
| +;; Really DI, but not important for the cases we care about. | |
| + (set_attr "mode" "DI") | |
| +;; The general li macro on a 64 bit machine can be up to 7 instructions long. | |
| + (set_attr "length" "1,1,1,1,1,1,2,2,8,15")]) | |
| + | |
| +(define_insn "movv4si_internal" | |
| + [(set (match_operand:V4SI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d") | |
| + (match_operand:V4SI 1 "movv4si_operand" "d,R,m,d,d,J,K,L,M,i"))] | |
| + "TARGET_SIMD | |
| + && (register_operand (operands[0], V4SImode) | |
| + || se_register_operand (operands[1], V4SImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (V4SImode))" | |
| + "@ | |
| + por %0,$0,%1 | |
| + lq %0,%1 | |
| + lq %0,%1 | |
| + sq %1,%0 | |
| + sq %1,%0 | |
| + por %0,%.,%. | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui | |
| + por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro | |
| + dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1" | |
| + [(set_attr "type" "move,load,load,store,store,move,move,move,move,move") | |
| +;; Really DI, but not important for the cases we care about. | |
| + (set_attr "mode" "DI") | |
| +;; The general li macro on a 64 bit machine can be up to 7 instructions long. | |
| + (set_attr "length" "1,1,1,1,1,1,2,2,8,15")]) | |
| + | |
| +(define_insn "movv2di_internal" | |
| + [(set (match_operand:V2DI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d") | |
| + (match_operand:V2DI 1 "movv2di_operand" "d,R,m,d,d,J,K,L,M,i"))] | |
| + "TARGET_SIMD | |
| + && (register_operand (operands[0], V2DImode) | |
| + || se_register_operand (operands[1], V2DImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (V2DImode))" | |
| + "@ | |
| + por %0,$0,%1 | |
| + lq %0,%1 | |
| + lq %0,%1 | |
| + sq %1,%0 | |
| + sq %1,%0 | |
| + por %0,%.,%. | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori | |
| + por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui | |
| + por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro | |
| + dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1" | |
| + [(set_attr "type" "move,load,load,store,store,move,move,move,move,move") | |
| +;; Really DI, but not important for the cases we care about. | |
| + (set_attr "mode" "DI") | |
| +;; The general li macro on a 64 bit machine can be up to 7 instructions long. | |
| + (set_attr "length" "1,1,1,1,1,1,2,2,8,15")]) | |
| ;; 64-bit integer moves | |
| ;; Unlike most other insns, the move insns can't be split with | |
| @@ -4827,6 +6233,109 @@ | |
| } | |
| }") | |
| +(define_expand "movv2si" | |
| + [(set (match_operand:V2SI 0 "nonimmediate_operand" "") | |
| + (match_operand:V2SI 1 "general_operand" ""))] | |
| + "" | |
| + " | |
| +{ | |
| + if (mips_split_addresses && mips_check_split (operands[1], V2SImode)) | |
| + { | |
| + enum machine_mode mode = GET_MODE (operands[0]); | |
| + rtx tem = ((reload_in_progress | reload_completed) | |
| + ? operands[0] : gen_reg_rtx (mode)); | |
| + | |
| + emit_insn (gen_rtx (SET, VOIDmode, tem, | |
| + gen_rtx (HIGH, mode, operands[1]))); | |
| + | |
| + operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]); | |
| + } | |
| + | |
| + /* If we are generating embedded PIC code, and we are referring to a | |
| + symbol in the .text section, we must use an offset from the start | |
| + of the function. */ | |
| + if (TARGET_EMBEDDED_PIC | |
| + && (GET_CODE (operands[1]) == LABEL_REF | |
| + || (GET_CODE (operands[1]) == SYMBOL_REF | |
| + && ! SYMBOL_REF_FLAG (operands[1])))) | |
| + { | |
| + rtx temp; | |
| + | |
| + temp = embedded_pic_offset (operands[1]); | |
| + temp = gen_rtx (PLUS, Pmode, embedded_pic_fnaddr_rtx, | |
| + force_reg (V2SImode, temp)); | |
| + emit_move_insn (operands[0], force_reg (V2SImode, temp)); | |
| + DONE; | |
| + } | |
| + | |
| + /* If operands[1] is a constant address illegal for pic, then we need to | |
| + handle it just like LEGITIMIZE_ADDRESS does. */ | |
| + if (flag_pic && pic_address_needs_scratch (operands[1])) | |
| + { | |
| + rtx temp = force_reg (V2SImode, XEXP (XEXP (operands[1], 0), 0)); | |
| + rtx temp2 = XEXP (XEXP (operands[1], 0), 1); | |
| + | |
| + if (! SMALL_INT (temp2)) | |
| + temp2 = force_reg (V2SImode, temp2); | |
| + | |
| + emit_move_insn (operands[0], gen_rtx (PLUS, V2SImode, temp, temp2)); | |
| + DONE; | |
| + } | |
| + | |
| + /* On the mips16, we can handle a GP relative reference by adding in | |
| + $gp. We need to check the name to see whether this is a string | |
| + constant. */ | |
| + if (TARGET_MIPS16 | |
| + && register_operand (operands[0], V2SImode) | |
| + && GET_CODE (operands[1]) == SYMBOL_REF | |
| + && SYMBOL_REF_FLAG (operands[1])) | |
| + { | |
| + char *name = XSTR (operands[1], 0); | |
| + | |
| + if (name[0] != '*' | |
| + || strncmp (name + 1, LOCAL_LABEL_PREFIX, | |
| + sizeof LOCAL_LABEL_PREFIX - 1) != 0) | |
| + { | |
| + rtx base_reg; | |
| + | |
| + if (reload_in_progress || reload_completed) | |
| + { | |
| + /* In movsi we use the constant table here. However, in | |
| + this case, we're better off copying $28 into a | |
| + register and adding, because the constant table entry | |
| + would be 8 bytes. */ | |
| + base_reg = operands[0]; | |
| + emit_move_insn (base_reg, | |
| + gen_rtx (CONST, V2SImode, | |
| + gen_rtx (REG, V2SImode, | |
| + GP_REG_FIRST + 28))); | |
| + } | |
| + else | |
| + { | |
| + base_reg = gen_reg_rtx (Pmode); | |
| + emit_move_insn (base_reg, mips16_gp_pseudo_reg ()); | |
| + } | |
| + | |
| + emit_move_insn (operands[0], | |
| + gen_rtx (PLUS, Pmode, base_reg, | |
| + mips16_gp_offset (operands[1]))); | |
| + DONE; | |
| + } | |
| + } | |
| + | |
| + if ((reload_in_progress | reload_completed) == 0 | |
| + && !register_operand (operands[0], V2SImode) | |
| + && !register_operand (operands[1], V2SImode) | |
| + && (TARGET_MIPS16 | |
| + || ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) | |
| + && operands[1] != CONST0_RTX (V2SImode)))) | |
| + { | |
| + rtx temp = force_reg (V2SImode, operands[1]); | |
| + emit_move_insn (operands[0], temp); | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| ;; For mips16, we need a special case to handle storing $31 into | |
| ;; memory, since we don't have a constraint to match $31. This | |
| ;; instruction can be generated by save_restore_insns. | |
| @@ -4844,8 +6353,9 @@ | |
| (set_attr "mode" "DI") | |
| (set_attr "length" "4,8")]) | |
| +;; CYGNUS LOCAL law | |
| (define_insn "movdi_internal" | |
| - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x,*d,*x") | |
| + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x*w,*d,*x*w") | |
| (match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d"))] | |
| "!TARGET_64BIT && !TARGET_MIPS16 | |
| && (register_operand (operands[0], DImode) | |
| @@ -4857,9 +6367,23 @@ | |
| (set_attr "mode" "DI") | |
| (set_attr "length" "8,16,8,16,8,16,8,8,8")]) | |
| +(define_insn "movv2si_internal" | |
| + [(set (match_operand:V2SI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x*w,*d,*x*w") | |
| + (match_operand:V2SI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d"))] | |
| + "TARGET_SIMD | |
| + && (register_operand (operands[0], V2SImode) | |
| + || register_operand (operands[1], V2SImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (V2SImode))" | |
| + "* return mips_move_2words (operands, insn); " | |
| + [(set_attr "type" "move,arith,load,load,store,store,hilo,hilo,hilo") | |
| + (set_attr "mode" "V2SI") | |
| + (set_attr "length" "2,4,2,4,2,4,2,2,2")]) | |
| + | |
| +;; CYGNUS LOCAL law | |
| (define_insn "" | |
| [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,To,*d") | |
| - (match_operand:DI 1 "general_operand" "d,d,y,K,N,R,To,d,d,*x"))] | |
| + (match_operand:DI 1 "general_operand" "d,d,y,K,N,R,To,d,d,*x*w"))] | |
| "!TARGET_64BIT && TARGET_MIPS16 | |
| && (register_operand (operands[0], DImode) | |
| || register_operand (operands[1], DImode))" | |
| @@ -4879,9 +6403,10 @@ | |
| (set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))] | |
| "") | |
| +;; CYGNUS LOCAL law | |
| (define_insn "movdi_internal2" | |
| - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x,*d,*x,*a") | |
| - (match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J"))] | |
| + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x*w,*d,*x*w,*a*q") | |
| + (match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x*w,*d,*J"))] | |
| "TARGET_64BIT && !TARGET_MIPS16 | |
| && (register_operand (operands[0], DImode) | |
| || se_register_operand (operands[1], DImode) | |
| @@ -4892,9 +6417,23 @@ | |
| (set_attr "mode" "DI") | |
| (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,8")]) | |
| +(define_insn "movv2si_internal2" | |
| + [(set (match_operand:V2SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x*w,*d,*x*w,*a*q") | |
| + (match_operand:V2SI 1 "movv2si_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x*w,*d,*J"))] | |
| + "TARGET_SIMD | |
| + && (register_operand (operands[0], V2SImode) | |
| + || se_register_operand (operands[1], V2SImode) | |
| + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) | |
| + || operands[1] == CONST0_RTX (V2SImode))" | |
| + "* return mips_move_2words (operands, insn); " | |
| + [(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo") | |
| + (set_attr "mode" "V2SI") | |
| + (set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,2")]) | |
| + | |
| +;; CYGNUS LOCAL law | |
| (define_insn "" | |
| [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d") | |
| - (match_operand:DI 1 "movdi_operand" "d,d,y,K,N,s,R,m,d,d,*x"))] | |
| + (match_operand:DI 1 "movdi_operand" "d,d,y,K,N,s,R,m,d,d,*x*w"))] | |
| "TARGET_64BIT && TARGET_MIPS16 | |
| && (register_operand (operands[0], DImode) | |
| || se_register_operand (operands[1], DImode))" | |
| @@ -5023,6 +6562,57 @@ | |
| } | |
| DONE; | |
| } | |
| + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO1_REGNUM) | |
| + { | |
| + if (GET_CODE (operands[1]) == MEM) | |
| + { | |
| + rtx memword, offword, hiword, loword; | |
| + rtx addr = find_replacement (&XEXP (operands[1], 0)); | |
| + rtx op1 = change_address (operands[1], VOIDmode, addr); | |
| + | |
| + scratch = gen_rtx (REG, SImode, REGNO (scratch)); | |
| + memword = change_address (op1, SImode, NULL_RTX); | |
| + offword = change_address (adj_offsettable_operand (op1, 4), | |
| + SImode, NULL_RTX); | |
| + if (BYTES_BIG_ENDIAN) | |
| + { | |
| + hiword = memword; | |
| + loword = offword; | |
| + } | |
| + else | |
| + { | |
| + hiword = offword; | |
| + loword = memword; | |
| + } | |
| + emit_move_insn (scratch, hiword); | |
| + emit_move_insn (gen_rtx (REG, SImode, 76), scratch); | |
| + emit_move_insn (scratch, loword); | |
| + emit_move_insn (gen_rtx (REG, SImode, 77), scratch); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); | |
| + | |
| + } | |
| + else | |
| + { | |
| + emit_insn (gen_ashrdi3 (scratch, operands[1], GEN_INT (32))); | |
| + emit_insn (gen_movdi (gen_rtx (REG, DImode, 76), scratch)); | |
| + emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32))); | |
| + emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_movdi (gen_rtx (REG, DImode, 77), scratch)); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); | |
| + } | |
| + DONE; | |
| + } | |
| + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO1_REGNUM) | |
| + { | |
| + emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 77))); | |
| + emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 76))); | |
| + emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32))); | |
| + emit_insn (gen_iordi3 (operands[0], operands[0], scratch)); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); | |
| + DONE; | |
| + } | |
| if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM) | |
| { | |
| emit_insn (gen_movdi (scratch, gen_rtx_REG (DImode, 65))); | |
| @@ -5064,6 +6654,16 @@ | |
| emit_insn (gen_rtx_USE (VOIDmode, operands[0])); | |
| DONE; | |
| } | |
| + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO1_REGNUM) | |
| + { | |
| + emit_insn (gen_ashrdi3 (scratch, operands[1], GEN_INT (32))); | |
| + emit_insn (gen_movdi (gen_rtx (REG, DImode, 76), scratch)); | |
| + emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32))); | |
| + emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_movdi (gen_rtx (REG, DImode, 77), scratch)); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); | |
| + DONE; | |
| + } | |
| if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM) | |
| { | |
| if (GET_CODE (operands[0]) == MEM) | |
| @@ -5119,6 +6719,61 @@ | |
| } | |
| DONE; | |
| } | |
| + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO1_REGNUM) | |
| + { | |
| + if (GET_CODE (operands[0]) == MEM) | |
| + { | |
| + rtx scratch, memword, offword, hiword, loword; | |
| + rtx addr = find_replacement (&XEXP (operands[0], 0)); | |
| + rtx op0 = change_address (operands[0], VOIDmode, addr); | |
| + | |
| + scratch = gen_rtx (REG, SImode, REGNO (operands[2])); | |
| + memword = change_address (op0, SImode, NULL_RTX); | |
| + offword = change_address (adj_offsettable_operand (op0, 4), | |
| + SImode, NULL_RTX); | |
| + if (BYTES_BIG_ENDIAN) | |
| + { | |
| + hiword = memword; | |
| + loword = offword; | |
| + } | |
| + else | |
| + { | |
| + hiword = offword; | |
| + loword = memword; | |
| + } | |
| + emit_move_insn (scratch, gen_rtx (REG, SImode, 76)); | |
| + emit_move_insn (hiword, scratch); | |
| + emit_move_insn (scratch, gen_rtx (REG, SImode, 77)); | |
| + emit_move_insn (loword, scratch); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); | |
| + } | |
| + else if (TARGET_MIPS16 && ! M16_REG_P (REGNO (operands[0]))) | |
| + { | |
| + /* Handle the case where operand[0] is not a 'd' register, | |
| + and hence we can not directly move from the HILO register | |
| + into it. */ | |
| + rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1); | |
| + emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 77))); | |
| + emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_movdi (scratch2, gen_rtx (REG, DImode, 76))); | |
| + emit_insn (gen_ashldi3 (scratch2, scratch2, GEN_INT (32))); | |
| + emit_insn (gen_iordi3 (scratch, scratch, scratch2)); | |
| + emit_insn (gen_movdi (operands[0], scratch)); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); | |
| + } | |
| + else | |
| + { | |
| + emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 77))); | |
| + emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32))); | |
| + emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 76))); | |
| + emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32))); | |
| + emit_insn (gen_iordi3 (operands[0], operands[0], scratch)); | |
| + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); | |
| + } | |
| + DONE; | |
| + } | |
| /* This handles moves between a float register and HI/LO. */ | |
| emit_move_insn (scratch, operands[1]); | |
| emit_move_insn (operands[0], scratch); | |
| @@ -5238,7 +6893,9 @@ | |
| if ((reload_in_progress | reload_completed) == 0 | |
| && !register_operand (operands[0], SImode) | |
| - && !register_operand (operands[1], SImode) | |
| + && ! (register_operand (operands[1], SImode) | |
| + && operands[1] != arg_pointer_rtx | |
| + && operands[1] != virtual_incoming_args_rtx) | |
| && (TARGET_MIPS16 | |
| || GET_CODE (operands[1]) != CONST_INT | |
| || INTVAL (operands[1]) != 0)) | |
| @@ -5269,9 +6926,10 @@ | |
| ;; The difference between these two is whether or not ints are allowed | |
| ;; in FP registers (off by default, use -mdebugh to enable). | |
| +;; CYGNUS LOCAL law | |
| (define_insn "movsi_internal1" | |
| - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d") | |
| - (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a"))] | |
| + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x*w,*x*w,*d,*d") | |
| + (match_operand:SI 1 "move_operand" "dA,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x*w,*a*q"))] | |
| "TARGET_DEBUG_H_MODE && !TARGET_MIPS16 | |
| && (register_operand (operands[0], SImode) | |
| || register_operand (operands[1], SImode) | |
| @@ -5281,9 +6939,10 @@ | |
| (set_attr "mode" "SI") | |
| (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,8,4,8,4,4,4,4")]) | |
| +;; CYGNUS LOCAL law | |
| (define_insn "movsi_internal2" | |
| - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d") | |
| - (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a"))] | |
| + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x*w,*d,*x*w,*d") | |
| + (match_operand:SI 1 "move_operand" "dA,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x*w,*d,*a*q"))] | |
| "!TARGET_DEBUG_H_MODE && !TARGET_MIPS16 | |
| && (register_operand (operands[0], SImode) | |
| || register_operand (operands[1], SImode) | |
| @@ -6326,7 +7985,7 @@ | |
| return \"sll\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "SI")]) | |
| (define_insn "ashlsi3_internal2" | |
| @@ -6344,7 +8003,7 @@ | |
| 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) | |
| @@ -6603,7 +8262,7 @@ | |
| return \"dsll\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "DI")]) | |
| (define_insn "" | |
| @@ -6621,7 +8280,7 @@ | |
| 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) | |
| @@ -6687,7 +8346,7 @@ | |
| return \"sra\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "SI")]) | |
| (define_insn "ashrsi3_internal2" | |
| @@ -6705,7 +8364,7 @@ | |
| 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) | |
| @@ -6956,7 +8615,7 @@ | |
| return \"dsra\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "DI")]) | |
| (define_insn "" | |
| @@ -6971,7 +8630,7 @@ | |
| return \"dsra\\t%0,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "DI") | |
| (set_attr_alternative "length" | |
| [(const_int 4) | |
| @@ -7036,7 +8695,7 @@ | |
| return \"srl\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "SI")]) | |
| (define_insn "lshrsi3_internal2" | |
| @@ -7054,7 +8713,7 @@ | |
| 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) | |
| @@ -7341,8 +9000,40 @@ | |
| return \"dsrl\\t%0,%1,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| + (set_attr "mode" "DI")]) | |
| + | |
| +;; CYGNUS LOCAL vr5400/raeburn | |
| +(define_insn "rotrsi3" | |
| + [(set (match_operand:SI 0 "register_operand" "=d") | |
| + (rotatert:SI (match_operand:SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "arith_operand" "dn")))] | |
| + "TARGET_MIPS5400" | |
| + "* | |
| +{ | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); | |
| + | |
| + return \"ror\\t%0,%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "shift") | |
| + (set_attr "mode" "SI")]) | |
| + | |
| +(define_insn "rotrdi3" | |
| + [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (rotatert:DI (match_operand:DI 1 "register_operand" "d") | |
| + (match_operand:DI 2 "arith_operand" "dn")))] | |
| + "TARGET_MIPS5400 && TARGET_64BIT" | |
| + "* | |
| +{ | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); | |
| + | |
| + return \"dror\\t%0,%1,%2\"; | |
| +}" | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "DI")]) | |
| +;; END CYGNUS LOCAL | |
| (define_insn "" | |
| [(set (match_operand:DI 0 "register_operand" "=d,d") | |
| @@ -7356,7 +9047,7 @@ | |
| return \"dsrl\\t%0,%2\"; | |
| }" | |
| - [(set_attr "type" "arith") | |
| + [(set_attr "type" "shift") | |
| (set_attr "mode" "DI") | |
| (set_attr_alternative "length" | |
| [(const_int 4) | |
| @@ -9379,6 +11070,7 @@ | |
| (set_attr "mode" "none") | |
| (set_attr "length" "0")]) | |
| +;; CYGNUS LOCAL sibcall/law | |
| (define_expand "epilogue" | |
| [(const_int 2)] | |
| "" | |
| @@ -9386,10 +11078,23 @@ | |
| { | |
| if (mips_isa >= 0) /* avoid unused code warnings */ | |
| { | |
| - mips_expand_epilogue (); | |
| + mips_expand_epilogue (0); /* CYGNUS LOCAL sibcall/law */ | |
| + DONE; | |
| + } | |
| +}") | |
| + | |
| +(define_expand "sibcall_epilogue" | |
| + [(const_int 3)] | |
| + "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS" | |
| + " | |
| +{ | |
| + if (mips_isa >= 0) /* avoid unused code warnings */ | |
| + { | |
| + mips_expand_epilogue (1); /* CYGNUS LOCAL sibcall/law */ | |
| DONE; | |
| } | |
| }") | |
| +;; END CYGNUS LOCAL | |
| ;; Trivial return. Make it look like a normal return insn as that | |
| ;; allows jump optimizations to work better . | |
| @@ -9446,47 +11151,10 @@ | |
| "" | |
| " | |
| { | |
| - rtx addr; | |
| - | |
| - if (operands[0]) /* eliminate unused code warnings */ | |
| - { | |
| - addr = XEXP (operands[0], 0); | |
| - if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS)) | |
| - || ! call_insn_operand (addr, VOIDmode)) | |
| - XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr); | |
| - | |
| - /* In order to pass small structures by value in registers | |
| - compatibly with the MIPS compiler, we need to shift the value | |
| - into the high part of the register. Function_arg has encoded | |
| - a PARALLEL rtx, holding a vector of adjustments to be made | |
| - as the next_arg_reg variable, so we split up the insns, | |
| - and emit them separately. */ | |
| - | |
| - if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL) | |
| - { | |
| - rtvec adjust = XVEC (operands[2], 0); | |
| - int num = GET_NUM_ELEM (adjust); | |
| - int i; | |
| - | |
| - for (i = 0; i < num; i++) | |
| - emit_insn (RTVEC_ELT (adjust, i)); | |
| - } | |
| - | |
| - if (TARGET_MIPS16 | |
| - && mips16_hard_float | |
| - && operands[2] != 0 | |
| - && (int) GET_MODE (operands[2]) != 0) | |
| - { | |
| - if (build_mips16_call_stub (NULL_RTX, operands[0], operands[1], | |
| - (int) GET_MODE (operands[2]))) | |
| - DONE; | |
| - } | |
| - | |
| - emit_call_insn (gen_call_internal0 (operands[0], operands[1], | |
| - gen_rtx_REG (SImode, | |
| - GP_REG_FIRST + 31))); | |
| + /* CYGNUS LOCAL sibcall/law */ | |
| + mips_expand_call (operands, 0); | |
| DONE; | |
| - } | |
| + /* END CYGNUS LOCAL */ | |
| }") | |
| (define_expand "call_internal0" | |
| @@ -9619,6 +11287,48 @@ | |
| (set_attr "mode" "none") | |
| (set_attr "length" "8")]) | |
| +;; CYGNUS LOCAL sibcall/law | |
| +(define_expand "sibcall" | |
| + [(parallel [(call (match_operand 0 "memory_operand" "m") | |
| + (match_operand 1 "" "i")) | |
| + (use (match_operand 2 "" "")) ;; next_arg_reg | |
| + (use (match_operand 3 "" "")) ;; struct_value_size_rtx | |
| + (use (reg:SI 31))])] ;; need $ra to return | |
| + "" | |
| + " | |
| +{ | |
| + mips_expand_call (operands, 1); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_expand "sibcall_internal0" | |
| + [(parallel [(call (match_operand 0 "" "") | |
| + (match_operand 1 "" "")) | |
| + (use (reg:SI 31))])] ;; need $ra to return | |
| + "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS" | |
| + "") | |
| + | |
| +(define_insn "sibcall_internal1" | |
| + [(parallel [(call (mem (match_operand 0 "call_insn_operand" "ri")) | |
| + (match_operand 1 "" "i")) | |
| + (use (reg:SI 31))])] | |
| + "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS" | |
| + "* | |
| +{ | |
| + register rtx target = operands[0]; | |
| + | |
| + if (GET_CODE (target) == SYMBOL_REF) | |
| + return \"%*j\\t%0\"; | |
| + else if (GET_CODE (target) == CONST_INT) | |
| + return \"%[li\\t%@,%0\\n\\t%*j\\t%@%]\"; | |
| + else | |
| + return \"%*j\\t%0\"; | |
| +}" | |
| + [(set_attr "type" "call") | |
| + (set_attr "mode" "none") | |
| + (set_attr "length" "4")]) | |
| +;; END CYGNUS LOCAL | |
| + | |
| ;; calls.c now passes a fourth argument, make saber happy | |
| (define_expand "call_value" | |
| @@ -9632,65 +11342,10 @@ | |
| { | |
| rtx addr; | |
| - if (operands[0]) /* eliminate unused code warning */ | |
| - { | |
| - addr = XEXP (operands[1], 0); | |
| - if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS)) | |
| - || ! call_insn_operand (addr, VOIDmode)) | |
| - XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr); | |
| - | |
| - /* In order to pass small structures by value in registers | |
| - compatibly with the MIPS compiler, we need to shift the value | |
| - into the high part of the register. Function_arg has encoded | |
| - a PARALLEL rtx, holding a vector of adjustments to be made | |
| - as the next_arg_reg variable, so we split up the insns, | |
| - and emit them separately. */ | |
| - | |
| - if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL) | |
| - { | |
| - rtvec adjust = XVEC (operands[3], 0); | |
| - int num = GET_NUM_ELEM (adjust); | |
| - int i; | |
| - | |
| - for (i = 0; i < num; i++) | |
| - emit_insn (RTVEC_ELT (adjust, i)); | |
| - } | |
| - | |
| - if (TARGET_MIPS16 | |
| - && mips16_hard_float | |
| - && ((operands[3] != 0 | |
| - && (int) GET_MODE (operands[3]) != 0) | |
| - || GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT)) | |
| - { | |
| - if (build_mips16_call_stub (operands[0], operands[1], operands[2], | |
| - (operands[3] == 0 ? 0 | |
| - : (int) GET_MODE (operands[3])))) | |
| - DONE; | |
| - } | |
| - | |
| - /* Handle Irix6 function calls that have multiple non-contiguous | |
| - results. */ | |
| - if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1) | |
| - { | |
| - emit_call_insn (gen_call_value_multiple_internal0 | |
| - (XEXP (XVECEXP (operands[0], 0, 0), 0), | |
| - operands[1], operands[2], | |
| - XEXP (XVECEXP (operands[0], 0, 1), 0), | |
| - gen_rtx_REG (SImode, GP_REG_FIRST + 31))); | |
| - DONE; | |
| - } | |
| - | |
| - /* We have a call returning a DImode structure in an FP reg. | |
| - Strip off the now unnecessary PARALLEL. */ | |
| - if (GET_CODE (operands[0]) == PARALLEL) | |
| - operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0); | |
| - | |
| - emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], operands[2], | |
| - gen_rtx_REG (SImode, | |
| - GP_REG_FIRST + 31))); | |
| - | |
| + /* CYGNUS LOCAL sibcall/law */ | |
| + mips_expand_call_value (operands, 0); | |
| DONE; | |
| - } | |
| + /* END CYGNUS LOCAL */ | |
| }") | |
| (define_expand "call_value_internal0" | |
| @@ -9831,6 +11486,52 @@ | |
| (set_attr "mode" "none") | |
| (set_attr "length" "8")]) | |
| +;; CYGNUS LOCAL sibcall/law | |
| +(define_expand "sibcall_value" | |
| + [(parallel [(set (match_operand 0 "register_operand" "=df") | |
| + (call (match_operand 1 "memory_operand" "m") | |
| + (match_operand 2 "" "i"))) | |
| + (use (match_operand 3 "" "")) ;; next_arg_reg | |
| + (use (reg:SI 31))])] ;; need $ra to return | |
| + "" | |
| + " | |
| +{ | |
| + rtx addr; | |
| + | |
| + mips_expand_call_value (operands, 1); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_expand "sibcall_value_internal0" | |
| + [(parallel [(set (match_operand 0 "" "") | |
| + (call (match_operand 1 "" "") | |
| + (match_operand 2 "" ""))) | |
| + (use (reg:SI 31))])] ;; need $ra to return | |
| + "" | |
| + "") | |
| + | |
| +(define_insn "sibcall_value_internal1" | |
| + [(parallel [(set (match_operand 0 "register_operand" "=df") | |
| + (call (mem (match_operand 1 "call_insn_operand" "ri")) | |
| + (match_operand 2 "" "i"))) | |
| + (use (reg:SI 31))])] ;; need $ra to return | |
| + "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS" | |
| + "* | |
| +{ | |
| + register rtx target = operands[1]; | |
| + | |
| + if (GET_CODE (target) == SYMBOL_REF) | |
| + return \"%*j\\t%1\"; | |
| + else if (GET_CODE (target) == CONST_INT) | |
| + return \"%[li\\t%@,%1\\n\\t%*j\\t%@%]\"; | |
| + else | |
| + return \"%*j\\t%1\"; | |
| +}" | |
| + [(set_attr "type" "call") | |
| + (set_attr "mode" "none") | |
| + (set_attr "length" "4")]) | |
| +;; END CYGNUS LOCAL | |
| + | |
| (define_expand "call_value_multiple_internal0" | |
| [(parallel [(set (match_operand 0 "" "") | |
| (call (match_operand 1 "" "") | |
| @@ -9914,7 +11615,7 @@ | |
| { | |
| int i; | |
| - emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); | |
| + emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); | |
| for (i = 0; i < XVECLEN (operands[2], 0); i++) | |
| { | |
| @@ -9973,7 +11674,7 @@ | |
| "@ | |
| mov%B4\\t%0,%z2,%1 | |
| mov%b4\\t%0,%z3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "SI")]) | |
| (define_insn "" | |
| @@ -9988,7 +11689,7 @@ | |
| "@ | |
| mov%B4\\t%0,%z2,%1 | |
| mov%b4\\t%0,%z3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "SI")]) | |
| (define_insn "" | |
| @@ -10004,7 +11705,7 @@ | |
| "@ | |
| mov%T3\\t%0,%z1,%4 | |
| mov%t3\\t%0,%z2,%4" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "SI")]) | |
| (define_insn "" | |
| @@ -10019,7 +11720,7 @@ | |
| "@ | |
| mov%B4\\t%0,%z2,%1 | |
| mov%b4\\t%0,%z3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "DI")]) | |
| (define_insn "" | |
| @@ -10034,7 +11735,7 @@ | |
| "@ | |
| mov%B4\\t%0,%z2,%1 | |
| mov%b4\\t%0,%z3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "DI")]) | |
| (define_insn "" | |
| @@ -10050,7 +11751,7 @@ | |
| "@ | |
| mov%T3\\t%0,%z1,%4 | |
| mov%t3\\t%0,%z2,%4" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "DI")]) | |
| (define_insn "" | |
| @@ -10065,7 +11766,7 @@ | |
| "@ | |
| mov%B4.s\\t%0,%2,%1 | |
| mov%b4.s\\t%0,%3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "SF")]) | |
| (define_insn "" | |
| @@ -10080,7 +11781,7 @@ | |
| "@ | |
| mov%B4.s\\t%0,%2,%1 | |
| mov%b4.s\\t%0,%3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "SF")]) | |
| (define_insn "" | |
| @@ -10096,7 +11797,7 @@ | |
| "@ | |
| mov%T3.s\\t%0,%1,%4 | |
| mov%t3.s\\t%0,%2,%4" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "SF")]) | |
| (define_insn "" | |
| @@ -10111,7 +11812,7 @@ | |
| "@ | |
| mov%B4.d\\t%0,%2,%1 | |
| mov%b4.d\\t%0,%3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "DF")]) | |
| (define_insn "" | |
| @@ -10126,7 +11827,7 @@ | |
| "@ | |
| mov%B4.d\\t%0,%2,%1 | |
| mov%b4.d\\t%0,%3,%1" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "DF")]) | |
| (define_insn "" | |
| @@ -10142,7 +11843,7 @@ | |
| "@ | |
| mov%T3.d\\t%0,%1,%4 | |
| mov%t3.d\\t%0,%2,%4" | |
| - [(set_attr "type" "move") | |
| + [(set_attr "type" "cmove") | |
| (set_attr "mode" "DF")]) | |
| ;; These are the main define_expand's used to make conditional moves. | |
| @@ -10156,6 +11857,10 @@ | |
| "ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE" | |
| " | |
| { | |
| + if (TARGET_MIPS5900 | |
| + && GET_MODE_CLASS (GET_MODE (branch_cmp[0])) == MODE_FLOAT) | |
| + FAIL; | |
| + | |
| gen_conditional_move (operands); | |
| DONE; | |
| }") | |
| @@ -10169,6 +11874,11 @@ | |
| "ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE" | |
| " | |
| { | |
| + if (TARGET_MIPS5900 | |
| + && GET_MODE_CLASS (GET_MODE (branch_cmp[0])) == MODE_FLOAT) | |
| + FAIL; | |
| + | |
| + | |
| gen_conditional_move (operands); | |
| DONE; | |
| }") | |
| @@ -10455,3 +12165,1371 @@ | |
| [(set_attr "type" "arith") | |
| (set_attr "mode" "DI") | |
| (set_attr "length" "40")]) | |
| + | |
| +(define_insn "mips5900_pabsh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 40))] | |
| + "TARGET_SIMD" | |
| + "pabsh\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pabsw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 41))] | |
| + "TARGET_SIMD" | |
| + "pabsw\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 42))] | |
| + "TARGET_SIMD" | |
| + "paddb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 43))] | |
| + "TARGET_SIMD" | |
| + "paddh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddsb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 44))] | |
| + "TARGET_SIMD" | |
| + "paddsb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddsh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 45))] | |
| + "TARGET_SIMD" | |
| + "paddsh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddsw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 46))] | |
| + "TARGET_SIMD" | |
| + "paddsw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddub" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 47))] | |
| + "TARGET_SIMD" | |
| + "paddub\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_padduh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 48))] | |
| + "TARGET_SIMD" | |
| + "padduh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_padduw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 49))] | |
| + "TARGET_SIMD" | |
| + "padduw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_paddw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 50))] | |
| + "TARGET_SIMD" | |
| + "paddw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_padsbh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 51))] | |
| + "TARGET_SIMD" | |
| + "padsbh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pand" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 52))] | |
| + "TARGET_SIMD" | |
| + "pand\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pceqb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 53))] | |
| + "TARGET_SIMD" | |
| + "pceqb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pceqh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 54))] | |
| + "TARGET_SIMD" | |
| + "pceqh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pceqw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 55))] | |
| + "TARGET_SIMD" | |
| + "pceqw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pcgtb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 56))] | |
| + "TARGET_SIMD" | |
| + "pcgtb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pcgth" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 57))] | |
| + "TARGET_SIMD" | |
| + "pcgth\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pcgtw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 58))] | |
| + "TARGET_SIMD" | |
| + "pcgtw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pcpyh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 59))] | |
| + "TARGET_SIMD" | |
| + "pcpyh\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pcpyld" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 60))] | |
| + "TARGET_SIMD" | |
| + "pcpyld\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pcpyud" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 61))] | |
| + "TARGET_SIMD" | |
| + "pcpyud\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pdivbw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=a") | |
| + (unspec [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 62))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pdivbw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pdivbw_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=a") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 62)) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=l")) | |
| + (clobber (match_operand:V4SI 4 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pdivbw\\t%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pexch" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 63))] | |
| + "TARGET_SIMD" | |
| + "pexch\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pexcw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 64))] | |
| + "TARGET_SIMD" | |
| + "pexcw\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pexeh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 65))] | |
| + "TARGET_SIMD" | |
| + "pexeh\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pexew" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 66))] | |
| + "TARGET_SIMD" | |
| + "pexew\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pext5" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")] 67))] | |
| + "TARGET_SIMD" | |
| + "pext5\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pextlb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 68))] | |
| + "TARGET_SIMD" | |
| + "pextlb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pextlh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 69))] | |
| + "TARGET_SIMD" | |
| + "pextlh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pextlw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 70))] | |
| + "TARGET_SIMD" | |
| + "pextlw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pextub" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 71))] | |
| + "TARGET_SIMD" | |
| + "pextub\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pextuh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 72))] | |
| + "TARGET_SIMD" | |
| + "pextuh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pextuw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 73))] | |
| + "TARGET_SIMD" | |
| + "pextuw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pinth" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 74))] | |
| + "TARGET_SIMD" | |
| + "pinth\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pinteh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 75))] | |
| + "TARGET_SIMD" | |
| + "pinteh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_plzcw" | |
| + [(set (match_operand:V2SI 0 "register_operand" "=d") | |
| + (unspec:V2SI [(match_operand:V2SI 1 "register_operand" "d")] 76))] | |
| + "TARGET_SIMD" | |
| + "plzcw\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmaxh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 77))] | |
| + "TARGET_SIMD" | |
| + "pmaxh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmaxw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 78))] | |
| + "TARGET_SIMD" | |
| + "pmaxw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pminh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 79))] | |
| + "TARGET_SIMD" | |
| + "pminh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pminw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 80))] | |
| + "TARGET_SIMD" | |
| + "pminw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pnor" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 81))] | |
| + "TARGET_SIMD" | |
| + "pnor\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_por" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 82))] | |
| + "TARGET_SIMD" | |
| + "por\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_ppac5" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V4SI 1 "register_operand" "d")] 83))] | |
| + "TARGET_SIMD" | |
| + "ppac5\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_ppacb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 84))] | |
| + "TARGET_SIMD" | |
| + "ppacb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_ppach" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 85))] | |
| + "TARGET_SIMD" | |
| + "ppach\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_ppacw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 86))] | |
| + "TARGET_SIMD" | |
| + "ppacw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_prevh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 87))] | |
| + "TARGET_SIMD" | |
| + "prevh\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_prot3w" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 88))] | |
| + "TARGET_SIMD" | |
| + "prot3w\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_psllh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_or_int_operand" "")] 89))] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[2]); | |
| + x &= 0xf; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[2] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_psllh_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_psllh_internal" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "const_int_operand" "")] 89))] | |
| + "TARGET_SIMD" | |
| + "psllh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psllvw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 90))] | |
| + "TARGET_SIMD" | |
| + "psllvw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_psllw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_or_int_operand" "")] 91))] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[2]); | |
| + x &= 0x1f; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[2] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_psllw_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_psllw_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "const_int_operand" "")] 91))] | |
| + "TARGET_SIMD" | |
| + "psllw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_psrah" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_or_int_operand" "")] 92))] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[2]); | |
| + x &= 0xf; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[2] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_psrah_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_psrah_internal" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "const_int_operand" "")] 92))] | |
| + "TARGET_SIMD" | |
| + "psrah\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psravw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 93))] | |
| + "TARGET_SIMD" | |
| + "psravw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_psraw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_or_int_operand" "")] 94))] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[2]); | |
| + x &= 0x1f; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[2] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_psraw_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_psraw_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "const_int_operand" "")] 94))] | |
| + "TARGET_SIMD" | |
| + "psraw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_psrlh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_or_int_operand" "")] 95))] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[2]); | |
| + x &= 0xf; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[2] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_psrlh_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_psrlh_internal" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "const_int_operand" "")] 95))] | |
| + "TARGET_SIMD" | |
| + "psrlh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psrlvw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 96))] | |
| + "TARGET_SIMD" | |
| + "psrlvw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_psrlw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "register_or_int_operand" "")] 97))] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[2]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[2]); | |
| + x &= 0x1f; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[2] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_psrlw_internal (operands[0], operands[1], operands[2])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_psrlw_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:SI 2 "const_int_operand" "")] 97))] | |
| + "TARGET_SIMD" | |
| + "psrlw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 98))] | |
| + "TARGET_SIMD" | |
| + "psubb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 99))] | |
| + "TARGET_SIMD" | |
| + "psubh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubsb" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 100))] | |
| + "TARGET_SIMD" | |
| + "psubsb\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubsh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 101))] | |
| + "TARGET_SIMD" | |
| + "psubsh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubsw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 102))] | |
| + "TARGET_SIMD" | |
| + "psubsw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubub" | |
| + [(set (match_operand:V16QI 0 "register_operand" "=d") | |
| + (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d") | |
| + (match_operand:V16QI 2 "register_operand" "d")] 103))] | |
| + "TARGET_SIMD" | |
| + "psubub\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V16QI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubuh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 104))] | |
| + "TARGET_SIMD" | |
| + "psubuh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubuw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 105))] | |
| + "TARGET_SIMD" | |
| + "psubuw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_psubw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 106))] | |
| + "TARGET_SIMD" | |
| + "psubw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pxor" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 107))] | |
| + "TARGET_SIMD" | |
| + "pxor\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_mtsa" | |
| + [(unspec_volatile [(match_operand:DI 0 "register_operand" "d")] 108)] | |
| + "TARGET_SIMD" | |
| + "mtsa\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "none") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_mfsa" | |
| + [(set (match_operand:DI 0 "register_operand" "=d") | |
| + (unspec:DI [(const_int 0)] 109))] | |
| + "TARGET_SIMD" | |
| + "mfsa\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_mtsab" | |
| + [(unspec_volatile [(match_operand:SI 0 "register_operand" "d") | |
| + (match_operand:SI 1 "register_or_int_operand" "")] 109)] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[1]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[1]); | |
| + x &= 0xffff; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[1] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_mtsab_internal (operands[0], operands[1])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_mtsab_internal" | |
| + [(unspec_volatile [(match_operand:SI 0 "register_operand" "d") | |
| + (match_operand:SI 1 "const_int_operand" "")] 109)] | |
| + "TARGET_SIMD" | |
| + "mtsab\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "none") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_mtsah" | |
| + [(unspec_volatile [(match_operand:SI 0 "register_operand" "d") | |
| + (match_operand:SI 1 "register_or_int_operand" "")] 110)] | |
| + "" | |
| + " | |
| +{ | |
| + int x; | |
| + if (GET_CODE (operands[1]) == CONST_INT) | |
| + { | |
| + x = INTVAL (operands[1]); | |
| + x &= 0xffff; | |
| + } | |
| + else | |
| + x = 0; /* nop if operand is not const int */ | |
| + operands[1] = GEN_INT (x); | |
| + emit_insn (gen_mips5900_mtsah_internal (operands[0], operands[1])); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_mtsah_internal" | |
| + [(unspec_volatile [(match_operand:SI 0 "register_operand" "d") | |
| + (match_operand:SI 1 "const_int_operand" "")] 110)] | |
| + "TARGET_SIMD" | |
| + "mtsah\\t%0,%1" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "none") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_qfsrv" | |
| + [(set (match_operand:TI 0 "register_operand" "=d") | |
| + (unspec:TI [(match_operand:TI 1 "register_operand" "d") | |
| + (match_operand:TI 2 "register_operand" "d")] 111))] | |
| + "TARGET_SIMD" | |
| + "qfsrv\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "TI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmfhi" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(const_int 0)] 112)) | |
| +; (use (reg:V2DI 64)) ; HI register | |
| +; (use (reg:V2DI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmfhi\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmflo" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(const_int 0)] 113)) | |
| +; (use (reg:V2DI 65)) ; LO register | |
| +; (use (reg:V2DI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmflo\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmfhl_lw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(const_int 0)] 114)) | |
| +; (use (reg:V4SI 65)) ; LO register | |
| +; (use (reg:V4SI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmfhl.lw\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmfhl_uw" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(const_int 0)] 115)) | |
| +; (use (reg:V4SI 65)) ; LO register | |
| +; (use (reg:V4SI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmfhl.uw\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmfhl_slw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(const_int 0)] 116)) | |
| +; (use (reg:V2DI 65)) ; LO register | |
| +; (use (reg:V2DI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmfhl.slw\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmfhl_lh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(const_int 0)] 117)) | |
| +; (use (reg:V8HI 65)) ; LO register | |
| +; (use (reg:V8HI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmfhl.lh\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_insn "mips5900_pmfhl_sh" | |
| + [(set (match_operand:V8HI 0 "register_operand" "=d") | |
| + (unspec:V8HI [(const_int 0)] 118)) | |
| +; (use (reg:V8HI 65)) ; LO register | |
| +; (use (reg:V8HI 66)) ; HILO register | |
| + ] | |
| + "TARGET_SIMD" | |
| + "pmfhl.sh\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V8HI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pdivuw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=a") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 119))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pdivuw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pdivuw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=a") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 119)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pdivuw\\t%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pdivw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=a") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 120))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pdivw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pdivw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=a") | |
| + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d") | |
| + (match_operand:V2DI 2 "register_operand" "d")] 120)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pdivw\\t%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_phmadh" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 121))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_phmadh_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_phmadh_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 121)) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V4SI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V4SI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "phmadh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_phmsbh" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 122))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_phmsbh_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_phmsbh_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 122)) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V4SI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V4SI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "phmsbh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmaddh" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 123))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmaddh_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmaddh_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 123)) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V4SI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V4SI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmaddh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmadduw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 124))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmadduw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmadduw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 124)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmadduw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmaddw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 125))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmaddw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmaddw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 125)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmaddw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmsubh" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 126))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmsubh_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmsubh_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 126)) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V4SI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V4SI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmsubh\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmsubw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 127))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmsubw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmsubw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 127)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmsubw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmthi" | |
| + [(unspec [(match_operand:V2DI 0 "register_operand" "d")] 128)] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmthi_internal (operands[0], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmthi_internal" | |
| + [(unspec:V2DI [(match_operand:V2DI 0 "register_operand" "d")] 128) | |
| + (clobber (match_operand:V2DI 1 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 2 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmthi\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmtlo" | |
| + [(unspec [(match_operand:V2DI 0 "register_operand" "d")] 129)] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmtlo_internal (operands[0], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmtlo_internal" | |
| + [(unspec:V2DI [(match_operand:V2DI 0 "register_operand" "d")] 129) | |
| + (clobber (match_operand:V2DI 1 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 2 "register_operand" "=l"))] | |
| + "TARGET_SIMD" | |
| + "pmtlo\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmthl_lw" | |
| + [(unspec [(match_operand:V4SI 0 "register_operand" "d")] 130)] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmthl_lw_internal (operands[0], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmthl_lw_internal" | |
| + [(unspec:V4SI [(match_operand:V4SI 0 "register_operand" "d")] 130) | |
| + (clobber (match_operand:V4SI 1 "register_operand" "=a")) | |
| + (clobber (match_operand:V4SI 2 "register_operand" "=h")) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=l"))] | |
| + "TARGET_SIMD" | |
| + "pmthl.lw\\t%0" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmulth" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 131))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmulth_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode), | |
| + gen_reg_rtx (V4SImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmulth_internal" | |
| + [(set (match_operand:V4SI 0 "register_operand" "=d") | |
| + (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d") | |
| + (match_operand:V8HI 2 "register_operand" "d")] 131)) | |
| + (clobber (match_operand:V4SI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V4SI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V4SI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmulth\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V4SI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmultuw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 132))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmultuw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmultuw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 132)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmultuw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) | |
| + | |
| +(define_expand "mips5900_pmultw" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 133))] | |
| + "TARGET_SIMD" | |
| + " | |
| +{ | |
| + emit_insn (gen_mips5900_pmultw_internal (operands[0], operands[1], | |
| + operands[2], | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode), | |
| + gen_reg_rtx (V2DImode))); | |
| + DONE; | |
| +}") | |
| + | |
| +(define_insn "mips5900_pmultw_internal" | |
| + [(set (match_operand:V2DI 0 "register_operand" "=d") | |
| + (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d") | |
| + (match_operand:V4SI 2 "register_operand" "d")] 133)) | |
| + (clobber (match_operand:V2DI 3 "register_operand" "=a")) | |
| + (clobber (match_operand:V2DI 4 "register_operand" "=l")) | |
| + (clobber (match_operand:V2DI 5 "register_operand" "=h"))] | |
| + "TARGET_SIMD" | |
| + "pmultw\\t%0,%1,%2" | |
| + [(set_attr "type" "simd") | |
| + (set_attr "mode" "V2DI") | |
| + (set_attr "length" "1")]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment