static int pa_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
static struct machine_function * pa_init_machine_status (void);
+static enum reg_class pa_secondary_reload (bool, rtx, enum reg_class,
+ enum machine_mode,
+ secondary_reload_info *);
/* Save the operands last given to a compare for use when we
#undef TARGET_CANNOT_FORCE_CONST_MEM
#define TARGET_CANNOT_FORCE_CONST_MEM pa_tls_referenced_p
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD pa_secondary_reload
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Parse the -mfixed-range= option string. */
fputc ('\n', asm_out_file);
}
\f
-/* Return the class of any secondary reload register that is needed to
- move IN into a register in class CLASS using mode MODE.
+static enum reg_class
+pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
+ enum machine_mode mode, secondary_reload_info *sri)
+{
+ int is_symbolic;
+ int regno = -1;
- Profiling has showed this routine and its descendants account for
- a significant amount of compile time (~7%). So it has been
- optimized to reduce redundant computations and eliminate useless
- function calls.
+ /* Handle the easy stuff first. */
+ if (class == R1_REGS)
+ return NO_REGS;
- It might be worthwhile to try and make this a leaf function too. */
+ if (REG_P (x))
+ {
+ regno = REGNO (x);
+ if (class == BASE_REG_CLASS && regno < FIRST_PSEUDO_REGISTER)
+ return NO_REGS;
+ }
-enum reg_class
-pa_secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
-{
- int regno, is_symbolic;
+ /* If we have something like (mem (mem (...)), we can safely assume the
+ inner MEM will end up in a general register after reloading, so there's
+ no need for a secondary reload. */
+ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == MEM)
+ return NO_REGS;
/* Trying to load a constant into a FP register during PIC code
- generation will require %r1 as a scratch register. */
+ generation requires %r1 as a scratch register. */
if (flag_pic
&& GET_MODE_CLASS (mode) == MODE_INT
&& FP_REG_CLASS_P (class)
- && (GET_CODE (in) == CONST_INT || GET_CODE (in) == CONST_DOUBLE))
- return R1_REGS;
-
- /* Profiling showed the PA port spends about 1.3% of its compilation
- time in true_regnum from calls inside pa_secondary_reload_class. */
-
- if (GET_CODE (in) == REG)
+ && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
{
- regno = REGNO (in);
- if (regno >= FIRST_PSEUDO_REGISTER)
- regno = true_regnum (in);
+ gcc_assert (mode == SImode || mode == DImode);
+ sri->icode = (mode == SImode ? CODE_FOR_reload_insi_r1
+ : CODE_FOR_reload_indi_r1);
+ return NO_REGS;
}
- else if (GET_CODE (in) == SUBREG)
- regno = true_regnum (in);
- else
- regno = -1;
- /* If we have something like (mem (mem (...)), we can safely assume the
- inner MEM will end up in a general register after reloading, so there's
- no need for a secondary reload. */
- if (GET_CODE (in) == MEM
- && GET_CODE (XEXP (in, 0)) == MEM)
- return NO_REGS;
+ /* Profiling showed the PA port spends about 1.3% of its compilation
+ time in true_regnum from calls inside pa_secondary_reload_class. */
+ if (regno >= FIRST_PSEUDO_REGISTER || GET_CODE (x) == SUBREG)
+ regno = true_regnum (x);
/* Handle out of range displacement for integer mode loads/stores of
FP registers. */
&& GET_MODE_CLASS (mode) == MODE_INT
&& FP_REG_CLASS_P (class))
|| (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
- return GENERAL_REGS;
+ {
+ sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+ return NO_REGS;
+ }
/* A SAR<->FP register copy requires a secondary register (GPR) as
well as secondary memory. */
if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
&& ((REGNO_REG_CLASS (regno) == SHIFT_REGS && FP_REG_CLASS_P (class))
- || (class == SHIFT_REGS && FP_REG_CLASS_P (REGNO_REG_CLASS (regno)))))
- return GENERAL_REGS;
+ || (class == SHIFT_REGS
+ && FP_REG_CLASS_P (REGNO_REG_CLASS (regno)))))
+ {
+ sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+ return NO_REGS;
+ }
- if (GET_CODE (in) == HIGH)
- in = XEXP (in, 0);
+ /* Secondary reloads of symbolic operands require %r1 as a scratch
+ register when we're generating PIC code and the operand isn't
+ readonly. */
+ if (GET_CODE (x) == HIGH)
+ x = XEXP (x, 0);
/* Profiling has showed GCC spends about 2.6% of its compilation
time in symbolic_operand from calls inside pa_secondary_reload_class.
-
- We use an inline copy and only compute its return value once to avoid
- useless work. */
- switch (GET_CODE (in))
+ So, we use an inline copy to avoid useless work. */
+ switch (GET_CODE (x))
{
- rtx tmp;
+ rtx op;
case SYMBOL_REF:
+ is_symbolic = !SYMBOL_REF_TLS_MODEL (x);
+ break;
case LABEL_REF:
is_symbolic = 1;
break;
case CONST:
- tmp = XEXP (in, 0);
- is_symbolic = ((GET_CODE (XEXP (tmp, 0)) == SYMBOL_REF
- || GET_CODE (XEXP (tmp, 0)) == LABEL_REF)
- && GET_CODE (XEXP (tmp, 1)) == CONST_INT);
+ op = XEXP (x, 0);
+ is_symbolic = (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
+ || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT);
break;
-
default:
is_symbolic = 0;
break;
}
- if (!flag_pic
- && is_symbolic
- && read_only_operand (in, VOIDmode))
- return NO_REGS;
-
- if (class != R1_REGS && is_symbolic)
- return R1_REGS;
+ if (is_symbolic && (flag_pic || !read_only_operand (x, VOIDmode)))
+ {
+ gcc_assert (mode == SImode || mode == DImode);
+ sri->icode = (mode == SImode ? CODE_FOR_reload_insi_r1
+ : CODE_FOR_reload_indi_r1);
+ }
return NO_REGS;
}
DONE;
}")
-;; Reloading an SImode or DImode value requires a scratch register if
-;; going in to or out of float point registers.
+;; Handle SImode input reloads requiring %r1 as a scratch register.
+(define_expand "reload_insi_r1"
+ [(set (match_operand:SI 0 "register_operand" "=Z")
+ (match_operand:SI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&a"))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, SImode, operands[2]))
+ DONE;
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle SImode input reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_insi"
[(set (match_operand:SI 0 "register_operand" "=Z")
(match_operand:SI 1 "non_hard_reg_operand" ""))
DONE;
}")
+;; Handle SImode output reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_outsi"
[(set (match_operand:SI 0 "non_hard_reg_operand" "")
(match_operand:SI 1 "register_operand" "Z"))
DONE;
}")
-;; Reloading an SImode or DImode value requires a scratch register if
-;; going in to or out of float point registers.
-
+;; Handle DFmode input reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_indf"
[(set (match_operand:DF 0 "register_operand" "=Z")
(match_operand:DF 1 "non_hard_reg_operand" ""))
DONE;
}")
+;; Handle DFmode output reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_outdf"
[(set (match_operand:DF 0 "non_hard_reg_operand" "")
(match_operand:DF 1 "register_operand" "Z"))
DONE;
}")
+;; Handle DImode input reloads requiring %r1 as a scratch register.
+(define_expand "reload_indi_r1"
+ [(set (match_operand:DI 0 "register_operand" "=Z")
+ (match_operand:DI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&a"))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, DImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle DImode input reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_indi"
[(set (match_operand:DI 0 "register_operand" "=Z")
(match_operand:DI 1 "non_hard_reg_operand" ""))
DONE;
}")
+;; Handle DImode output reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_outdi"
[(set (match_operand:DI 0 "non_hard_reg_operand" "")
(match_operand:DI 1 "register_operand" "Z"))
DONE;
}")
-;; Reloading an SImode or DImode value requires a scratch register if
-;; going in to or out of float point registers.
-
+;; Handle SFmode input reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_insf"
[(set (match_operand:SF 0 "register_operand" "=Z")
(match_operand:SF 1 "non_hard_reg_operand" ""))
DONE;
}")
+;; Handle SFmode output reloads requiring a general register as a
+;; scratch register.
(define_expand "reload_outsf"
[(set (match_operand:SF 0 "non_hard_reg_operand" "")
(match_operand:SF 1 "register_operand" "Z"))