diff options
author | obrien <obrien@FreeBSD.org> | 2002-05-09 20:02:13 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-05-09 20:02:13 +0000 |
commit | c8f5fc7032940ad6633f932ac40cade82ec4d0cc (patch) | |
tree | 29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/config/sparc/sparc.c | |
parent | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (diff) | |
download | FreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.zip FreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.tar.gz |
Gcc 3.1.0 pre-release from the FSF anoncvs repo on 9-May-2002 15:57:15 EDT.
Diffstat (limited to 'contrib/gcc/config/sparc/sparc.c')
-rw-r--r-- | contrib/gcc/config/sparc/sparc.c | 1436 |
1 files changed, 959 insertions, 477 deletions
diff --git a/contrib/gcc/config/sparc/sparc.c b/contrib/gcc/config/sparc/sparc.c index 8cc4449..28bbcec 100644 --- a/contrib/gcc/config/sparc/sparc.c +++ b/contrib/gcc/config/sparc/sparc.c @@ -68,26 +68,24 @@ Boston, MA 02111-1307, USA. */ static int apparent_fsize; static int actual_fsize; -/* Number of live general or floating point registers needed to be saved - (as 4-byte quantities). This is only done if TARGET_EPILOGUE. */ +/* Number of live general or floating point registers needed to be + saved (as 4-byte quantities). */ static int num_gfregs; /* Save the operands last given to a compare for use when we generate a scc or bcc insn. */ - rtx sparc_compare_op0, sparc_compare_op1; -/* We may need an epilogue if we spill too many registers. - If this is non-zero, then we branch here for the epilogue. */ -static rtx leaf_label; +/* Coordinate with the md file wrt special insns created by + sparc_nonflat_function_epilogue. */ +bool sparc_emitting_epilogue; #ifdef LEAF_REGISTERS -/* Vector to say how input registers are mapped to output - registers. FRAME_POINTER_REGNUM cannot be remapped by - this function to eliminate it. You must use -fomit-frame-pointer - to get that. */ -const char leaf_reg_remap[] = +/* Vector to say how input registers are mapped to output registers. + HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to + eliminate it. You must use -fomit-frame-pointer to get that. */ +char leaf_reg_remap[] = { 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -180,6 +178,12 @@ static int sparc_issue_rate PARAMS ((void)); static int sparc_variable_issue PARAMS ((FILE *, int, rtx, int)); static void sparc_sched_init PARAMS ((FILE *, int, int)); static int sparc_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int)); + +static void emit_soft_tfmode_libcall PARAMS ((const char *, int, rtx *)); +static void emit_soft_tfmode_binop PARAMS ((enum rtx_code, rtx *)); +static void emit_soft_tfmode_unop PARAMS ((enum rtx_code, rtx *)); +static void emit_soft_tfmode_cvt PARAMS ((enum rtx_code, rtx *)); +static void emit_hard_tfmode_operation PARAMS ((enum rtx_code, rtx *)); /* Option handling. */ @@ -433,12 +437,6 @@ sparc_override_options () /* Do various machine dependent initializations. */ sparc_init_modes (); - if ((profile_flag) - && sparc_cmodel != CM_32 && sparc_cmodel != CM_MEDLOW) - { - error ("profiling does not support code models other than medlow"); - } - /* Register global variables with the garbage collector. */ sparc_add_gc_roots (); } @@ -492,6 +490,20 @@ fp_zero_operand (op, mode) return op == CONST0_RTX (mode); } +/* Nonzero if OP is a register operand in floating point register. */ + +int +fp_register_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (! register_operand (op, mode)) + return 0; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op)); +} + /* Nonzero if OP is a floating point constant which can be loaded into an integer register using a single sethi instruction. */ @@ -609,6 +621,27 @@ fcc_reg_operand (op, mode) #endif } +/* Nonzero if OP is a floating point condition code fcc0 register. */ + +int +fcc0_reg_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + /* This can happen when recog is called from combine. Op may be a MEM. + Fail instead of calling abort in this case. */ + if (GET_CODE (op) != REG) + return 0; + + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + if (mode == VOIDmode + && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode)) + return 0; + + return REGNO (op) == SPARC_FCC_REG; +} + /* Nonzero if OP is an integer or floating point condition code register. */ int @@ -879,12 +912,35 @@ noov_compare_op (op, mode) if (GET_RTX_CLASS (code) != '<') return 0; - if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode) + if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode + || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode) /* These are the only branches which work with CC_NOOVmode. */ return (code == EQ || code == NE || code == GE || code == LT); return 1; } +/* Return 1 if this is a 64-bit comparison operator. This allows the use of + MATCH_OPERATOR to recognize all the branch insns. */ + +int +noov_compare64_op (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + enum rtx_code code = GET_CODE (op); + + if (! TARGET_V9) + return 0; + + if (GET_RTX_CLASS (code) != '<') + return 0; + + if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode) + /* These are the only branches which work with CCX_NOOVmode. */ + return (code == EQ || code == NE || code == GE || code == LT); + return (GET_MODE (XEXP (op, 0)) == CCXmode); +} + /* Nonzero if OP is a comparison operator suitable for use in v9 conditional move or branch on register contents instructions. */ @@ -951,13 +1007,11 @@ arith_operand (op, mode) rtx op; enum machine_mode mode; { - int val; if (register_operand (op, mode)) return 1; if (GET_CODE (op) != CONST_INT) return 0; - val = INTVAL (op) & 0xffffffff; - return SPARC_SIMM13_P (val); + return SMALL_INT32 (op); } /* Return true if OP is a constant 4096 */ @@ -967,11 +1021,10 @@ arith_4096_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED; { - int val; if (GET_CODE (op) != CONST_INT) return 0; - val = INTVAL (op) & 0xffffffff; - return val == 4096; + else + return INTVAL (op) == 4096; } /* Return true if OP is suitable as second operand for add/sub */ @@ -999,7 +1052,7 @@ const64_operand (op, mode) && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)) && (CONST_DOUBLE_HIGH (op) == ((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ? - (HOST_WIDE_INT)0xffffffff : 0))) + (HOST_WIDE_INT)-1 : 0))) #endif ); } @@ -1008,21 +1061,15 @@ const64_operand (op, mode) int const64_high_operand (op, mode) rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; + enum machine_mode mode; { return ((GET_CODE (op) == CONST_INT - && (INTVAL (op) & 0xfffffc00) != 0 - && SPARC_SETHI_P (INTVAL (op)) -#if HOST_BITS_PER_WIDE_INT != 64 - /* Must be positive on non-64bit host else the - optimizer is fooled into thinking that sethi - sign extends, even though it does not. */ - && INTVAL (op) >= 0 -#endif + && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0 + && SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode)) ) || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 - && (CONST_DOUBLE_LOW (op) & 0xfffffc00) != 0 + && (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0 && SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))); } @@ -1231,12 +1278,7 @@ input_operand (op, mode) variants when we are working in DImode and !arch64. */ if (GET_MODE_CLASS (mode) == MODE_INT && ((GET_CODE (op) == CONST_INT - && ((SPARC_SETHI_P (INTVAL (op)) - && (! TARGET_ARCH64 - || (INTVAL (op) >= 0) - || mode == SImode - || mode == HImode - || mode == QImode)) + && (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode)) || SPARC_SIMM13_P (INTVAL (op)) || (mode == DImode && ! TARGET_ARCH64))) @@ -1315,7 +1357,7 @@ sparc_emit_set_const32 (op0, op1) { HOST_WIDE_INT value = INTVAL (op1); - if (SPARC_SETHI_P (value) + if (SPARC_SETHI_P (value & GET_MODE_MASK (mode)) || SPARC_SIMM13_P (value)) abort (); } @@ -1336,11 +1378,13 @@ sparc_emit_set_const32 (op0, op1) && (INTVAL (op1) & 0x80000000) != 0) emit_insn (gen_rtx_SET (VOIDmode, temp, - gen_rtx_CONST_DOUBLE (VOIDmode, INTVAL (op1) & 0xfffffc00, + gen_rtx_CONST_DOUBLE (VOIDmode, + INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff, 0))); else emit_insn (gen_rtx_SET (VOIDmode, temp, - GEN_INT (INTVAL (op1) & 0xfffffc00))); + GEN_INT (INTVAL (op1) + & ~(HOST_WIDE_INT)0x3ff))); emit_insn (gen_rtx_SET (VOIDmode, op0, @@ -1366,6 +1410,14 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1) rtx op1; rtx temp1; { + rtx ti_temp1 = 0; + + if (temp1 && GET_MODE (temp1) == TImode) + { + ti_temp1 = temp1; + temp1 = gen_rtx_REG (DImode, REGNO (temp1)); + } + switch (sparc_cmodel) { case CM_MEDLOW: @@ -1419,12 +1471,16 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1) sllx %temp3, 32, %temp5 or %temp4, %temp5, %reg */ - /* Getting this right wrt. reloading is really tricky. - We _MUST_ have a separate temporary at this point, - if we don't barf immediately instead of generating - incorrect code. */ + /* It is possible that one of the registers we got for operands[2] + might coincide with that of operands[0] (which is why we made + it TImode). Pick the other one to use as our scratch. */ if (rtx_equal_p (temp1, op0)) - abort (); + { + if (ti_temp1) + temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1); + else + abort(); + } emit_insn (gen_sethh (op0, op1)); emit_insn (gen_setlm (temp1, op1)); @@ -1462,12 +1518,16 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1) } else { - /* Getting this right wrt. reloading is really tricky. - We _MUST_ have a separate temporary at this point, - so we barf immediately instead of generating - incorrect code. */ - if (temp1 == op0) - abort (); + /* It is possible that one of the registers we got for operands[2] + might coincide with that of operands[0] (which is why we made + it TImode). Pick the other one to use as our scratch. */ + if (rtx_equal_p (temp1, op0)) + { + if (ti_temp1) + temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1); + else + abort(); + } emit_insn (gen_embmedany_textuhi (op0, op1)); emit_insn (gen_embmedany_texthi (temp1, op1)); @@ -1494,15 +1554,15 @@ static rtx gen_safe_OR64 PARAMS ((rtx, HOST_WIDE_INT)); static rtx gen_safe_XOR64 PARAMS ((rtx, HOST_WIDE_INT)); #if HOST_BITS_PER_WIDE_INT == 64 -#define GEN_HIGHINT64(__x) GEN_INT ((__x) & 0xfffffc00) +#define GEN_HIGHINT64(__x) GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff) #define GEN_INT64(__x) GEN_INT (__x) #else #define GEN_HIGHINT64(__x) \ - gen_rtx_CONST_DOUBLE (VOIDmode, (__x) & 0xfffffc00, 0) + gen_rtx_CONST_DOUBLE (VOIDmode, (__x) & ~(HOST_WIDE_INT)0x3ff, 0) #define GEN_INT64(__x) \ gen_rtx_CONST_DOUBLE (VOIDmode, (__x) & 0xffffffff, \ ((__x) & 0x80000000 \ - ? 0xffffffff : 0)) + ? -1 : 0)) #endif /* The optimizer is not to assume anything about exactly @@ -1587,7 +1647,8 @@ sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg) { emit_insn (gen_rtx_SET (VOIDmode, op0, gen_safe_XOR64 (temp, - (-0x400 | (low_bits & 0x3ff))))); + (-(HOST_WIDE_INT)0x400 + | (low_bits & 0x3ff))))); } } } @@ -2295,16 +2356,7 @@ gen_v9_scc (compare_code, operands) || GET_MODE (operands[0]) == DImode)) return 0; - /* Handle the case where operands[0] == sparc_compare_op0. - We "early clobber" the result. */ - if (REGNO (operands[0]) == REGNO (sparc_compare_op0)) - { - op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0)); - emit_move_insn (op0, sparc_compare_op0); - } - else - op0 = sparc_compare_op0; - /* For consistency in the following. */ + op0 = sparc_compare_op0; op1 = sparc_compare_op1; /* Try to use the movrCC insns. */ @@ -2314,14 +2366,12 @@ gen_v9_scc (compare_code, operands) && v9_regcmp_p (compare_code)) { /* Special case for op0 != 0. This can be done with one instruction if - operands[0] == sparc_compare_op0. We don't assume they are equal - now though. */ + operands[0] == sparc_compare_op0. */ if (compare_code == NE && GET_MODE (operands[0]) == DImode - && GET_MODE (op0) == DImode) + && rtx_equal_p (op0, operands[0])) { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], op0)); emit_insn (gen_rtx_SET (VOIDmode, operands[0], gen_rtx_IF_THEN_ELSE (DImode, gen_rtx_fmt_ee (compare_code, DImode, @@ -2331,6 +2381,14 @@ gen_v9_scc (compare_code, operands) return 1; } + if (reg_overlap_mentioned_p (operands[0], op0)) + { + /* Handle the case where operands[0] == sparc_compare_op0. + We "early clobber" the result. */ + op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0)); + emit_move_insn (op0, sparc_compare_op0); + } + emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); if (GET_MODE (op0) != DImode) { @@ -2406,6 +2464,304 @@ gen_df_reg (reg, low) return gen_rtx_REG (DFmode, regno); } +/* Generate a call to FUNC with OPERANDS. Operand 0 is the return value. + Unlike normal calls, TFmode operands are passed by reference. It is + assumed that no more than 3 operands are required. */ + +static void +emit_soft_tfmode_libcall (func_name, nargs, operands) + const char *func_name; + int nargs; + rtx *operands; +{ + rtx ret_slot = NULL, arg[3], func_sym; + int i; + + /* We only expect to be called for conversions, unary, and binary ops. */ + if (nargs < 2 || nargs > 3) + abort (); + + for (i = 0; i < nargs; ++i) + { + rtx this_arg = operands[i]; + rtx this_slot; + + /* TFmode arguments and return values are passed by reference. */ + if (GET_MODE (this_arg) == TFmode) + { + if (GET_CODE (this_arg) == MEM) + this_arg = XEXP (this_arg, 0); + else if (CONSTANT_P (this_arg)) + { + this_slot = force_const_mem (TFmode, this_arg); + this_arg = XEXP (this_slot, 0); + } + else + { + this_slot = assign_stack_temp (TFmode, GET_MODE_SIZE (TFmode), 0); + + /* Operand 0 is the return value. We'll copy it out later. */ + if (i > 0) + emit_move_insn (this_slot, this_arg); + else + ret_slot = this_slot; + + this_arg = XEXP (this_slot, 0); + } + } + + arg[i] = this_arg; + } + + func_sym = gen_rtx_SYMBOL_REF (Pmode, func_name); + + if (GET_MODE (operands[0]) == TFmode) + { + if (nargs == 2) + emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 2, + arg[0], GET_MODE (arg[0]), + arg[1], GET_MODE (arg[1])); + else + emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 3, + arg[0], GET_MODE (arg[0]), + arg[1], GET_MODE (arg[1]), + arg[2], GET_MODE (arg[2])); + + if (ret_slot) + emit_move_insn (operands[0], ret_slot); + } + else + { + rtx ret; + + if (nargs != 2) + abort (); + + ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL, + GET_MODE (operands[0]), 1, + arg[1], GET_MODE (arg[1])); + + if (ret != operands[0]) + emit_move_insn (operands[0], ret); + } +} + +/* Expand soft-float TFmode calls to sparc abi routines. */ + +static void +emit_soft_tfmode_binop (code, operands) + enum rtx_code code; + rtx *operands; +{ + const char *func; + + switch (code) + { + case PLUS: + func = "_Qp_add"; + break; + case MINUS: + func = "_Qp_sub"; + break; + case MULT: + func = "_Qp_mul"; + break; + case DIV: + func = "_Qp_div"; + break; + default: + abort (); + } + + emit_soft_tfmode_libcall (func, 3, operands); +} + +static void +emit_soft_tfmode_unop (code, operands) + enum rtx_code code; + rtx *operands; +{ + const char *func; + + switch (code) + { + case SQRT: + func = "_Qp_sqrt"; + break; + default: + abort (); + } + + emit_soft_tfmode_libcall (func, 2, operands); +} + +static void +emit_soft_tfmode_cvt (code, operands) + enum rtx_code code; + rtx *operands; +{ + const char *func; + + switch (code) + { + case FLOAT_EXTEND: + switch (GET_MODE (operands[1])) + { + case SFmode: + func = "_Qp_stoq"; + break; + case DFmode: + func = "_Qp_dtoq"; + break; + default: + abort (); + } + break; + + case FLOAT_TRUNCATE: + switch (GET_MODE (operands[0])) + { + case SFmode: + func = "_Qp_qtos"; + break; + case DFmode: + func = "_Qp_qtod"; + break; + default: + abort (); + } + break; + + case FLOAT: + switch (GET_MODE (operands[1])) + { + case SImode: + func = "_Qp_itoq"; + break; + case DImode: + func = "_Qp_xtoq"; + break; + default: + abort (); + } + break; + + case UNSIGNED_FLOAT: + switch (GET_MODE (operands[1])) + { + case SImode: + func = "_Qp_uitoq"; + break; + case DImode: + func = "_Qp_uxtoq"; + break; + default: + abort (); + } + break; + + case FIX: + switch (GET_MODE (operands[0])) + { + case SImode: + func = "_Qp_qtoi"; + break; + case DImode: + func = "_Qp_qtox"; + break; + default: + abort (); + } + break; + + case UNSIGNED_FIX: + switch (GET_MODE (operands[0])) + { + case SImode: + func = "_Qp_qtoui"; + break; + case DImode: + func = "_Qp_qtoux"; + break; + default: + abort (); + } + break; + + default: + abort (); + } + + emit_soft_tfmode_libcall (func, 2, operands); +} + +/* Expand a hard-float tfmode operation. All arguments must be in + registers. */ + +static void +emit_hard_tfmode_operation (code, operands) + enum rtx_code code; + rtx *operands; +{ + rtx op, dest; + + if (GET_RTX_CLASS (code) == '1') + { + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]); + } + else + { + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + op = gen_rtx_fmt_ee (code, GET_MODE (operands[0]), + operands[1], operands[2]); + } + + if (register_operand (operands[0], VOIDmode)) + dest = operands[0]; + else + dest = gen_reg_rtx (GET_MODE (operands[0])); + + emit_insn (gen_rtx_SET (VOIDmode, dest, op)); + + if (dest != operands[0]) + emit_move_insn (operands[0], dest); +} + +void +emit_tfmode_binop (code, operands) + enum rtx_code code; + rtx *operands; +{ + if (TARGET_HARD_QUAD) + emit_hard_tfmode_operation (code, operands); + else + emit_soft_tfmode_binop (code, operands); +} + +void +emit_tfmode_unop (code, operands) + enum rtx_code code; + rtx *operands; +{ + if (TARGET_HARD_QUAD) + emit_hard_tfmode_operation (code, operands); + else + emit_soft_tfmode_unop (code, operands); +} + +void +emit_tfmode_cvt (code, operands) + enum rtx_code code; + rtx *operands; +{ + if (TARGET_HARD_QUAD) + emit_hard_tfmode_operation (code, operands); + else + emit_soft_tfmode_cvt (code, operands); +} + /* Return nonzero if a return peephole merging return with setting of output register is ok. */ int @@ -2414,6 +2770,26 @@ leaf_return_peephole_ok () return (actual_fsize == 0); } +/* Return nonzero if a branch/jump/call instruction will be emitting + nop into its delay slot. */ + +int +empty_delay_slot (insn) + rtx insn; +{ + rtx seq; + + /* If no previous instruction (should not happen), return true. */ + if (PREV_INSN (insn) == NULL) + return 1; + + seq = NEXT_INSN (PREV_INSN (insn)); + if (GET_CODE (PATTERN (seq)) == SEQUENCE) + return 0; + + return 1; +} + /* Return nonzero if TRIAL can go into the function epilogue's delay slot. SLOT is the slot we are trying to fill. */ @@ -2931,7 +3307,7 @@ load_pic_register () } /* Return 1 if RTX is a MEM which is known to be aligned to at - least an 8 byte boundary. */ + least a DESIRED byte boundary. */ int mem_min_alignment (mem, desired) @@ -2972,8 +3348,7 @@ mem_min_alignment (mem, desired) { int regno = REGNO (base); - if (regno != FRAME_POINTER_REGNUM - && regno != STACK_POINTER_REGNUM) + if (regno != HARD_FRAME_POINTER_REGNUM && regno != STACK_POINTER_REGNUM) { /* Check if the compiler has recorded some information about the alignment of the base REG. If reload has @@ -3190,7 +3565,7 @@ sparc_init_modes () { if (i < 16 && TARGET_V8PLUS) sparc_regno_reg_class[i] = I64_REGS; - else if (i < 32) + else if (i < 32 || i == FRAME_POINTER_REGNUM) sparc_regno_reg_class[i] = GENERAL_REGS; else if (i < 64) sparc_regno_reg_class[i] = FP_REGS; @@ -3334,31 +3709,28 @@ compute_frame_size (size, leaf_function) int outgoing_args_size = (current_function_outgoing_args_size + REG_PARM_STACK_SPACE (current_function_decl)); - if (TARGET_EPILOGUE) - { - /* N_REGS is the number of 4-byte regs saved thus far. This applies - even to v9 int regs to be consistent with save_regs/restore_regs. */ + /* N_REGS is the number of 4-byte regs saved thus far. This applies + even to v9 int regs to be consistent with save_regs/restore_regs. */ - if (TARGET_ARCH64) - { - for (i = 0; i < 8; i++) - if (regs_ever_live[i] && ! call_used_regs[i]) - n_regs += 2; - } - else - { - for (i = 0; i < 8; i += 2) - if ((regs_ever_live[i] && ! call_used_regs[i]) - || (regs_ever_live[i+1] && ! call_used_regs[i+1])) - n_regs += 2; - } - - for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2) + if (TARGET_ARCH64) + { + for (i = 0; i < 8; i++) + if (regs_ever_live[i] && ! call_used_regs[i]) + n_regs += 2; + } + else + { + for (i = 0; i < 8; i += 2) if ((regs_ever_live[i] && ! call_used_regs[i]) || (regs_ever_live[i+1] && ! call_used_regs[i+1])) n_regs += 2; } + for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2) + if ((regs_ever_live[i] && ! call_used_regs[i]) + || (regs_ever_live[i+1] && ! call_used_regs[i+1])) + n_regs += 2; + /* Set up values for use in `function_epilogue'. */ num_gfregs = n_regs; @@ -3369,9 +3741,8 @@ compute_frame_size (size, leaf_function) } else { - /* We subtract STARTING_FRAME_OFFSET, remember it's negative. - The stack bias (if any) is taken out to undo its effects. */ - apparent_fsize = (size - STARTING_FRAME_OFFSET + SPARC_STACK_BIAS + 7) & -8; + /* We subtract STARTING_FRAME_OFFSET, remember it's negative. */ + apparent_fsize = (size - STARTING_FRAME_OFFSET + 7) & -8; apparent_fsize += n_regs * 4; actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8); } @@ -3538,7 +3909,7 @@ sparc_nonflat_function_prologue (file, size, leaf_function) /* The canonical frame address refers to the top of the frame. */ dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM - : FRAME_POINTER_REGNUM), + : HARD_FRAME_POINTER_REGNUM), frame_base_offset); if (! leaf_function) @@ -3583,24 +3954,9 @@ sparc_nonflat_function_prologue (file, size, leaf_function) base = frame_base_name; } - n_regs = 0; - if (TARGET_EPILOGUE && ! leaf_function) - /* ??? Originally saved regs 0-15 here. */ - n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset); - else if (leaf_function) - /* ??? Originally saved regs 0-31 here. */ - n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset); - if (TARGET_EPILOGUE) - save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs, - real_offset); - } - - leaf_label = 0; - if (leaf_function && actual_fsize != 0) - { - /* warning ("leaf procedure with frame size %d", actual_fsize); */ - if (! TARGET_EPILOGUE) - leaf_label = gen_label_rtx (); + n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset); + save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs, + real_offset); } } @@ -3609,7 +3965,7 @@ sparc_nonflat_function_prologue (file, size, leaf_function) static void output_restore_regs (file, leaf_function) FILE *file; - int leaf_function; + int leaf_function ATTRIBUTE_UNUSED; { int offset, n_regs; const char *base; @@ -3627,15 +3983,8 @@ output_restore_regs (file, leaf_function) base = frame_base_name; } - n_regs = 0; - if (TARGET_EPILOGUE && ! leaf_function) - /* ??? Originally saved regs 0-15 here. */ - n_regs = restore_regs (file, 0, 8, base, offset, 0); - else if (leaf_function) - /* ??? Originally saved regs 0-31 here. */ - n_regs = restore_regs (file, 0, 8, base, offset, 0); - if (TARGET_EPILOGUE) - restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs); + n_regs = restore_regs (file, 0, 8, base, offset, 0); + restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs); } /* This function generates the assembly code for function exit, @@ -3668,21 +4017,25 @@ sparc_nonflat_function_epilogue (file, size, leaf_function) { const char *ret; - if (leaf_label) - { - emit_label_after (leaf_label, get_last_insn ()); - final_scan_insn (get_last_insn (), file, 0, 0, 1); - } - if (current_function_epilogue_delay_list == 0) { /* If code does not drop into the epilogue, we need - do nothing except output pending case vectors. */ - rtx insn = get_last_insn (); - if (GET_CODE (insn) == NOTE) - insn = prev_nonnote_insn (insn); - if (insn && GET_CODE (insn) == BARRIER) - goto output_vectors; + do nothing except output pending case vectors. + + We have to still output a dummy nop for the sake of + sane backtraces. Otherwise, if the last two instructions + of a function were call foo; dslot; this can make the return + PC of foo (ie. address of call instruction plus 8) point to + the first instruction in the next function. */ + rtx insn; + + fputs("\tnop\n", file); + + insn = get_last_insn (); + if (GET_CODE (insn) == NOTE) + insn = prev_nonnote_insn (insn); + if (insn && GET_CODE (insn) == BARRIER) + goto output_vectors; } if (num_gfregs) @@ -3694,95 +4047,93 @@ sparc_nonflat_function_epilogue (file, size, leaf_function) else ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret"); - if (TARGET_EPILOGUE || leaf_label) + if (! leaf_function) { - int old_target_epilogue = TARGET_EPILOGUE; - target_flags &= ~old_target_epilogue; + if (current_function_calls_eh_return) + { + if (current_function_epilogue_delay_list) + abort (); + if (SKIP_CALLERS_UNIMP_P) + abort (); - if (! leaf_function) + fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file); + } + /* If we wound up with things in our delay slot, flush them here. */ + else if (current_function_epilogue_delay_list) { - if (current_function_calls_eh_return) - { - if (current_function_epilogue_delay_list) - abort (); - if (SKIP_CALLERS_UNIMP_P) - abort (); + rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0)); - fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file); + if (TARGET_V9 && ! epilogue_renumber (&delay, 1)) + { + epilogue_renumber (&delay, 0); + fputs (SKIP_CALLERS_UNIMP_P + ? "\treturn\t%i7+12\n" + : "\treturn\t%i7+8\n", file); + final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), + file, 1, 0, 0); } - /* If we wound up with things in our delay slot, flush them here. */ - else if (current_function_epilogue_delay_list) + else { - rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0)); + rtx insn, src; - if (TARGET_V9 && ! epilogue_renumber (&delay, 1)) - { - epilogue_renumber (&delay, 0); - fputs (SKIP_CALLERS_UNIMP_P - ? "\treturn\t%i7+12\n" - : "\treturn\t%i7+8\n", file); - final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file, 1, 0, 0); - } - else - { - rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode), - get_last_insn ()); - rtx src; + if (GET_CODE (delay) != SET) + abort(); - if (GET_CODE (delay) != SET) + src = SET_SRC (delay); + if (GET_CODE (src) == ASHIFT) + { + if (XEXP (src, 1) != const1_rtx) abort(); + SET_SRC (delay) + = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0), + XEXP (src, 0)); + } - src = SET_SRC (delay); - if (GET_CODE (src) == ASHIFT) - { - if (XEXP (src, 1) != const1_rtx) - abort(); - SET_SRC (delay) = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0), - XEXP (src, 0)); - } + insn = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, delay, + gen_rtx_RETURN (VOIDmode))); + insn = emit_jump_insn (insn); - PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, delay, PATTERN (insn))); - final_scan_insn (insn, file, 1, 0, 1); - } + sparc_emitting_epilogue = true; + final_scan_insn (insn, file, 1, 0, 1); + sparc_emitting_epilogue = false; } - else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P) - fputs ("\treturn\t%i7+8\n\tnop\n", file); - else - fprintf (file, "\t%s\n\trestore\n", ret); } - else if (current_function_calls_eh_return) + else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P) + fputs ("\treturn\t%i7+8\n\tnop\n", file); + else + fprintf (file, "\t%s\n\trestore\n", ret); + } + /* All of the following cases are for leaf functions. */ + else if (current_function_calls_eh_return) + abort (); + else if (current_function_epilogue_delay_list) + { + /* eligible_for_epilogue_delay_slot ensures that if this is a + leaf function, then we will only have insn in the delay slot + if the frame size is zero, thus no adjust for the stack is + needed here. */ + if (actual_fsize != 0) abort (); - /* All of the following cases are for leaf functions. */ - else if (current_function_epilogue_delay_list) - { - /* eligible_for_epilogue_delay_slot ensures that if this is a - leaf function, then we will only have insn in the delay slot - if the frame size is zero, thus no adjust for the stack is - needed here. */ - if (actual_fsize != 0) - abort (); - fprintf (file, "\t%s\n", ret); - final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), - file, 1, 0, 1); - } - /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to - avoid generating confusing assembly language output. */ - else if (actual_fsize == 0) - fprintf (file, "\t%s\n\tnop\n", ret); - else if (actual_fsize <= 4096) - fprintf (file, "\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize); - else if (actual_fsize <= 8192) - fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -%d, %%sp\n", - ret, actual_fsize - 4096); - else if ((actual_fsize & 0x3ff) == 0) - fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", - actual_fsize, ret); - else - fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", - actual_fsize, actual_fsize, ret); - target_flags |= old_target_epilogue; + fprintf (file, "\t%s\n", ret); + final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), + file, 1, 0, 1); } + /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to + avoid generating confusing assembly language output. */ + else if (actual_fsize == 0) + fprintf (file, "\t%s\n\tnop\n", ret); + else if (actual_fsize <= 4096) + fprintf (file, "\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize); + else if (actual_fsize <= 8192) + fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -%d, %%sp\n", + ret, actual_fsize - 4096); + else if ((actual_fsize & 0x3ff) == 0) + fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", + actual_fsize, ret); + else + fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", + actual_fsize, actual_fsize, ret); output_vectors: sparc_output_deferred_case_vectors (); @@ -4222,7 +4573,10 @@ function_arg_record_value_1 (type, startbitpos, parms) if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms); - else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE + else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE + || (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (field))) + == REAL_TYPE))) && TARGET_FPU && ! packed_p && parms->named) @@ -4245,6 +4599,8 @@ function_arg_record_value_1 (type, startbitpos, parms) /* There's no need to check this_slotno < SPARC_FP_ARG MAX. If it wasn't true we wouldn't be here. */ parms->nregs += 1; + if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) + parms->nregs += 1; } else { @@ -4348,24 +4704,45 @@ function_arg_record_value_2 (type, startbitpos, parms) if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms); - else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE + else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE + || (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (field))) + == REAL_TYPE))) && TARGET_FPU && ! packed_p && parms->named) { int this_slotno = parms->slotno + bitpos / BITS_PER_WORD; + int regno; + enum machine_mode mode = DECL_MODE (field); rtx reg; function_arg_record_value_3 (bitpos, parms); - - reg = gen_rtx_REG (DECL_MODE (field), - (SPARC_FP_ARG_FIRST + this_slotno * 2 - + (DECL_MODE (field) == SFmode - && (bitpos & 32) != 0))); + regno = SPARC_FP_ARG_FIRST + this_slotno * 2 + + ((mode == SFmode || mode == SCmode) + && (bitpos & 32) != 0); + switch (mode) + { + case SCmode: mode = SFmode; break; + case DCmode: mode = DFmode; break; + case TCmode: mode = TFmode; break; + default: break; + } + reg = gen_rtx_REG (mode, regno); XVECEXP (parms->ret, 0, parms->nregs) = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (bitpos / BITS_PER_UNIT)); parms->nregs += 1; + if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) + { + regno += GET_MODE_SIZE (mode) / 4; + reg = gen_rtx_REG (mode, regno); + XVECEXP (parms->ret, 0, parms->nregs) + = gen_rtx_EXPR_LIST (VOIDmode, reg, + GEN_INT ((bitpos + GET_MODE_BITSIZE (mode)) + / BITS_PER_UNIT)); + parms->nregs += 1; + } } else { @@ -4693,8 +5070,9 @@ function_arg_pass_by_reference (cum, mode, type, named) return ((type && TREE_CODE (type) == ARRAY_TYPE) /* Consider complex values as aggregates, so care for TCmode. */ || GET_MODE_SIZE (mode) > 16 - || (type && AGGREGATE_TYPE_P (type) - && int_size_in_bytes (type) > 16)); + || (type + && AGGREGATE_TYPE_P (type) + && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)); } } @@ -4846,7 +5224,7 @@ sparc_builtin_saveregs () emit_move_insn (gen_rtx_MEM (word_mode, gen_rtx_PLUS (Pmode, frame_pointer_rtx, - GEN_INT (STACK_POINTER_OFFSET + GEN_INT (FIRST_PARM_OFFSET (0) + (UNITS_PER_WORD * regno)))), gen_rtx_REG (word_mode, @@ -4854,7 +5232,7 @@ sparc_builtin_saveregs () address = gen_rtx_PLUS (Pmode, frame_pointer_rtx, - GEN_INT (STACK_POINTER_OFFSET + GEN_INT (FIRST_PARM_OFFSET (0) + UNITS_PER_WORD * first_reg)); return address; @@ -4895,11 +5273,15 @@ sparc_va_arg (valist, type) if (AGGREGATE_TYPE_P (type)) { - if (size > 16) + if ((unsigned HOST_WIDE_INT) size > 16) { indirect = 1; size = rsize = UNITS_PER_WORD; } + /* SPARC v9 ABI states that structures up to 8 bytes in size are + given one 8 byte slot. */ + else if (size == 0) + size = rsize = UNITS_PER_WORD; else size = rsize; } @@ -4994,25 +5376,43 @@ sparc_va_arg (valist, type) INSN, if set, is the insn. */ char * -output_cbranch (op, label, reversed, annul, noop, insn) - rtx op; +output_cbranch (op, dest, label, reversed, annul, noop, insn) + rtx op, dest; int label; int reversed, annul, noop; rtx insn; { - static char string[32]; + static char string[50]; enum rtx_code code = GET_CODE (op); rtx cc_reg = XEXP (op, 0); enum machine_mode mode = GET_MODE (cc_reg); - static char v8_labelno[] = "%lX"; - static char v9_icc_labelno[] = "%%icc, %lX"; - static char v9_xcc_labelno[] = "%%xcc, %lX"; - static char v9_fcc_labelno[] = "%%fccX, %lY"; - char *labelno; - const char *branch; - int labeloff, spaces = 8; + const char *labelno, *branch; + int spaces = 8, far; + char *p; + + /* v9 branches are limited to +-1MB. If it is too far away, + change + + bne,pt %xcc, .LC30 + + to + + be,pn %xcc, .+12 + nop + ba .LC30 + + and + + fbne,a,pn %fcc2, .LC29 + + to - if (reversed) + fbe,pt %fcc2, .+16 + nop + ba .LC29 */ + + far = get_attr_length (insn) >= 3; + if (reversed ^ far) { /* Reversal of FP compares takes care -- an ordered compare becomes an unordered compare and vice versa. */ @@ -5095,7 +5495,7 @@ output_cbranch (op, label, reversed, annul, noop, insn) branch = "be"; break; case GE: - if (mode == CC_NOOVmode) + if (mode == CC_NOOVmode || mode == CCX_NOOVmode) branch = "bpos"; else branch = "bge"; @@ -5107,7 +5507,7 @@ output_cbranch (op, label, reversed, annul, noop, insn) branch = "ble"; break; case LT: - if (mode == CC_NOOVmode) + if (mode == CC_NOOVmode || mode == CCX_NOOVmode) branch = "bneg"; else branch = "bl"; @@ -5131,54 +5531,89 @@ output_cbranch (op, label, reversed, annul, noop, insn) strcpy (string, branch); } spaces -= strlen (branch); + p = strchr (string, '\0'); /* Now add the annulling, the label, and a possible noop. */ - if (annul) + if (annul && ! far) { - strcat (string, ",a"); + strcpy (p, ",a"); + p += 2; spaces -= 2; } if (! TARGET_V9) - { - labeloff = 2; - labelno = v8_labelno; - } + labelno = ""; else { rtx note; + int v8 = 0; - if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) + if (! far && insn && INSN_ADDRESSES_SET_P ()) { - strcat (string, - INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); - spaces -= 3; + int delta = (INSN_ADDRESSES (INSN_UID (dest)) + - INSN_ADDRESSES (INSN_UID (insn))); + /* Leave some instructions for "slop". */ + if (delta < -260000 || delta >= 260000) + v8 = 1; } - labeloff = 9; if (mode == CCFPmode || mode == CCFPEmode) { - labeloff = 10; - labelno = v9_fcc_labelno; + static char v9_fcc_labelno[] = "%%fccX, "; /* Set the char indicating the number of the fcc reg to use. */ - labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; + v9_fcc_labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; + labelno = v9_fcc_labelno; + if (v8) + { + if (REGNO (cc_reg) == SPARC_FCC_REG) + labelno = ""; + else + abort (); + } } else if (mode == CCXmode || mode == CCX_NOOVmode) - labelno = v9_xcc_labelno; + { + labelno = "%%xcc, "; + if (v8) + abort (); + } else - labelno = v9_icc_labelno; + { + labelno = "%%icc, "; + if (v8) + labelno = ""; + } + + if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX))) + { + strcpy (p, + ((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far) + ? ",pt" : ",pn"); + p += 3; + spaces -= 3; + } } - /* Set the char indicating the number of the operand containing the - label_ref. */ - labelno[labeloff] = label + '0'; if (spaces > 0) - strcat (string, "\t"); + *p++ = '\t'; else - strcat (string, " "); - strcat (string, labelno); - + *p++ = ' '; + strcpy (p, labelno); + p = strchr (p, '\0'); + if (far) + { + strcpy (p, ".+12\n\tnop\n\tb\t"); + if (annul || noop) + p[3] = '6'; + p += 13; + } + *p++ = '%'; + *p++ = 'l'; + /* Set the char indicating the number of the operand containing the + label_ref. */ + *p++ = label + '0'; + *p = '\0'; if (noop) - strcat (string, "\n\tnop"); + strcpy (p, "\n\tnop"); return string; } @@ -5257,7 +5692,7 @@ sparc_emit_float_lib_cmp (x, y, comparison) else slot1 = y; - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), 1, + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL, DImode, 2, XEXP (slot0, 0), Pmode, XEXP (slot1, 0), Pmode); @@ -5266,7 +5701,7 @@ sparc_emit_float_lib_cmp (x, y, comparison) } else { - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), 1, + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL, SImode, 2, x, TFmode, y, TFmode); @@ -5324,6 +5759,42 @@ sparc_emit_float_lib_cmp (x, y, comparison) } } +/* Generate an unsigned DImode to FP conversion. This is the same code + optabs would emit if we didn't have TFmode patterns. */ + +void +sparc_emit_floatunsdi (operands) + rtx operands[2]; +{ + rtx neglab, donelab, i0, i1, f0, in, out; + enum machine_mode mode; + + out = operands[0]; + in = force_reg (DImode, operands[1]); + mode = GET_MODE (out); + neglab = gen_label_rtx (); + donelab = gen_label_rtx (); + i0 = gen_reg_rtx (DImode); + i1 = gen_reg_rtx (DImode); + f0 = gen_reg_rtx (mode); + + emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab); + + emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in))); + emit_jump_insn (gen_jump (donelab)); + emit_barrier (); + + emit_label (neglab); + + emit_insn (gen_lshrdi3 (i0, in, const1_rtx)); + emit_insn (gen_anddi3 (i1, in, const1_rtx)); + emit_insn (gen_iordi3 (i0, i0, i1)); + emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0))); + emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0))); + + emit_label (donelab); +} + /* Return the string to output a conditional branch to LABEL, testing register REG. LABEL is the operand number of the label; REG is the operand number of the reg. OP is the conditional expression. The mode @@ -5336,22 +5807,45 @@ sparc_emit_float_lib_cmp (x, y, comparison) NOOP is non-zero if we have to follow this branch by a noop. */ char * -output_v9branch (op, reg, label, reversed, annul, noop, insn) - rtx op; +output_v9branch (op, dest, reg, label, reversed, annul, noop, insn) + rtx op, dest; int reg, label; int reversed, annul, noop; rtx insn; { - static char string[20]; + static char string[50]; enum rtx_code code = GET_CODE (op); enum machine_mode mode = GET_MODE (XEXP (op, 0)); - static char labelno[] = "%X, %lX"; rtx note; - int spaces = 8; + int far; + char *p; + + /* branch on register are limited to +-128KB. If it is too far away, + change + + brnz,pt %g1, .LC30 + + to + + brz,pn %g1, .+12 + nop + ba,pt %xcc, .LC30 + + and + + brgez,a,pn %o1, .LC29 + + to + + brlz,pt %o1, .+16 + nop + ba,pt %xcc, .LC29 */ + + far = get_attr_length (insn) >= 3; /* If not floating-point or if EQ or NE, we can just reverse the code. */ - if (reversed) - code = reverse_condition (code), reversed = 0; + if (reversed ^ far) + code = reverse_condition (code); /* Only 64 bit versions of these instructions exist. */ if (mode != DImode) @@ -5363,62 +5857,90 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn) { case NE: strcpy (string, "brnz"); - spaces -= 4; break; case EQ: strcpy (string, "brz"); - spaces -= 3; break; case GE: strcpy (string, "brgez"); - spaces -= 5; break; case LT: strcpy (string, "brlz"); - spaces -= 4; break; case LE: strcpy (string, "brlez"); - spaces -= 5; break; case GT: strcpy (string, "brgz"); - spaces -= 4; break; default: abort (); } + p = strchr (string, '\0'); + /* Now add the annulling, reg, label, and nop. */ - if (annul) + if (annul && ! far) { - strcat (string, ",a"); - spaces -= 2; + strcpy (p, ",a"); + p += 2; } - if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) + if (insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX))) { - strcat (string, - INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); - spaces -= 3; + strcpy (p, + ((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far) + ? ",pt" : ",pn"); + p += 3; } - labelno[1] = reg + '0'; - labelno[6] = label + '0'; - if (spaces > 0) - strcat (string, "\t"); - else - strcat (string, " "); - strcat (string, labelno); + *p = p < string + 8 ? '\t' : ' '; + p++; + *p++ = '%'; + *p++ = '0' + reg; + *p++ = ','; + *p++ = ' '; + if (far) + { + int veryfar = 1, delta; + + if (INSN_ADDRESSES_SET_P ()) + { + delta = (INSN_ADDRESSES (INSN_UID (dest)) + - INSN_ADDRESSES (INSN_UID (insn))); + /* Leave some instructions for "slop". */ + if (delta >= -260000 && delta < 260000) + veryfar = 0; + } + + strcpy (p, ".+12\n\tnop\n\t"); + if (annul || noop) + p[3] = '6'; + p += 11; + if (veryfar) + { + strcpy (p, "b\t"); + p += 2; + } + else + { + strcpy (p, "ba,pt\t%%xcc, "); + p += 13; + } + } + *p++ = '%'; + *p++ = 'l'; + *p++ = '0' + label; + *p = '\0'; if (noop) - strcat (string, "\n\tnop"); + strcpy (p, "\n\tnop"); return string; } @@ -5467,7 +5989,7 @@ epilogue_renumber (where, test) are in the return delayed slot. */ case PLUS: if (GET_CODE (XEXP (*where, 0)) == REG - && REGNO (XEXP (*where, 0)) == FRAME_POINTER_REGNUM + && REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM && (GET_CODE (XEXP (*where, 1)) != CONST_INT || INTVAL (XEXP (*where, 1)) < SPARC_STACK_BIAS)) return 1; @@ -5476,7 +5998,7 @@ epilogue_renumber (where, test) case MEM: if (SPARC_STACK_BIAS && GET_CODE (XEXP (*where, 0)) == REG - && REGNO (XEXP (*where, 0)) == FRAME_POINTER_REGNUM) + && REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM) return 1; break; @@ -5501,87 +6023,6 @@ epilogue_renumber (where, test) } return 0; } - -/* Output assembler code to return from a function. */ - -const char * -output_return (operands) - rtx *operands; -{ - rtx delay = final_sequence ? XVECEXP (final_sequence, 0, 1) : 0; - - if (leaf_label) - { - operands[0] = leaf_label; - return "b%* %l0%("; - } - else if (current_function_uses_only_leaf_regs) - { - /* No delay slot in a leaf function. */ - if (delay) - abort (); - - /* If we didn't allocate a frame pointer for the current function, - the stack pointer might have been adjusted. Output code to - restore it now. */ - - operands[0] = GEN_INT (actual_fsize); - - /* Use sub of negated value in first two cases instead of add to - allow actual_fsize == 4096. */ - - if (actual_fsize <= 4096) - { - if (SKIP_CALLERS_UNIMP_P) - return "jmp\t%%o7+12\n\tsub\t%%sp, -%0, %%sp"; - else - return "retl\n\tsub\t%%sp, -%0, %%sp"; - } - else if (actual_fsize <= 8192) - { - operands[0] = GEN_INT (actual_fsize - 4096); - if (SKIP_CALLERS_UNIMP_P) - return "sub\t%%sp, -4096, %%sp\n\tjmp\t%%o7+12\n\tsub\t%%sp, -%0, %%sp"; - else - return "sub\t%%sp, -4096, %%sp\n\tretl\n\tsub\t%%sp, -%0, %%sp"; - } - else if (SKIP_CALLERS_UNIMP_P) - { - if ((actual_fsize & 0x3ff) != 0) - return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tjmp\t%%o7+12\n\tadd\t%%sp, %%g1, %%sp"; - else - return "sethi\t%%hi(%a0), %%g1\n\tjmp\t%%o7+12\n\tadd\t%%sp, %%g1, %%sp"; - } - else - { - if ((actual_fsize & 0x3ff) != 0) - return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp"; - else - return "sethi\t%%hi(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp"; - } - } - else if (TARGET_V9) - { - if (delay) - { - epilogue_renumber (&SET_DEST (PATTERN (delay)), 0); - epilogue_renumber (&SET_SRC (PATTERN (delay)), 0); - } - if (SKIP_CALLERS_UNIMP_P) - return "return\t%%i7+12%#"; - else - return "return\t%%i7+8%#"; - } - else - { - if (delay) - abort (); - if (SKIP_CALLERS_UNIMP_P) - return "jmp\t%%i7+12\n\trestore"; - else - return "ret\n\trestore"; - } -} /* Leaf functions and non-leaf functions have different needs. */ @@ -5689,6 +6130,20 @@ registers_ok_for_ldd_peep (reg1, reg2) ld [%o0 + 4], %o1 to ldd [%o0], %o0 + nor: + ld [%g3 + 4], %g3 + ld [%g3], %g2 + to + ldd [%g3], %g2 + + But, note that the transformation from: + ld [%g2 + 4], %g3 + ld [%g2], %g2 + to + ldd [%g2], %g2 + is perfectly fine. Thus, the peephole2 patterns always pass us + the destination register of the first load, never the second one. + For stores we don't have a similar problem, so dependent_reg_rtx is NULL_RTX. */ @@ -5987,9 +6442,7 @@ print_operand (file, x, code) case 'b': { /* Print a sign-extended character. */ - int i = INTVAL (x) & 0xff; - if (i & 0x80) - i |= 0xffffff00; + int i = trunc_int_for_mode (INTVAL (x), QImode); fprintf (file, "%d", i); return; } @@ -6260,38 +6713,42 @@ sparc_initialize_trampoline (tramp, fnaddr, cxt) */ #ifdef TRANSFER_FROM_TRAMPOLINE emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"), - 0, VOIDmode, 1, tramp, Pmode); + LCT_NORMAL, VOIDmode, 1, tramp, Pmode); #endif - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 0)), - expand_binop (SImode, ior_optab, - expand_shift (RSHIFT_EXPR, SImode, fnaddr, - size_int (10), 0, 1), - GEN_INT (0x03000000), - NULL_RTX, 1, OPTAB_DIRECT)); - - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), - expand_binop (SImode, ior_optab, - expand_shift (RSHIFT_EXPR, SImode, cxt, - size_int (10), 0, 1), - GEN_INT (0x05000000), - NULL_RTX, 1, OPTAB_DIRECT)); - - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), - expand_binop (SImode, ior_optab, - expand_and (fnaddr, GEN_INT (0x3ff), NULL_RTX), - GEN_INT (0x81c06000), - NULL_RTX, 1, OPTAB_DIRECT)); - - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), - expand_binop (SImode, ior_optab, - expand_and (cxt, GEN_INT (0x3ff), NULL_RTX), - GEN_INT (0x8410a000), - NULL_RTX, 1, OPTAB_DIRECT)); + emit_move_insn + (gen_rtx_MEM (SImode, plus_constant (tramp, 0)), + expand_binop (SImode, ior_optab, + expand_shift (RSHIFT_EXPR, SImode, fnaddr, + size_int (10), 0, 1), + GEN_INT (trunc_int_for_mode (0x03000000, SImode)), + NULL_RTX, 1, OPTAB_DIRECT)); + + emit_move_insn + (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), + expand_binop (SImode, ior_optab, + expand_shift (RSHIFT_EXPR, SImode, cxt, + size_int (10), 0, 1), + GEN_INT (trunc_int_for_mode (0x05000000, SImode)), + NULL_RTX, 1, OPTAB_DIRECT)); + + emit_move_insn + (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), + expand_binop (SImode, ior_optab, + expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX), + GEN_INT (trunc_int_for_mode (0x81c06000, SImode)), + NULL_RTX, 1, OPTAB_DIRECT)); + + emit_move_insn + (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), + expand_binop (SImode, ior_optab, + expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX), + GEN_INT (trunc_int_for_mode (0x8410a000, SImode)), + NULL_RTX, 1, OPTAB_DIRECT)); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp)))); /* On UltraSPARC a flush flushes an entire cache line. The trampoline is aligned on a 16 byte boundary so one flush clears it all. */ + emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp)))); if (sparc_cpu != PROCESSOR_ULTRASPARC) emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, plus_constant (tramp, 8))))); @@ -6307,7 +6764,7 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt) { #ifdef TRANSFER_FROM_TRAMPOLINE emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"), - 0, VOIDmode, 1, tramp, Pmode); + LCT_NORMAL, VOIDmode, 1, tramp, Pmode); #endif /* @@ -6319,13 +6776,13 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt) */ emit_move_insn (gen_rtx_MEM (SImode, tramp), - GEN_INT (0x83414000)); + GEN_INT (trunc_int_for_mode (0x83414000, SImode))); emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), - GEN_INT (0xca586018)); + GEN_INT (trunc_int_for_mode (0xca586018, SImode))); emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), - GEN_INT (0x81c14000)); + GEN_INT (trunc_int_for_mode (0x81c14000, SImode))); emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), - GEN_INT (0xca586010)); + GEN_INT (trunc_int_for_mode (0xca586010, SImode))); emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt); emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr); emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp)))); @@ -6421,12 +6878,12 @@ struct sparc_frame_info zero_frame_info; /* Tell prologue and epilogue if register REGNO should be saved / restored. */ #define RETURN_ADDR_REGNUM 15 -#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) +#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM)) #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) #define MUST_SAVE_REGISTER(regno) \ - ((regs_ever_live[regno] && !call_used_regs[regno]) \ - || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) \ + ((regs_ever_live[regno] && !call_used_regs[regno]) \ + || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ || (regno == RETURN_ADDR_REGNUM && regs_ever_live[RETURN_ADDR_REGNUM])) /* Return the bytes needed to compute the frame pointer from the current @@ -6699,7 +7156,7 @@ sparc_flat_function_prologue (file, size) if (size > 0) { unsigned int reg_offset = current_frame_info.reg_offset; - const char *const fp_str = reg_names[FRAME_POINTER_REGNUM]; + const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM]; static const char *const t1_str = "%g1"; /* Things get a little tricky if local variables take up more than ~4096 @@ -6720,7 +7177,7 @@ sparc_flat_function_prologue (file, size) { fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) -size, sp_str); - if (gmask & FRAME_POINTER_MASK) + if (gmask & HARD_FRAME_POINTER_MASK) { fprintf (file, "\tst\t%s, [%s+%d]\n", fp_str, sp_str, reg_offset); @@ -6735,7 +7192,7 @@ sparc_flat_function_prologue (file, size) fprintf (file, HOST_WIDE_INT_PRINT_DEC, size); fprintf (file, ", %s\n\tsub\t%s, %s, %s\n", t1_str, sp_str, t1_str, sp_str); - if (gmask & FRAME_POINTER_MASK) + if (gmask & HARD_FRAME_POINTER_MASK) { fprintf (file, "\tst\t%s, [%s+%d]\n", fp_str, sp_str, reg_offset); @@ -6747,11 +7204,11 @@ sparc_flat_function_prologue (file, size) if (dwarf2out_do_frame ()) { char *l = dwarf2out_cfi_label (); - if (gmask & FRAME_POINTER_MASK) + if (gmask & HARD_FRAME_POINTER_MASK) { - dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, + dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM, reg_offset - 4 - size); - dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, 0); + dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0); } else dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size); @@ -6765,7 +7222,7 @@ sparc_flat_function_prologue (file, size) reg_offset += 4; } sparc_flat_save_restore (file, sp_str, reg_offset, - gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), + gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK), current_frame_info.fmask, "st", "std", -size); } @@ -6782,7 +7239,7 @@ sparc_flat_function_prologue (file, size) { fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) -size1, sp_str); - if (gmask & FRAME_POINTER_MASK) + if (gmask & HARD_FRAME_POINTER_MASK) { fprintf (file, "\tst\t%s, [%s+%d]\n\tsub\t%s, %d, %s\t%s# set up frame pointer\n", fp_str, sp_str, (int) offset, sp_str, (int) -size1, @@ -6796,7 +7253,7 @@ sparc_flat_function_prologue (file, size) fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1); fprintf (file, ", %s\n\tsub\t%s, %s, %s\n", t1_str, sp_str, t1_str, sp_str); - if (gmask & FRAME_POINTER_MASK) + if (gmask & HARD_FRAME_POINTER_MASK) { fprintf (file, "\tst\t%s, [%s+%d]\n\tadd\t%s, %s, %s\t%s# set up frame pointer\n", fp_str, sp_str, (int) offset, sp_str, t1_str, @@ -6807,11 +7264,11 @@ sparc_flat_function_prologue (file, size) if (dwarf2out_do_frame ()) { char *l = dwarf2out_cfi_label (); - if (gmask & FRAME_POINTER_MASK) + if (gmask & HARD_FRAME_POINTER_MASK) { - dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, + dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM, offset - 4 - size1); - dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, 0); + dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0); } else dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1); @@ -6827,7 +7284,7 @@ sparc_flat_function_prologue (file, size) offset += 4; } sparc_flat_save_restore (file, sp_str, offset, - gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), + gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK), current_frame_info.fmask, "st", "std", -size1); fprintf (file, "\tset\t"); @@ -6835,7 +7292,7 @@ sparc_flat_function_prologue (file, size) fprintf (file, ", %s\n\tsub\t%s, %s, %s\n", t1_str, sp_str, t1_str, sp_str); if (dwarf2out_do_frame ()) - if (! (gmask & FRAME_POINTER_MASK)) + if (! (gmask & HARD_FRAME_POINTER_MASK)) dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size); } } @@ -6884,7 +7341,7 @@ sparc_flat_function_epilogue (file, size) unsigned HOST_WIDE_INT reg_offset = current_frame_info.reg_offset; unsigned HOST_WIDE_INT size1; const char *const sp_str = reg_names[STACK_POINTER_REGNUM]; - const char *const fp_str = reg_names[FRAME_POINTER_REGNUM]; + const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM]; static const char *const t1_str = "%g1"; /* In the reload sequence, we don't need to fill the load delay @@ -6930,7 +7387,7 @@ sparc_flat_function_epilogue (file, size) /* We must restore the frame pointer and return address reg first because they are treated specially by the prologue output code. */ - if (current_frame_info.gmask & FRAME_POINTER_MASK) + if (current_frame_info.gmask & HARD_FRAME_POINTER_MASK) { fprintf (file, "\tld\t[%s+%d], %s\n", sp_str, (int) reg_offset, fp_str); @@ -6945,7 +7402,7 @@ sparc_flat_function_epilogue (file, size) /* Restore any remaining saved registers. */ sparc_flat_save_restore (file, sp_str, reg_offset, - current_frame_info.gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), + current_frame_info.gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK), current_frame_info.fmask, "ld", "ldd", 0); @@ -8397,60 +8854,24 @@ sparc_v8plus_shift (operands, insn, opcode) else return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0"); } - - -/* Return 1 if DEST and SRC reference only global and in registers. */ - -int -sparc_return_peephole_ok (dest, src) - rtx dest, src; -{ - if (! TARGET_V9) - return 0; - if (current_function_uses_only_leaf_regs) - return 0; - if (GET_CODE (src) != CONST_INT - && (GET_CODE (src) != REG || ! IN_OR_GLOBAL_P (src))) - return 0; - return IN_OR_GLOBAL_P (dest); -} -/* Output assembler code to FILE to increment profiler label # LABELNO - for profiling a function entry. - - 32 bit sparc uses %g2 as the STATIC_CHAIN_REGNUM which gets clobbered - during profiling so we need to save/restore it around the call to mcount. - We're guaranteed that a save has just been done, and we use the space - allocated for intreg/fpreg value passing. */ +/* Output rtl to increment the profiler label LABELNO + for profiling a function entry. */ void -sparc_function_profiler (file, labelno) - FILE *file; +sparc_profile_hook (labelno) int labelno; { char buf[32]; - ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); - - if (! TARGET_ARCH64) - fputs ("\tst\t%g2, [%fp-4]\n", file); - - fputs ("\tsethi\t%hi(", file); - assemble_name (file, buf); - fputs ("), %o0\n", file); + rtx lab, fun; - fputs ("\tcall\t", file); - assemble_name (file, MCOUNT_FUNCTION); - putc ('\n', file); - - fputs ("\t or\t%o0, %lo(", file); - assemble_name (file, buf); - fputs ("), %o0\n", file); + ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); + lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); + fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION); - if (! TARGET_ARCH64) - fputs ("\tld\t[%fp-4], %g2\n", file); + emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode); } - - + /* Mark ARG, which is really a struct ultrasparc_pipline_state *, for GC. */ @@ -8474,7 +8895,6 @@ sparc_add_gc_roots () { ggc_add_rtx_root (&sparc_compare_op0, 1); ggc_add_rtx_root (&sparc_compare_op1, 1); - ggc_add_rtx_root (&leaf_label, 1); ggc_add_rtx_root (&global_offset_table, 1); ggc_add_rtx_root (&get_pc_symbol, 1); ggc_add_rtx_root (&sparc_addr_diff_list, 1); @@ -8511,3 +8931,65 @@ sparc_elf_asm_named_section (name, flags) fputc ('\n', asm_out_file); } #endif /* OBJECT_FORMAT_ELF */ + +int +sparc_extra_constraint_check (op, c, strict) + rtx op; + int c; + int strict; +{ + int reload_ok_mem; + + if (TARGET_ARCH64 + && (c == 'T' || c == 'U')) + return 0; + + switch (c) + { + case 'Q': + return fp_sethi_p (op); + + case 'R': + return fp_mov_p (op); + + case 'S': + return fp_high_losum_p (op); + + case 'U': + if (! strict + || (GET_CODE (op) == REG + && (REGNO (op) < FIRST_PSEUDO_REGISTER + || reg_renumber[REGNO (op)] >= 0))) + return register_ok_for_ldd (op); + + return 0; + + case 'W': + case 'T': + break; + + default: + return 0; + } + + /* Our memory extra constraints have to emulate the + behavior of 'm' and 'o' in order for reload to work + correctly. */ + if (GET_CODE (op) == MEM) + { + reload_ok_mem = 0; + if ((TARGET_ARCH64 || mem_min_alignment (op, 8)) + && (! strict + || strict_memory_address_p (Pmode, XEXP (op, 0)))) + reload_ok_mem = 1; + } + else + { + reload_ok_mem = (reload_in_progress + && GET_CODE (op) == REG + && REGNO (op) >= FIRST_PSEUDO_REGISTER + && reg_renumber [REGNO (op)] < 0); + } + + return reload_ok_mem; +} |