sparc.c (fp_sethi_p, [...]): New functions.

* config/sparc/sparc.c (fp_sethi_p, fp_mov_p, fp_high_losum_p):
	New functions.
	* config/sparc/sparc-protos.h: Add them.
	* config/sparc/sparc.h: Add them to PREDICATE_CODES.
	(EXTRA_CONSTRAINT_BASE): New macro, handling Q, R, and S
	constraints which use those helpers.
	(EXTRA_CONSTRAINT): Use this new macro.
	* md.texi: Update sparc target constraints documentation.
	* config/sparc/sparc.md (clear_sf, clear_sfp, movsf_const_intreg,
	movsf_const_high, movsf_const_lo, movsf_insn): Delete.
	(movsf_insn_novis_liveg0, movsf_insn_novis_noliveg0,
	movsf_insn_vis, movsf_lo_sum, movsf_high): New patterns.
	(movsf high/lo_sum split): Rework for new patterns.
	(movsf expander): Allow storing fp_zero to memory if ! live_g0.

From-SVN: r30857
This commit is contained in:
David S. Miller 1999-12-10 04:08:51 -08:00 committed by David S. Miller
parent acce043733
commit 6219012805
6 changed files with 329 additions and 117 deletions

View File

@ -1,3 +1,20 @@
1999-12-10 David S. Miller <davem@redhat.com>
* config/sparc/sparc.c (fp_sethi_p, fp_mov_p, fp_high_losum_p):
New functions.
* config/sparc/sparc-protos.h: Add them.
* config/sparc/sparc.h: Add them to PREDICATE_CODES.
(EXTRA_CONSTRAINT_BASE): New macro, handling Q, R, and S
constraints which use those helpers.
(EXTRA_CONSTRAINT): Use this new macro.
* md.texi: Update sparc target constraints documentation.
* config/sparc/sparc.md (clear_sf, clear_sfp, movsf_const_intreg,
movsf_const_high, movsf_const_lo, movsf_insn): Delete.
(movsf_insn_novis_liveg0, movsf_insn_novis_noliveg0,
movsf_insn_vis, movsf_lo_sum, movsf_high): New patterns.
(movsf high/lo_sum split): Rework for new patterns.
(movsf expander): Allow storing fp_zero to memory if ! live_g0.
1999-12-09 Gavin Romig-Koch <gavin@cetus.cygnus.com>
* c-common.c (c_common_nodes_and_builtins):

View File

@ -124,6 +124,9 @@ extern int emit_move_sequence PARAMS ((rtx, enum machine_mode));
extern int extend_op PARAMS ((rtx, enum machine_mode));
extern int fcc_reg_operand PARAMS ((rtx, enum machine_mode));
extern int fp_zero_operand PARAMS ((rtx));
extern int fp_sethi_p PARAMS ((rtx));
extern int fp_mov_p PARAMS ((rtx));
extern int fp_high_losum_p PARAMS ((rtx));
extern int icc_or_fcc_reg_operand PARAMS ((rtx, enum machine_mode));
extern int label_ref_operand PARAMS ((rtx, enum machine_mode));
extern int mem_min_alignment PARAMS ((rtx, int));

View File

@ -406,6 +406,85 @@ fp_zero_operand (op)
return (REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r));
}
/* Nonzero if OP is a floating point constant which can
be loaded into an integer register using a single
sethi instruction. */
int
fp_sethi_p (op)
rtx op;
{
if (GET_CODE (op) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
if (REAL_VALUES_EQUAL (r, dconst0) &&
! REAL_VALUE_MINUS_ZERO (r))
return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (SPARC_SETHI_P (i))
return 1;
}
return 0;
}
/* Nonzero if OP is a floating point constant which can
be loaded into an integer register using a single
mov instruction. */
int
fp_mov_p (op)
rtx op;
{
if (GET_CODE (op) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
if (REAL_VALUES_EQUAL (r, dconst0) &&
! REAL_VALUE_MINUS_ZERO (r))
return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (SPARC_SIMM13_P (i))
return 1;
}
return 0;
}
/* Nonzero if OP is a floating point constant which can
be loaded into an integer register using a high/losum
instruction sequence. */
int
fp_high_losum_p (op)
rtx op;
{
/* The constraints calling this should only be in
SFmode move insns, so any constant which cannot
be moved using a single insn will do. */
if (GET_CODE (op) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
if (REAL_VALUES_EQUAL (r, dconst0) &&
! REAL_VALUE_MINUS_ZERO (r))
return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (! SPARC_SETHI_P (i)
&& ! SPARC_SIMM13_P (i))
return 1;
}
return 0;
}
/* Nonzero if OP is an integer register. */
int
@ -1112,6 +1191,10 @@ input_operand (op, mode)
if (register_operand (op, mode))
return 1;
if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_CODE (op) == CONST_DOUBLE)
return 1;
/* If this is a SUBREG, look inside so that we handle
paradoxical ones. */
if (GET_CODE (op) == SUBREG)

View File

@ -2283,12 +2283,27 @@ LFLGRET"ID":\n\
/* Optional extra constraints for this machine.
'Q' handles floating point constants which can be moved into
an integer register with a single sethi instruction.
'R' handles floating point constants which can be moved into
an integer register with a single mov instruction.
'S' handles floating point constants which can be moved into
an integer register using a high/lo_sum sequence.
'T' handles memory addresses where the alignment is known to
be at least 8 bytes.
`U' handles all pseudo registers or a hard even numbered
integer register, needed for ldd/std instructions. */
#define EXTRA_CONSTRAINT_BASE(OP, C) \
((C) == 'Q' ? fp_sethi_p(OP) \
: (C) == 'R' ? fp_mov_p(OP) \
: (C) == 'S' ? fp_high_losum_p(OP) \
: 0)
#ifndef REG_OK_STRICT
/* Nonzero if X is a hard reg that can be used as an index
@ -2303,12 +2318,13 @@ LFLGRET"ID":\n\
/* 'T', 'U' are for aligned memory loads which aren't needed for v9. */
#define EXTRA_CONSTRAINT(OP, C) \
((! TARGET_ARCH64 && (C) == 'T') \
? (mem_min_alignment (OP, 8)) \
: ((! TARGET_ARCH64 && (C) == 'U') \
? (register_ok_for_ldd (OP)) \
: 0))
(EXTRA_CONSTRAINT_BASE(OP, C) \
|| ((! TARGET_ARCH64 && (C) == 'T') \
? (mem_min_alignment (OP, 8)) \
: ((! TARGET_ARCH64 && (C) == 'U') \
? (register_ok_for_ldd (OP)) \
: 0)))
#else
/* Nonzero if X is a hard reg that can be used as an index. */
@ -2317,14 +2333,16 @@ LFLGRET"ID":\n\
#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
#define EXTRA_CONSTRAINT(OP, C) \
((! TARGET_ARCH64 && (C) == 'T') \
? mem_min_alignment (OP, 8) && strict_memory_address_p (Pmode, XEXP (OP, 0)) \
: ((! TARGET_ARCH64 && (C) == 'U') \
? (GET_CODE (OP) == REG \
&& (REGNO (OP) < FIRST_PSEUDO_REGISTER \
|| reg_renumber[REGNO (OP)] >= 0) \
&& register_ok_for_ldd (OP)) \
: 0))
(EXTRA_CONSTRAINT_BASE(OP, C) \
|| ((! TARGET_ARCH64 && (C) == 'T') \
? mem_min_alignment (OP, 8) && strict_memory_address_p (Pmode, XEXP (OP, 0)) \
: ((! TARGET_ARCH64 && (C) == 'U') \
? (GET_CODE (OP) == REG \
&& (REGNO (OP) < FIRST_PSEUDO_REGISTER \
|| reg_renumber[REGNO (OP)] >= 0) \
&& register_ok_for_ldd (OP)) \
: 0)))
#endif
/* Should gcc use [%reg+%lo(xx)+offset] addresses? */
@ -3309,6 +3327,9 @@ do { \
#define PREDICATE_CODES \
{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"fp_zero_operand", {CONST_DOUBLE}}, \
{"fp_sethi_p", {CONST_DOUBLE}}, \
{"fp_mov_p", {CONST_DOUBLE}}, \
{"fp_high_losum_p", {CONST_DOUBLE}}, \
{"intreg_operand", {SUBREG, REG}}, \
{"fcc_reg_operand", {REG}}, \
{"icc_or_fcc_reg_operand", {REG}}, \

View File

@ -37,12 +37,10 @@
;; 9 sethh
;; 10 setlm
;; 11 embmedany_sethi, embmedany_brsum
;; 12 movsf_const_high
;; 13 embmedany_textuhi
;; 14 embmedany_texthi
;; 15 embmedany_textulo
;; 16 embmedany_textlo
;; 17 movsf_const_lo
;; 18 sethm
;; 19 setlo
;;
@ -2820,83 +2818,165 @@
;; Floating point move insns
(define_insn "*clear_sf"
[(set (match_operand:SF 0 "register_operand" "=f")
(match_operand:SF 1 "const_double_operand" ""))]
"TARGET_VIS
&& fp_zero_operand (operands[1])"
"fzeros\\t%0"
[(set_attr "type" "fpmove")
(define_insn "*movsf_insn_novis_liveg0"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,*r,*r,*r,*r,*r,f,m,m")
(match_operand:SF 1 "input_operand" "f,G,Q,*rR,S,m,m,f,*r"))]
"(TARGET_FPU && ! TARGET_VIS && TARGET_LIVE_G0)
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
"*
{
if (GET_CODE (operands[1]) == CONST_DOUBLE
&& (which_alternative == 2
|| which_alternative == 3
|| which_alternative == 4))
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, i);
operands[1] = GEN_INT (i);
}
switch (which_alternative)
{
case 0:
return \"fmovs\\t%1, %0\";
case 1:
return \"and\\t%0, 0, %0\";
case 2:
return \"sethi\\t%%hi(%a1), %0\";
case 3:
return \"mov\\t%1, %0\";
case 4:
return \"#\";
case 5:
case 6:
return \"ld\\t%1, %0\";
case 7:
case 8:
return \"st\\t%1, %0\";
}
}"
[(set_attr "type" "fpmove,move,move,move,*,load,fpload,fpstore,store")
(set_attr "length" "1")])
(define_insn "*clear_sfp"
[(set (match_operand:SF 0 "memory_operand" "=m")
(match_operand:SF 1 "const_double_operand" ""))]
"! TARGET_LIVE_G0
&& fp_zero_operand (operands[1])"
"st\\t%%g0, %0"
[(set_attr "type" "store")
(define_insn "*movsf_insn_novis_noliveg0"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,*r,*r,*r,*r,*r,f,m,m")
(match_operand:SF 1 "input_operand" "f,G,Q,*rR,S,m,m,f,*rG"))]
"(TARGET_FPU && ! TARGET_VIS && ! TARGET_LIVE_G0)
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)
|| fp_zero_operand (operands[1]))"
"*
{
if (GET_CODE (operands[1]) == CONST_DOUBLE
&& (which_alternative == 2
|| which_alternative == 3
|| which_alternative == 4))
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, i);
operands[1] = GEN_INT (i);
}
switch (which_alternative)
{
case 0:
return \"fmovs\\t%1, %0\";
case 1:
return \"clr\\t%0\";
case 2:
return \"sethi\\t%%hi(%a1), %0\";
case 3:
return \"mov\\t%1, %0\";
case 4:
return \"#\";
case 5:
case 6:
return \"ld\\t%1, %0\";
case 7:
case 8:
return \"st\\t%r1, %0\";
}
}"
[(set_attr "type" "fpmove,move,move,move,*,load,fpload,fpstore,store")
(set_attr "length" "1")])
(define_insn "*movsf_const_intreg"
[(set (match_operand:SF 0 "register_operand" "=f,r")
(match_operand:SF 1 "const_double_operand" "m#F,F"))]
"TARGET_FPU"
(define_insn "*movsf_insn_vis"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,*r,*r,*r,f,m,m")
(match_operand:SF 1 "input_operand" "f,G,G,Q,*rR,S,m,m,f,*rG"))]
"(TARGET_FPU && TARGET_VIS)
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)
|| fp_zero_operand (operands[1]))"
"*
{
if (GET_CODE (operands[1]) == CONST_DOUBLE
&& (which_alternative == 3
|| which_alternative == 4
|| which_alternative == 5))
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, i);
operands[1] = GEN_INT (i);
}
switch (which_alternative)
{
case 0:
return \"fmovs\\t%1, %0\";
case 1:
return \"fzeros\\t%0\";
case 2:
return \"clr\\t%0\";
case 3:
return \"sethi\\t%%hi(%a1), %0\";
case 4:
return \"mov\\t%1, %0\";
case 5:
return \"#\";
case 6:
case 7:
return \"ld\\t%1, %0\";
case 8:
case 9:
return \"st\\t%r1, %0\";
}
}"
[(set_attr "type" "fpmove,fpmove,move,move,move,*,load,fpload,fpstore,store")
(set_attr "length" "1")])
(define_insn "*movsf_lo_sum"
[(set (match_operand:SF 0 "register_operand" "")
(lo_sum:SF (match_operand:SF 1 "register_operand" "")
(match_operand:SF 2 "const_double_operand" "")))]
"TARGET_FPU && fp_high_losum_p (operands[2])"
"*
{
REAL_VALUE_TYPE r;
long i;
if (which_alternative == 0)
return \"ld\\t%1, %0\";
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[2]);
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (SPARC_SIMM13_P (i) || SPARC_SETHI_P (i))
{
operands[1] = GEN_INT (i);
if (SPARC_SIMM13_P (INTVAL (operands[1])))
return \"mov\\t%1, %0\";
else if (SPARC_SETHI_P (INTVAL (operands[1])))
return \"sethi\\t%%hi(%a1), %0\";
else
abort ();
}
else
return \"#\";
operands[2] = GEN_INT (i);
return \"or\\t%1, %%lo(%a2), %0\";
}"
[(set_attr "type" "move")
(set_attr "length" "1,2")])
;; There isn't much I can do about this, if I change the
;; mode then flow info gets really confused because the
;; destination no longer looks the same. Ho hum...
(define_insn "*movsf_const_high"
[(set (match_operand:SF 0 "register_operand" "=r")
(unspec:SF [(match_operand 1 "const_int_operand" "")] 12))]
""
"sethi\\t%%hi(%a1), %0"
[(set_attr "type" "move")
[(set_attr "type" "ialu")
(set_attr "length" "1")])
(define_insn "*movsf_const_lo"
[(set (match_operand:SF 0 "register_operand" "=r")
(unspec:SF [(match_operand:SF 1 "register_operand" "r")
(match_operand 2 "const_int_operand" "")] 17))]
""
"or\\t%1, %%lo(%a2), %0"
[(set_attr "type" "move")
(set_attr "length" "1")])
(define_split
(define_insn "*movsf_high"
[(set (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "const_double_operand" ""))]
"TARGET_FPU
&& (GET_CODE (operands[0]) == REG
&& REGNO (operands[0]) < 32)"
[(set (match_dup 0) (unspec:SF [(match_dup 1)] 12))
(set (match_dup 0) (unspec:SF [(match_dup 0) (match_dup 1)] 17))]
"
(high:SF (match_operand:SF 1 "const_double_operand" "")))]
"TARGET_FPU && fp_high_losum_p (operands[1])"
"*
{
REAL_VALUE_TYPE r;
long i;
@ -2904,7 +2984,37 @@
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, i);
operands[1] = GEN_INT (i);
}")
return \"sethi\\t%%hi(%1), %0\";
}"
[(set_attr "type" "move")
(set_attr "length" "1")])
(define_split
[(set (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "const_double_operand" ""))]
"TARGET_FPU
&& fp_high_losum_p (operands[1])
&& (GET_CODE (operands[0]) == REG
&& REGNO (operands[0]) < 32)"
[(set (match_dup 0) (high:SF (match_dup 1)))
(set (match_dup 0) (lo_sum:SF (match_dup 0) (match_dup 1)))])
;; Exactly the same as above, except that all `f' cases are deleted.
;; This is necessary to prevent reload from ever trying to use a `f' reg
;; when -mno-fpu.
(define_insn "*movsf_no_f_insn"
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
(match_operand:SF 1 "input_operand" "r,m,r"))]
"! TARGET_FPU
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
"@
mov\\t%1, %0
ld\\t%1, %0
st\\t%1, %0"
[(set_attr "type" "move,load,store")
(set_attr "length" "1")])
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
@ -2933,7 +3043,10 @@
/* Handle sets of MEM first. */
if (GET_CODE (operands[0]) == MEM)
{
if (register_operand (operands[1], SFmode))
if (register_operand (operands[1], SFmode)
|| (! TARGET_LIVE_G0
&& GET_CODE (operands[1]) == CONST_DOUBLE
&& fp_zero_operand (operands[1])))
goto movsf_is_ok;
if (! reload_in_progress)
@ -2964,39 +3077,6 @@
;
}")
(define_insn "*movsf_insn"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,m,r,r,m")
(match_operand:SF 1 "input_operand" "f,m,f,r,m,r"))]
"TARGET_FPU
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
"@
fmovs\\t%1, %0
ld\\t%1, %0
st\\t%1, %0
mov\\t%1, %0
ld\\t%1, %0
st\\t%1, %0"
[(set_attr "type" "fpmove,fpload,fpstore,move,load,store")
(set_attr "length" "1")])
;; Exactly the same as above, except that all `f' cases are deleted.
;; This is necessary to prevent reload from ever trying to use a `f' reg
;; when -mno-fpu.
(define_insn "*movsf_no_f_insn"
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
(match_operand:SF 1 "input_operand" "r,m,r"))]
"! TARGET_FPU
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
"@
mov\\t%1, %0
ld\\t%1, %0
st\\t%1, %0"
[(set_attr "type" "move,load,store")
(set_attr "length" "1")])
(define_insn "*clear_df"
[(set (match_operand:DF 0 "register_operand" "=e")
(match_operand:DF 1 "const_double_operand" ""))]

View File

@ -1621,11 +1621,19 @@ Floating-point zero
Signed 13 bit constant, sign-extended to 32 or 64 bits
@item Q
Memory reference that can be loaded with one instruction (@samp{m} is
more appropriate for @code{asm} statements)
Floating-point constant whose integral representation can
be moved into an integer register using a single sethi
instruction
@item R
Floating-point constant whose integral representation can
be moved into an integer register using a single mov
instruction
@item S
Constant, or memory address
Floating-point constant whose integral representation can
be moved into an integer register using a high/lo_sum
instruction sequence
@item T
Memory address aligned to an 8-byte boundary