From 520b7351be5faa46c4df91b47eaa7bf9196a6aef Mon Sep 17 00:00:00 2001
From: ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu, 26 Feb 2004 18:40:41 +0000
Subject: [PATCH] 	* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@78511 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                         | 13 ++++++++
 gcc/config/sparc/sparc-protos.h       |  3 +-
 gcc/config/sparc/sparc.c              | 45 +++++++++++++++++++++++++--
 gcc/config/sparc/sparc.md             | 20 +++++++++---
 gcc/testsuite/ChangeLog               |  4 +++
 gcc/testsuite/gcc.dg/fixuns-trunc-1.c | 31 ++++++++++++++++++
 6 files changed, 108 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/fixuns-trunc-1.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0ae22cb8a01f..7818fed38413 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 cc164df2d78b..0908aaa5ea58 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 258dfc2d81e5..079ed5d9d164 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 2a060b85be9c..f0e69b173589 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 e86d65422cdd..508a19247d5b 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 000000000000..0d0942952497
--- /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;
+}
-- 
GitLab