From 6219012805548899fb34a29ca4f16cf9ddc7c0ad Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 10 Dec 1999 04:08:51 -0800 Subject: [PATCH] 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 --- gcc/ChangeLog | 17 ++ gcc/config/sparc/sparc-protos.h | 3 + gcc/config/sparc/sparc.c | 83 ++++++++++ gcc/config/sparc/sparc.h | 49 ++++-- gcc/config/sparc/sparc.md | 280 ++++++++++++++++++++------------ gcc/md.texi | 14 +- 6 files changed, 329 insertions(+), 117 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d595ca914a9..42204f48418 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +1999-12-10 David S. Miller + + * 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 * c-common.c (c_common_nodes_and_builtins): diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index c7616696fb5..8c5b1b1a82b 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -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)); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 072e7e694ac..9c5380d574a 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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) diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 4387fc88ee5..c949c3eea2d 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -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}}, \ diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 25951f07ecc..b7025a860ce 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -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" ""))] diff --git a/gcc/md.texi b/gcc/md.texi index 483016794c8..067d464d46c 100644 --- a/gcc/md.texi +++ b/gcc/md.texi @@ -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