diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0ae22cb8a01fd33b361694e0b0c17d0015604de6..7818fed3841370c692006fc7157182670467492a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-02-26 Eric Botcazou <ebotcazou@act-europe.fr> + + * config/sparc/sparc-protos.h (sparc_emit_floatunsdi): Add 'mode'. + (sparc_emit_fixunsdi): New prototype. + * config/sparc/sparc.c (sparc_emit_floatunsdi): Use 'mode' argument. + (sparc_emit_fixunsdi): New function. + * config/sparc/sparc.md (floatunsdisf2): Use 'general_operand' for + operand 1. Pass SFmode to sparc_emit_floatunsdi. + (floatunsdidf2): Use 'general_operand' for operand 1. Pass DFmode + to sparc_emit_floatunsdi. + (fixuns_truncsfdi2): New expander. + (fixuns_truncdfdi2): Likewise. + 2004-02-26 Alan Modra <amodra@bigpond.net.au> * gcse.c (delete_null_pointer_checks_1): Do not delete CC setter diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index cc164df2d78b2196730ef74b9579313b65f855e8..0908aaa5ea58f53ffbbfa0c8ad01c31ec539b4e2 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -63,7 +63,8 @@ extern enum machine_mode select_cc_mode (enum rtx_code, rtx, rtx); /* Define the function that build the compare insn for scc and bcc. */ extern rtx gen_compare_reg (enum rtx_code code, rtx, rtx); extern void sparc_emit_float_lib_cmp (rtx, rtx, enum rtx_code); -extern void sparc_emit_floatunsdi (rtx [2]); +extern void sparc_emit_floatunsdi (rtx [2], enum machine_mode); +extern void sparc_emit_fixunsdi (rtx [2], enum machine_mode); extern void emit_tfmode_binop (enum rtx_code, rtx *); extern void emit_tfmode_unop (enum rtx_code, rtx *); extern void emit_tfmode_cvt (enum rtx_code, rtx *); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 258dfc2d81e545d39f246a28ab5498f9de7a2706..079ed5d9d164a39078ef05efb7066f9e5abeb24c 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -6419,14 +6419,12 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison) optabs would emit if we didn't have TFmode patterns. */ void -sparc_emit_floatunsdi (rtx *operands) +sparc_emit_floatunsdi (rtx *operands, enum machine_mode mode) { rtx neglab, donelab, i0, i1, f0, in, out; - enum machine_mode mode; out = operands[0]; in = force_reg (DImode, operands[1]); - mode = GET_MODE (out); neglab = gen_label_rtx (); donelab = gen_label_rtx (); i0 = gen_reg_rtx (DImode); @@ -6450,6 +6448,47 @@ sparc_emit_floatunsdi (rtx *operands) emit_label (donelab); } +/* Generate an FP to unsigned DImode conversion. This is the same code + optabs would emit if we didn't have TFmode patterns. */ + +void +sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode) +{ + rtx neglab, donelab, i0, i1, f0, in, out, limit; + + out = operands[0]; + in = force_reg (mode, operands[1]); + neglab = gen_label_rtx (); + donelab = gen_label_rtx (); + i0 = gen_reg_rtx (DImode); + i1 = gen_reg_rtx (DImode); + limit = gen_reg_rtx (mode); + f0 = gen_reg_rtx (mode); + + emit_move_insn (limit, + CONST_DOUBLE_FROM_REAL_VALUE ( + REAL_VALUE_ATOF ("9223372036854775808.0", mode), mode)); + emit_cmp_and_jump_insns (in, limit, GE, NULL_RTX, mode, 0, neglab); + + emit_insn (gen_rtx_SET (VOIDmode, + out, + gen_rtx_FIX (DImode, gen_rtx_FIX (mode, in)))); + emit_jump_insn (gen_jump (donelab)); + emit_barrier (); + + emit_label (neglab); + + emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_MINUS (mode, in, limit))); + emit_insn (gen_rtx_SET (VOIDmode, + i0, + gen_rtx_FIX (DImode, gen_rtx_FIX (mode, f0)))); + emit_insn (gen_movdi (i1, const1_rtx)); + emit_insn (gen_ashldi3 (i1, i1, GEN_INT (63))); + emit_insn (gen_xordi3 (out, i0, i1)); + + emit_label (donelab); +} + /* Return the string to output a conditional branch to LABEL, testing register REG. LABEL is the operand number of the label; REG is the operand number of the reg. OP is the conditional expression. The mode diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 2a060b85be9cb421209aa922529c23eb7d9934ff..f0e69b173589ad458e2b6ad3a34b3851081241ce 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -4662,9 +4662,9 @@ (define_expand "floatunsdisf2" [(use (match_operand:SF 0 "register_operand" "")) - (use (match_operand:DI 1 "register_operand" ""))] + (use (match_operand:DI 1 "general_operand" ""))] "TARGET_ARCH64 && TARGET_FPU" - "sparc_emit_floatunsdi (operands); DONE;") + "sparc_emit_floatunsdi (operands, SFmode); DONE;") (define_insn "floatdidf2" [(set (match_operand:DF 0 "register_operand" "=e") @@ -4676,9 +4676,9 @@ (define_expand "floatunsdidf2" [(use (match_operand:DF 0 "register_operand" "")) - (use (match_operand:DI 1 "register_operand" ""))] + (use (match_operand:DI 1 "general_operand" ""))] "TARGET_ARCH64 && TARGET_FPU" - "sparc_emit_floatunsdi (operands); DONE;") + "sparc_emit_floatunsdi (operands, DFmode); DONE;") (define_expand "floatditf2" [(set (match_operand:TF 0 "nonimmediate_operand" "") @@ -4747,6 +4747,12 @@ [(set_attr "type" "fp") (set_attr "fptype" "double")]) +(define_expand "fixuns_truncsfdi2" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:SF 1 "general_operand" ""))] + "TARGET_ARCH64 && TARGET_FPU" + "sparc_emit_fixunsdi (operands, SFmode); DONE;") + (define_insn "fix_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "=e") (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "e"))))] @@ -4755,6 +4761,12 @@ [(set_attr "type" "fp") (set_attr "fptype" "double")]) +(define_expand "fixuns_truncdfdi2" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DF 1 "general_operand" ""))] + "TARGET_ARCH64 && TARGET_FPU" + "sparc_emit_fixunsdi (operands, DFmode); DONE;") + (define_expand "fix_trunctfdi2" [(set (match_operand:DI 0 "register_operand" "") (fix:DI (match_operand:TF 1 "general_operand" "")))] diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e86d65422cdd2486bb16e60a1f37a701c5c3404a..508a19247d5b49b86010bae2103d7a1fe3fa1cb1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-02-26 Eric Botcazou <ebotcazou@act-europe.fr> + + * gcc.dg/fixuns-trunc-1.c: New test. + 2004-02-26 John David Anglin <dave.anglin@nrc-cnrc.gc.ca> * gcc.dg/builtins-config.h: Use #elif. diff --git a/gcc/testsuite/gcc.dg/fixuns-trunc-1.c b/gcc/testsuite/gcc.dg/fixuns-trunc-1.c new file mode 100644 index 0000000000000000000000000000000000000000..0d0942952497ab6ba2afbc65085ce70c1d71dc3e --- /dev/null +++ b/gcc/testsuite/gcc.dg/fixuns-trunc-1.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-options "-std=c99" } */ + +unsigned long foo(double d) +{ + return (unsigned long) d; +} + +extern void abort(void); + +int main(void) +{ + double d; + unsigned long l; + +#ifdef __LP64__ + d = 9223372036854775808.7; + l = 1LL << 63; + + if (foo(d) != l) + abort(); +#endif + + d = 122485.2; + l = 122485; + + if (foo(d) != l) + abort(); + + return 0; +}