aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>1994-08-09 00:03:07 -0600
committerJeff Law <law@gcc.gnu.org>1994-08-09 00:03:07 -0600
commit326bc2de1db63451ba0918858cc8a691f36bf216 (patch)
tree089d5a753c4949ba0bee19f5a9c6867d71284dff
parent6ce47c075f882002192a9b68c9c31ff04d2efe06 (diff)
downloadgcc-326bc2de1db63451ba0918858cc8a691f36bf216.zip
gcc-326bc2de1db63451ba0918858cc8a691f36bf216.tar.gz
gcc-326bc2de1db63451ba0918858cc8a691f36bf216.tar.bz2
pa.c (hppa_legitimize_address): Do nothing with function label arithmetic.
* pa.c (hppa_legitimize_address): Do nothing with function label arithmetic. (emit_move_sequence): Split up function label arithmetic so that function's address is loaded first, then constant part is added to the function's address. (is_function_label_plus_const): New function. From-SVN: r7882
-rw-r--r--gcc/config/pa/pa.c50
1 files changed, 47 insertions, 3 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 94a7ebd..2ec1d8b 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -611,9 +611,12 @@ hppa_legitimize_address (x, oldx, mode)
if (GET_CODE (x) == CONST)
x = XEXP (x, 0);
+ /* Note we must reject symbols which represent function addresses
+ since the assembler/linker can't handle arithmetic on plabels. */
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT
- && (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ && ((GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ && !FUNCTION_NAME_P (XSTR (XEXP (x, 0), 0)))
|| GET_CODE (XEXP (x, 0)) == REG))
{
rtx int_part, ptr_reg;
@@ -892,13 +895,32 @@ emit_move_sequence (operands, mode, scratch_reg)
cse and loop optimizations. */
else
{
- rtx temp, set;
+ rtx temp, set, const_part = NULL;
if (reload_in_progress || reload_completed)
temp = scratch_reg ? scratch_reg : operand0;
else
temp = gen_reg_rtx (mode);
+ /* Argh. The assembler and linker can't handle arithmetic
+ involving plabels. We'll have to split up operand1 here
+ if it's a function label involved in an arithmetic
+ expression. Luckily, this only happens with addition
+ of constants to plabels, which simplifies the test. */
+ if (GET_CODE (operand1) == CONST
+ && GET_CODE (XEXP (operand1, 0)) == PLUS
+ && function_label_operand (XEXP (XEXP (operand1, 0), 0),
+ Pmode))
+ {
+ /* Save away the constant part of the expression. */
+ const_part = XEXP (XEXP (operand1, 0), 1);
+ if (GET_CODE (const_part) != CONST_INT)
+ abort ();
+
+ /* Set operand1 to just the SYMBOL_REF. */
+ operand1 = XEXP (XEXP (operand1, 0), 0);
+ }
+
if (ishighonly)
set = gen_rtx (SET, mode, operand0, temp);
else
@@ -910,6 +932,12 @@ emit_move_sequence (operands, mode, scratch_reg)
temp,
gen_rtx (HIGH, mode, operand1)));
emit_insn (set);
+
+ /* Add back in the constant part if needed. */
+ if (const_part != NULL)
+ emit_insn (gen_rtx (SET, mode, operand0,
+ plus_constant (operand0,
+ XEXP (const_part, 0))));
return 1;
}
return 1;
@@ -3794,13 +3822,29 @@ hppa_encode_label (sym)
}
int
-function_label_operand (op, mode)
+function_label_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return GET_CODE (op) == SYMBOL_REF && FUNCTION_NAME_P (XSTR (op, 0));
}
+/* Returns 1 if OP is a function label involved in a simple addition
+ with a constant. Used to keep certain patterns from matching
+ during instruction combination. */
+int
+is_function_label_plus_const (op)
+ rtx op;
+{
+ /* Strip off any CONST. */
+ if (GET_CODE (op) == CONST)
+ op = XEXP (op, 0);
+
+ return (GET_CODE (op) == PLUS
+ && function_label_operand (XEXP (op, 0), Pmode)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT);
+}
+
/* Returns 1 if the 6 operands specified in OPERANDS are suitable for
use in fmpyadd instructions. */
int