2002-02-04 Ulrich Weigand <uweigand@de.ibm.com>
+ * config/s390/s390-protos.h (legitimize_la_operand,
+ s390_secondary_input_reload_class, s390_plus_operand,
+ s390_expand_plus_operand): Add prototypes.
+
+ config/s390/s390.c (s390_secondary_input_reload_class,
+ s390_plus_operand, s390_expand_plus_operand): New functions.
+
+ (struct s390_address): New member 'pointer'.
+ (s390_decompose_address): Compute it.
+ (legitimate_la_operand_p): Use it.
+ (legitimize_la_operand): New function.
+ (movti, movdi, movdf splitters): Call it.
+
+ config/s390/s390.h (SECONDARY_INPUT_RELOAD_CLASS): Define.
+ (PREDICATE_CODES): Add s390_plus_operand.
+
+ config/s390/s390.md (adddi3_inv_64, addaddr_ccclobber): Delete.
+ (la_ccclobber): Allow GENERAL_REGS as output operand.
+
+ (reload_load_address, *reload_load_address_reg_0, *la, *do_la_reg_0,
+ *reload_la_64, *reload_la_31 and splitters): Delete, replace by ...
+ (*la_64, *la_31, reload_indi, reload_insi): ... these.
+
+2002-02-04 Ulrich Weigand <uweigand@de.ibm.com>
+
* gcc/config/s390/s390.h (CRT_CALL_STATIC_FUNCTION): Fixed
register names for regular asm () construct.
extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx));
extern int symbolic_reference_mentioned_p PARAMS ((rtx));
extern int legitimate_la_operand_p PARAMS ((rtx));
+extern rtx legitimize_la_operand PARAMS ((rtx));
extern int legitimate_pic_operand_p PARAMS ((rtx));
extern int legitimate_constant_p PARAMS ((rtx));
extern int legitimate_reload_constant_p PARAMS ((rtx));
extern rtx legitimize_pic_address PARAMS ((rtx, rtx));
extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
extern enum reg_class s390_preferred_reload_class PARAMS ((rtx, enum reg_class));
+extern enum reg_class s390_secondary_input_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx));
+extern int s390_plus_operand PARAMS ((rtx, enum machine_mode));
+extern void s390_expand_plus_operand PARAMS ((rtx, rtx, rtx));
extern void emit_pic_move PARAMS ((rtx *, enum machine_mode));
extern void s390_output_symbolic_const PARAMS ((FILE *, rtx));
rtx base;
rtx indx;
rtx disp;
+ int pointer;
};
/* Structure containing information for prologue and epilogue. */
return class;
}
+/* Return the register class of a scratch register needed to
+ load IN into a register of class CLASS in MODE.
+
+ We need a temporary when loading a PLUS expression which
+ is not a legitimate operand of the LOAD ADDRESS instruction. */
+
+enum reg_class
+s390_secondary_input_reload_class (class, mode, in)
+ enum reg_class class ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
+ rtx in;
+{
+ if (s390_plus_operand (in, mode))
+ return ADDR_REGS;
+
+ return NO_REGS;
+}
+
+/* Return true if OP is a PLUS that is not a legitimate
+ operand for the LA instruction.
+ OP is the current operation.
+ MODE is the current operation mode. */
+
+int
+s390_plus_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (!check_mode (op, &mode) || mode != Pmode)
+ return FALSE;
+
+ if (GET_CODE (op) != PLUS)
+ return FALSE;
+
+ if (legitimate_la_operand_p (op))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Generate code to load SRC, which is PLUS that is not a
+ legitimate operand for the LA instruction, into TARGET.
+ SCRATCH may be used as scratch register. */
+
+void
+s390_expand_plus_operand (target, src, scratch)
+ register rtx target;
+ register rtx src;
+ register rtx scratch;
+{
+ /* src must be a PLUS; get its two operands. */
+ rtx sum1, sum2;
+
+ if (GET_CODE (src) != PLUS || GET_MODE (src) != Pmode)
+ abort ();
+
+ sum1 = XEXP (src, 0);
+ sum2 = XEXP (src, 1);
+
+ /* If one of the two operands is equal to the target,
+ make it the first one. */
+ if (rtx_equal_p (target, sum2))
+ {
+ sum2 = XEXP (src, 0);
+ sum1 = XEXP (src, 1);
+ }
+
+ /* If the first operand is not an address register,
+ we reload it into the target. */
+ if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15)
+ {
+ emit_move_insn (target, sum1);
+ sum1 = target;
+ }
+
+ /* Likewise for the second operand. However, take
+ care not to clobber the target if we already used
+ it for the first operand. Use the scratch instead. */
+ if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15)
+ {
+ if (!rtx_equal_p (target, sum1))
+ {
+ emit_move_insn (target, sum2);
+ sum2 = target;
+ }
+ else
+ {
+ emit_move_insn (scratch, sum2);
+ sum2 = scratch;
+ }
+ }
+
+ /* Emit the LOAD ADDRESS pattern. Note that reload of PLUS
+ is only ever performed on addresses, so we can mark the
+ sum as legitimate for LA in any case. */
+ src = gen_rtx_PLUS (Pmode, sum1, sum2);
+ src = legitimize_la_operand (src);
+ emit_insn (gen_rtx_SET (VOIDmode, target, src));
+}
+
+
/* Decompose a RTL expression ADDR for a memory address into
its components, returned in OUT. The boolean STRICT
specifies whether strict register checking applies.
rtx base = NULL_RTX;
rtx indx = NULL_RTX;
rtx disp = NULL_RTX;
+ int pointer = FALSE;
/* Decompose address into base + index + displacement. */
if (XVECLEN (base, 0) != 1 || XINT (base, 1) != 101)
return FALSE;
base = XVECEXP (base, 0, 0);
+ pointer = TRUE;
}
if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
|| (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
return FALSE;
+
+ if (REGNO (base) == BASE_REGISTER
+ || REGNO (base) == STACK_POINTER_REGNUM
+ || REGNO (base) == FRAME_POINTER_REGNUM
+ || ((reload_completed || reload_in_progress)
+ && frame_pointer_needed
+ && REGNO (base) == HARD_FRAME_POINTER_REGNUM)
+ || (flag_pic
+ && REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
+ pointer = TRUE;
}
/* Validate index register. */
if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != 101)
return FALSE;
indx = XVECEXP (indx, 0, 0);
+ pointer = TRUE;
}
if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
if ((strict && ! REG_OK_FOR_BASE_STRICT_P (indx))
|| (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (indx)))
return FALSE;
+
+ if (REGNO (indx) == BASE_REGISTER
+ || REGNO (indx) == STACK_POINTER_REGNUM
+ || REGNO (indx) == FRAME_POINTER_REGNUM
+ || ((reload_completed || reload_in_progress)
+ && frame_pointer_needed
+ && REGNO (indx) == HARD_FRAME_POINTER_REGNUM)
+ || (flag_pic
+ && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
+ pointer = TRUE;
}
/* Validate displacement. */
{
if (flag_pic != 1)
return FALSE;
+
+ pointer = TRUE;
}
/* We can convert literal pool addresses to
if (offset)
disp = plus_constant (disp, offset);
+
+ pointer = TRUE;
}
}
+ if (!base && !indx)
+ pointer = TRUE;
+
if (out)
{
out->base = base;
out->indx = indx;
out->disp = disp;
+ out->pointer = pointer;
}
return TRUE;
if (!s390_decompose_address (op, &addr, FALSE))
return FALSE;
- if (TARGET_64BIT)
+ if (TARGET_64BIT || addr.pointer)
return TRUE;
- /* Use of the base or stack pointer implies address. */
+ return FALSE;
+}
- if (addr.base && GET_CODE (addr.base) == REG)
- {
- if (REGNO (addr.base) == BASE_REGISTER
- || REGNO (addr.base) == STACK_POINTER_REGNUM
- || REGNO (addr.base) == FRAME_POINTER_REGNUM)
- return TRUE;
- }
+/* Return a modified variant of OP that is guaranteed to
+ be accepted by legitimate_la_operand_p. */
- if (addr.indx && GET_CODE (addr.indx) == REG)
- {
- if (REGNO (addr.indx) == BASE_REGISTER
- || REGNO (addr.indx) == STACK_POINTER_REGNUM
- || REGNO (addr.base) == FRAME_POINTER_REGNUM)
- return TRUE;
- }
+rtx
+legitimize_la_operand (op)
+ register rtx op;
+{
+ struct s390_address addr;
+ if (!s390_decompose_address (op, &addr, FALSE))
+ abort ();
- return FALSE;
+ if (TARGET_64BIT || addr.pointer)
+ return op;
+
+ if (!addr.base)
+ abort ();
+
+ op = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr.base), 101);
+ if (addr.indx)
+ op = gen_rtx_PLUS (Pmode, op, addr.indx);
+ if (addr.disp)
+ op = gen_rtx_PLUS (Pmode, op, addr.disp);
+
+ return op;
}
/* Return a legitimate reference for ORIG (an address) using the
(GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) : \
(GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+/* We need a secondary reload when loading a PLUS which is
+ not a valid operand for LOAD ADDRESS. */
+
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \
+ s390_secondary_input_reload_class ((CLASS), (MODE), (IN))
+
/* If we are copying between FP registers and anything else, we need a memory
location. */
{"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \
{"load_multiple_operation", {PARALLEL}}, \
{"store_multiple_operation", {PARALLEL}}, \
- {"const0_operand", { CONST_INT, CONST_DOUBLE }},
+ {"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
+ {"s390_plus_operand", { PLUS }},
/* S/390 constant pool breaks the devices in crtstuff.c to control section
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (mem:TI (match_dup 2)))]
"operands[2] = operand_subword (operands[0], 1, 0, TImode);
- operands[3] = XEXP (operands[1], 0);")
+ operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
;
; movdi instruction pattern(s).
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (mem:DI (match_dup 2)))]
"operands[2] = operand_subword (operands[0], 1, 0, DImode);
- operands[3] = XEXP (operands[1], 0);")
+ operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
;
; movsi instruction pattern(s).
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (mem:DI (match_dup 2)))]
"operands[2] = operand_subword (operands[0], 1, 0, DFmode);
- operands[3] = XEXP (operands[1], 0);")
+ operands[3] = legitimize_la_operand (XEXP (operands[1], 0));")
;
; movsf instruction pattern(s).
[(set_attr "op_type" "RRE,RI,RXE")
(set_attr "atype" "reg,reg,mem")])
-;
-; For weakness of reload, need (set (reg x) (plus (reg y) (reg x)))
-;
-
-(define_insn "adddi3_inv_64"
- [(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (plus:DI (match_operand:DI 1 "general_operand" "%d,K,m")
- (match_operand:DI 2 "register_operand" "0,0,0") ) )
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "@
- agr\\t%0,%1
- aghi\\t%0,%h1
- ag\\t%0,%1"
- [(set_attr "op_type" "RRE,RI,RXE")
- (set_attr "atype" "reg,reg,mem")])
-
(define_insn "adddi3_31"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(plus:DI (match_operand:DI 1 "register_operand" "0,0")
DONE;
}")
-(define_insn "reload_load_address"
- [(set (match_operand:DI 0 "register_operand" "=a")
+(define_insn "*la_64"
+ [(set (match_operand:DI 0 "register_operand" "=d")
(match_operand:QI 1 "address_operand" "p"))]
"TARGET_64BIT"
"la\\t%0,%a1"
(set_attr "atype" "mem")
(set_attr "type" "la")])
-(define_insn "*reload_load_address_reg_0"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (plus:DI (match_operand:DI 1 "register_operand" "%0")
- (match_operand:DI 2 "register_operand" "d")))]
+(define_expand "reload_indi"
+ [(parallel [(match_operand:DI 0 "register_operand" "=a")
+ (match_operand:DI 1 "s390_plus_operand" "")
+ (match_operand:DI 2 "register_operand" "=&a")])]
"TARGET_64BIT"
- "brxlg\\t%0,%2,.+6"
- [(set_attr "op_type" "RIE")
- (set_attr "atype" "reg")])
-
-(define_insn "*reload_la_64"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (plus:DI (match_operand:DI 1 "general_operand" "g")
- (match_operand:DI 2 "general_operand" "g")))]
- "TARGET_64BIT && reload_in_progress
- && !address_operand (gen_rtx_PLUS (DImode, operands[1], operands[2]), QImode)
- && !rtx_equal_p (operands[0], operands[1])
- && !rtx_equal_p (operands[0], operands[2])"
- "#")
-
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (plus:DI (match_operand:DI 1 "general_operand" "")
- (match_operand:DI 2 "register_operand" "")))]
- "TARGET_64BIT && reload_completed
- && !address_operand (gen_rtx_PLUS (DImode, operands[1], operands[2]), QImode)
- && !rtx_equal_p (operands[0], operands[1])
- && !rtx_equal_p (operands[0], operands[2])"
- [(set (match_dup 0) (match_dup 1))
- (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))]
"
{
- if (CONSTANT_P (operands[1])
- && !legitimate_reload_constant_p (operands[1]))
- operands[1] = force_const_mem (DImode, operands[1]);
+ s390_expand_plus_operand (operands[0], operands[1], operands[2]);
+ DONE;
}")
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (plus:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "general_operand" "")))]
- "TARGET_64BIT && reload_completed
- && !address_operand (gen_rtx_PLUS (DImode, operands[1], operands[2]), QImode)
- && !rtx_equal_p (operands[0], operands[1])
- && !rtx_equal_p (operands[0], operands[2])"
- [(set (match_dup 0) (match_dup 2))
- (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1)))]
- "
-{
- if (CONSTANT_P (operands[2])
- && !legitimate_reload_constant_p (operands[2]))
- operands[2] = force_const_mem (DImode, operands[2]);
-}")
;
; addsi3 instruction pattern(s).
;
(define_insn "*la_ccclobber"
- [(set (match_operand:SI 0 "register_operand" "=a")
+ [(set (match_operand:SI 0 "register_operand" "=d")
(match_operand:QI 1 "address_operand" "p"))
(clobber (reg:CC 33))]
"legitimate_la_operand_p (operands[1])"
(set_attr "atype" "mem")
(set_attr "type" "la")])
-(define_insn "*addaddr_ccclobber"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (plus:SI (match_operand:SI 1 "register_operand" "%a,a")
- (match_operand:SI 2 "nonmemory_operand" "J,a")))
- (clobber (reg:CC 33))]
- "(((REGNO (operands[1]) == STACK_POINTER_REGNUM ) ||
- (REGNO (operands[1]) == FRAME_POINTER_REGNUM ) ||
- (REGNO (operands[1]) == BASE_REGISTER)) &&
- (GET_CODE (operands[2]) == REG ||
- CONST_OK_FOR_LETTER_P (INTVAL (operands[2]),'J')))"
- "@
- la\\t%0,%c2(,%1)
- la\\t%0,0(%1,%2)"
- [(set_attr "op_type" "RX")
- (set_attr "atype" "mem")
- (set_attr "type" "la")])
-
(define_insn "*addsi3_cc"
[(set (reg 33)
(compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
[(set_attr "op_type" "RR,RI,RX")
(set_attr "atype" "reg,reg,mem")])
-(define_insn "*la"
- [(set (match_operand:SI 0 "register_operand" "=a")
+(define_insn "*la_31"
+ [(set (match_operand:SI 0 "register_operand" "=d")
(match_operand:QI 1 "address_operand" "p"))]
- "reload_in_progress || reload_completed
- || legitimate_la_operand_p (operands[1])"
+ "legitimate_la_operand_p (operands[1])"
"la\\t%0,%a1"
[(set_attr "op_type" "RX")
(set_attr "atype" "mem")
(set_attr "type" "la")])
-(define_insn "*do_la_reg_0"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (plus:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "d")))]
- "reload_in_progress || reload_completed"
- "brxle\\t%0,%2,.+4"
- [(set_attr "op_type" "RSI")
- (set_attr "atype" "reg")])
-
-(define_insn "*reload_la_31"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (plus:SI (match_operand:SI 1 "general_operand" "g")
- (match_operand:SI 2 "general_operand" "g")))]
- "reload_in_progress
- && !address_operand (gen_rtx_PLUS (SImode, operands[1], operands[2]), QImode)
- && !rtx_equal_p (operands[0], operands[1])
- && !rtx_equal_p (operands[0], operands[2])"
- "#")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (plus:SI (match_operand:SI 1 "general_operand" "")
- (match_operand:SI 2 "register_operand" "")))]
- "reload_completed
- && !address_operand (gen_rtx_PLUS (SImode, operands[1], operands[2]), QImode)
- && !rtx_equal_p (operands[0], operands[1])
- && !rtx_equal_p (operands[0], operands[2])"
- [(set (match_dup 0) (match_dup 1))
- (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))]
- "
-{
- if (CONSTANT_P (operands[1])
- && !legitimate_reload_constant_p (operands[1]))
- operands[1] = force_const_mem (SImode, operands[1]);
-}")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (plus:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "general_operand" "")))]
- "reload_completed
- && !address_operand (gen_rtx_PLUS (SImode, operands[1], operands[2]), QImode)
- && !rtx_equal_p (operands[0], operands[1])
- && !rtx_equal_p (operands[0], operands[2])"
- [(set (match_dup 0) (match_dup 2))
- (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
+(define_expand "reload_insi"
+ [(parallel [(match_operand:SI 0 "register_operand" "=a")
+ (match_operand:SI 1 "s390_plus_operand" "")
+ (match_operand:SI 2 "register_operand" "=&a")])]
+ "!TARGET_64BIT"
"
{
- if (CONSTANT_P (operands[2])
- && !legitimate_reload_constant_p (operands[2]))
- operands[2] = force_const_mem (SImode, operands[2]);
+ s390_expand_plus_operand (operands[0], operands[1], operands[2]);
+ DONE;
}")