This patch adds built-in functions for getting and setting the value of
the FPU's FCSR.  Unlike any of the existing built-in functions, these two
can be used in both MIPS16 and non-MIPS16 code.

The functions are needed for the two patches that I'm about to post,
which fix c11-atomic-exec-5.c for mips64-linux-gnu.

Tested on mips64-linux-gnu and mipsisa64-sde-elf.  Applied.

Thanks,
Richard


gcc/
        * doc/extend.texi (__builtin_mips_get_fcsr): Document.
        (__builtin_mips_set_fcsr): Likewise.
        * config/mips/mips-ftypes.def: Add MIPS_VOID_FTYPE_USI and
        MIPS_USI_FTYPE_VOID.
        * config/mips/mips-protos.h (mips16_expand_get_fcsr): Declare
        (mips16_expand_set_fcsr): Likewise.
        * config/mips/mips.c (mips16_get_fcsr_stub): New variable.
        (mips16_set_fcsr_stub): Likewise.
        (mips16_get_fcsr_one_only_stub): New class.
        (mips16_set_fcsr_one_only_stub): Likewise.
        (mips16_expand_get_fcsr, mips16_expand_set_fcsr): New functions.
        (mips_code_end): Output the get_fcsr and set_fcsr stubs, if needed.
        (BUILTIN_AVAIL_MIPS16, AVAIL_ALL): New macros.
        (hard_float): New availability predicate.
        (mips_builtins): Add get_fcsr and set_fcsr.
        (mips_expand_builtin): Check BUILTIN_AVAIL_MIPS16.
        * config/mips/mips.md (UNSPEC_GET_FCSR, UNSPEC_SET_FCSR): New unspecs.
        (GET_FCSR_REGNUM, SET_FCSR_REGNUM): New constants.
        (mips_get_fcsr, *mips_get_fcsr, mips_get_fcsr_mips16_<mode>)
        (mips_set_fcsr, *mips_set_fcsr, mips_set_fcsr_mips16_<mode>): New
        patterns.

gcc/testsuite/
        * gcc.target/mips/get-fcsr-1.c, gcc.target/mips/get-fcsr-2.c,
        gcc.target/mips/set-fcsr-1.c, gcc.target/mips/set-fcsr-2.c: New tests.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi 2014-02-01 09:13:22.748607746 +0000
+++ gcc/doc/extend.texi 2014-02-02 14:55:41.179416791 +0000
@@ -12617,6 +12617,15 @@ GCC provides other MIPS-specific built-i
 Insert a @samp{cache} instruction with operands @var{op} and @var{addr}.
 GCC defines the preprocessor macro @code{___GCC_HAVE_BUILTIN_MIPS_CACHE}
 when this function is available.
+
+@item unsigned int __builtin_mips_get_fcsr (void)
+@itemx void __builtin_mips_set_fcsr (unsigned int @var{value})
+Get and set the contents of the floating-point control and status register
+(FPU control register 31).  These functions are only available in hard-float
+code but can be called in both MIPS16 and non-MIPS16 contexts.
+
+@code{__builtin_mips_set_fcsr} can be used to change any bit of the
+register except the condition codes, which GCC assumes are preserved.
 @end table
 
 @node MSP430 Built-in Functions
Index: gcc/config/mips/mips-ftypes.def
===================================================================
--- gcc/config/mips/mips-ftypes.def     2014-02-02 14:33:33.587385903 +0000
+++ gcc/config/mips/mips-ftypes.def     2014-02-02 14:40:21.504714501 +0000
@@ -69,6 +69,8 @@ DEF_MIPS_FTYPE (1, (SF, V2SF))
 DEF_MIPS_FTYPE (2, (UDI, UDI, UDI))
 DEF_MIPS_FTYPE (2, (UDI, UV2SI, UV2SI))
 
+DEF_MIPS_FTYPE (1, (USI, VOID))
+
 DEF_MIPS_FTYPE (2, (UV2SI, UV2SI, UQI))
 DEF_MIPS_FTYPE (2, (UV2SI, UV2SI, UV2SI))
 
@@ -122,5 +124,6 @@ DEF_MIPS_FTYPE (2, (V8QI, V8QI, V8QI))
 
 DEF_MIPS_FTYPE (2, (VOID, SI, CVPOINTER))
 DEF_MIPS_FTYPE (2, (VOID, SI, SI))
+DEF_MIPS_FTYPE (1, (VOID, USI))
 DEF_MIPS_FTYPE (2, (VOID, V2HI, V2HI))
 DEF_MIPS_FTYPE (2, (VOID, V4QI, V4QI))
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h       2014-02-02 14:33:33.587385903 +0000
+++ gcc/config/mips/mips-protos.h       2014-02-02 14:40:21.498714452 +0000
@@ -345,6 +345,8 @@ extern bool lwsp_swsp_address_p (rtx, en
 extern bool m16_based_address_p (rtx, enum machine_mode,
                                 int (*)(rtx_def*, machine_mode)); 
 extern rtx mips_expand_thread_pointer (rtx);
+extern void mips16_expand_get_fcsr (rtx);
+extern void mips16_expand_set_fcsr (rtx);
 
 extern bool mips_eh_uses (unsigned int);
 extern bool mips_epilogue_uses (unsigned int);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c      2014-02-02 14:38:14.311668731 +0000
+++ gcc/config/mips/mips.c      2014-02-02 14:40:21.502714485 +0000
@@ -641,8 +641,10 @@ struct target_globals *mips16_globals;
    and returned from mips_sched_reorder2.  */
 static int cached_can_issue_more;
 
-/* The stub for __mips16_rdhwr, if used.  */
+/* The stubs for various MIPS16 support functions, if used.   */
 static mips_one_only_stub *mips16_rdhwr_stub;
+static mips_one_only_stub *mips16_get_fcsr_stub;
+static mips_one_only_stub *mips16_set_fcsr_stub;
 
 /* Index R is the smallest register class that contains register R.  */
 const enum reg_class mips_regno_to_class[FIRST_PSEUDO_REGISTER] = {
@@ -1660,6 +1662,48 @@ mips16_rdhwr_one_only_stub::output_body
           "\t.set\tpop\n"
           "\tj\t$31\n");
 }
+
+/* A stub for moving the FCSR into GET_FCSR_REGNUM.  */
+class mips16_get_fcsr_one_only_stub : public mips_one_only_stub
+{
+  virtual const char *get_name ();
+  virtual void output_body ();
+};
+
+const char *
+mips16_get_fcsr_one_only_stub::get_name ()
+{
+  return "__mips16_get_fcsr";
+}
+
+void
+mips16_get_fcsr_one_only_stub::output_body ()
+{
+  fprintf (asm_out_file,
+          "\tcfc1\t%s,$31\n"
+          "\tj\t$31\n", reg_names[GET_FCSR_REGNUM]);
+}
+
+/* A stub for moving SET_FCSR_REGNUM into the FCSR.  */
+class mips16_set_fcsr_one_only_stub : public mips_one_only_stub
+{
+  virtual const char *get_name ();
+  virtual void output_body ();
+};
+
+const char *
+mips16_set_fcsr_one_only_stub::get_name ()
+{
+  return "__mips16_set_fcsr";
+}
+
+void
+mips16_set_fcsr_one_only_stub::output_body ()
+{
+  fprintf (asm_out_file,
+          "\tctc1\t%s,$31\n"
+          "\tj\t$31\n", reg_names[SET_FCSR_REGNUM]);
+}
 
 /* Return true if symbols of type TYPE require a GOT access.  */
 
@@ -3220,6 +3264,31 @@ mips_legitimize_tls_address (rtx loc)
   return dest;
 }
 
+/* Implement "TARGET = __builtin_mips_get_fcsr ()" for MIPS16,
+   using a stub.  */
+
+void
+mips16_expand_get_fcsr (rtx target)
+{
+  if (!mips16_get_fcsr_stub)
+    mips16_get_fcsr_stub = new mips16_get_fcsr_one_only_stub ();
+  rtx fn = mips16_stub_call_address (mips16_get_fcsr_stub);
+  emit_insn (PMODE_INSN (gen_mips_get_fcsr_mips16, (fn)));
+  emit_move_insn (target, gen_rtx_REG (SImode, GET_FCSR_REGNUM));
+}
+
+/* Implement __builtin_mips_set_fcsr (TARGET) for MIPS16, using a stub.  */
+
+void
+mips16_expand_set_fcsr (rtx newval)
+{
+  if (!mips16_set_fcsr_stub)
+    mips16_set_fcsr_stub = new mips16_set_fcsr_one_only_stub ();
+  rtx fn = mips16_stub_call_address (mips16_set_fcsr_stub);
+  emit_move_insn (gen_rtx_REG (SImode, SET_FCSR_REGNUM), newval);
+  emit_insn (PMODE_INSN (gen_mips_set_fcsr_mips16, (fn)));
+}
+
 /* If X is not a valid address for mode MODE, force it into a register.  */
 
 static rtx
@@ -8959,6 +9028,8 @@ mips_file_start (void)
 mips_code_end (void)
 {
   mips_finish_stub (&mips16_rdhwr_stub);
+  mips_finish_stub (&mips16_get_fcsr_stub);
+  mips_finish_stub (&mips16_set_fcsr_stub);
 }
 
 /* Make the last instruction frame-related and note that it performs
@@ -13650,9 +13721,12 @@ mips_prefetch_cookie (rtx write, rtx loc
 /* Flags that indicate when a built-in function is available.
 
    BUILTIN_AVAIL_NON_MIPS16
-       The function is available on the current target, but only
-       in non-MIPS16 mode.  */
+       The function is available on the current target if !TARGET_MIPS16.
+
+   BUILTIN_AVAIL_MIPS16
+       The function is available on the current target if TARGET_MIPS16.  */
 #define BUILTIN_AVAIL_NON_MIPS16 1
+#define BUILTIN_AVAIL_MIPS16 2
 
 /* Declare an availability predicate for built-in functions that
    require non-MIPS16 mode and also require COND to be true.
@@ -13664,6 +13738,16 @@ #define AVAIL_NON_MIPS16(NAME, COND)
    return (COND) ? BUILTIN_AVAIL_NON_MIPS16 : 0;                       \
  }
 
+/* Declare an availability predicate for built-in functions that
+   support both MIPS16 and non-MIPS16 code and also require COND
+   to be true.  NAME is the main part of the predicate's name.  */
+#define AVAIL_ALL(NAME, COND)                                          \
+ static unsigned int                                                   \
+ mips_builtin_avail_##NAME (void)                                      \
+ {                                                                     \
+   return (COND) ? BUILTIN_AVAIL_NON_MIPS16 | BUILTIN_AVAIL_MIPS16 : 0;        
\
+ }
+
 /* This structure describes a single built-in function.  */
 struct mips_builtin_description {
   /* The code of the main .md file instruction.  See mips_builtin_type
@@ -13686,6 +13770,7 @@ struct mips_builtin_description {
   unsigned int (*avail) (void);
 };
 
+AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI)
 AVAIL_NON_MIPS16 (paired_single, TARGET_PAIRED_SINGLE_FLOAT)
 AVAIL_NON_MIPS16 (sb1_paired_single, TARGET_SB1 && TARGET_PAIRED_SINGLE_FLOAT)
 AVAIL_NON_MIPS16 (mips3d, TARGET_MIPS3D)
@@ -13853,6 +13938,9 @@ #define CODE_FOR_loongson_psubush CODE_F
 #define CODE_FOR_loongson_psubusb CODE_FOR_ussubv8qi3
 
 static const struct mips_builtin_description mips_builtins[] = {
+  DIRECT_BUILTIN (get_fcsr, MIPS_USI_FTYPE_VOID, hard_float),
+  DIRECT_NO_TARGET_BUILTIN (set_fcsr, MIPS_VOID_FTYPE_USI, hard_float),
+
   DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
   DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
   DIRECT_BUILTIN (plu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
@@ -14502,7 +14590,7 @@ mips_expand_builtin (tree exp, rtx targe
   d = &mips_builtins[fcode];
   avail = d->avail ();
   gcc_assert (avail != 0);
-  if (TARGET_MIPS16)
+  if (TARGET_MIPS16 && !(avail & BUILTIN_AVAIL_MIPS16))
     {
       error ("built-in function %qE not supported for MIPS16",
             DECL_NAME (fndecl));
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md     2014-02-02 14:33:36.845412170 +0000
+++ gcc/config/mips/mips.md     2014-02-02 14:40:21.504714501 +0000
@@ -86,6 +86,10 @@ (define_c_enum "unspec" [
   UNSPEC_MFHC1
   UNSPEC_MTHC1
 
+  ;; Floating-point environment.
+  UNSPEC_GET_FCSR
+  UNSPEC_SET_FCSR
+
   ;; HI/LO moves.
   UNSPEC_MFHI
   UNSPEC_MTHI
@@ -147,6 +151,8 @@ (define_c_enum "unspec" [
 
 (define_constants
   [(TLS_GET_TP_REGNUM          3)
+   (GET_FCSR_REGNUM            2)
+   (SET_FCSR_REGNUM            4)
    (MIPS16_T_REGNUM            24)
    (PIC_FUNCTION_ADDR_REGNUM   25)
    (RETURN_ADDR_REGNUM         31)
@@ -7057,6 +7063,66 @@ (define_expand "get_thread_pointer<mode>
   DONE;
 })
 
+;; __builtin_mips_get_fcsr: move the FCSR into operand 0.
+(define_expand "mips_get_fcsr"
+  [(set (match_operand:SI 0 "register_operand")
+       (unspec_volatile [(const_int 0)] UNSPEC_GET_FCSR))]
+  "TARGET_HARD_FLOAT_ABI"
+{
+  if (TARGET_MIPS16)
+    {
+      mips16_expand_get_fcsr (operands[0]);
+      DONE;
+    }
+})
+
+(define_insn "*mips_get_fcsr"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (unspec_volatile [(const_int 0)] UNSPEC_GET_FCSR))]
+  "TARGET_HARD_FLOAT"
+  "cfc1\t%0,$31")
+
+;; See tls_get_tp_mips16_<mode> for why this form is used.
+(define_insn "mips_get_fcsr_mips16_<mode>"
+  [(set (reg:SI GET_FCSR_REGNUM)
+       (unspec:SI [(match_operand:P 0 "call_insn_operand" "dS")]
+                  UNSPEC_GET_FCSR))
+   (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM))
+   (clobber (reg:P RETURN_ADDR_REGNUM))]
+  "TARGET_HARD_FLOAT_ABI && TARGET_MIPS16"
+  { return MIPS_CALL ("jal", operands, 0, -1); }
+  [(set_attr "type" "call")
+   (set_attr "insn_count" "3")])
+
+;; __builtin_mips_set_fcsr: move operand 0 into the FCSR.
+(define_expand "mips_set_fcsr"
+  [(unspec_volatile [(match_operand:SI 0 "register_operand")]
+                   UNSPEC_SET_FCSR)]
+  "TARGET_HARD_FLOAT_ABI"
+{
+  if (TARGET_MIPS16)
+    {
+      mips16_expand_set_fcsr (operands[0]);
+      DONE;
+    }
+})
+
+(define_insn "*mips_set_fcsr"
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")]
+                   UNSPEC_SET_FCSR)]
+  "TARGET_HARD_FLOAT"
+  "ctc1\t%0,$31")
+
+;; See tls_get_tp_mips16_<mode> for why this form is used.
+(define_insn "mips_set_fcsr_mips16_<mode>"
+  [(unspec_volatile:SI [(match_operand:P 0 "call_insn_operand" "dS")
+                       (reg:SI SET_FCSR_REGNUM)] UNSPEC_SET_FCSR)
+   (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM))
+   (clobber (reg:P RETURN_ADDR_REGNUM))]
+  "TARGET_HARD_FLOAT_ABI && TARGET_MIPS16"
+  { return MIPS_CALL ("jal", operands, 0, -1); }
+  [(set_attr "type" "call")
+   (set_attr "insn_count" "3")])
 
 ;; Synchronization instructions.
 
Index: gcc/testsuite/gcc.target/mips/get-fcsr-1.c
===================================================================
--- /dev/null   2014-01-30 08:06:21.701666182 +0000
+++ gcc/testsuite/gcc.target/mips/get-fcsr-1.c  2014-02-02 14:40:21.505714510 
+0000
@@ -0,0 +1,9 @@
+/* { dg-options "-mhard-float" } */
+
+NOMIPS16 unsigned int
+foo (void)
+{
+  return __builtin_mips_get_fcsr ();
+}
+
+/* { dg-final { scan-assembler "cfc1\t\\\$2,\\\$31" } } */
Index: gcc/testsuite/gcc.target/mips/get-fcsr-2.c
===================================================================
--- /dev/null   2014-01-30 08:06:21.701666182 +0000
+++ gcc/testsuite/gcc.target/mips/get-fcsr-2.c  2014-02-02 14:40:21.504714501 
+0000
@@ -0,0 +1,10 @@
+/* { dg-options "-mhard-float (-mips16)" } */
+
+MIPS16 unsigned int
+foo (void)
+{
+  return __builtin_mips_get_fcsr ();
+}
+
+/* { dg-final { scan-assembler "__mips16_get_fcsr" } } */
+/* { dg-final { scan-assembler "cfc1\t\\\$2,\\\$31" } } */
Index: gcc/testsuite/gcc.target/mips/set-fcsr-1.c
===================================================================
--- /dev/null   2014-01-30 08:06:21.701666182 +0000
+++ gcc/testsuite/gcc.target/mips/set-fcsr-1.c  2014-02-02 14:40:21.505714510 
+0000
@@ -0,0 +1,10 @@
+/* { dg-options "-mhard-float" } */
+/* { dg-skip-if "requiring \$4 is a code-quality test" { *-*-* } { "-O0" } { 
"" } } */
+
+NOMIPS16 void
+foo (unsigned int x)
+{
+  __builtin_mips_set_fcsr (x);
+}
+
+/* { dg-final { scan-assembler "ctc1\t\\\$4,\\\$31" } } */
Index: gcc/testsuite/gcc.target/mips/set-fcsr-2.c
===================================================================
--- /dev/null   2014-01-30 08:06:21.701666182 +0000
+++ gcc/testsuite/gcc.target/mips/set-fcsr-2.c  2014-02-02 14:40:21.505714510 
+0000
@@ -0,0 +1,10 @@
+/* { dg-options "-mhard-float (-mips16)" } */
+
+MIPS16 void
+foo (unsigned int x)
+{
+  __builtin_mips_set_fcsr (x);
+}
+
+/* { dg-final { scan-assembler "__mips16_set_fcsr" } } */
+/* { dg-final { scan-assembler "ctc1\t\\\$4,\\\$31" } } */

Reply via email to