Change the return value from void to double for __builtin_set_fpscr_rn.
The return value consists of the FPSCR fields DRN, VE, OE, UE, ZE, XE, NI,
RN bit positions. A new test file, test powerpc/test_fpscr_rn_builtin_2.c,
is added to test the new return value for the built-in.
The value __SET_FPSCR_RN_RETURNS_FPSCR__ is defined if
__builtin_set_fpscr_rn returns a double.
gcc/ChangeLog:
* config/rs6000/rs6000-builtins.def (__builtin_set_fpscr_rn): Update
built-in definition return type.
* config/rs6000/rs6000-c.cc (rs6000_target_modify_macros): Add check,
define __SET_FPSCR_RN_RETURNS_FPSCR__ macro.
* config/rs6000/rs6000.md (rs6000_set_fpscr_rn): Add return
argument to return FPSCR fields.
* doc/extend.texi (__builtin_set_fpscr_rn): Update description for
the return value. Add description for
__SET_FPSCR_RN_RETURNS_FPSCR__ macro.
gcc/testsuite/ChangeLog:
* gcc.target/powerpc/test_fpscr_rn_builtin.c: Rename to
test_fpscr_rn_builtin_1.c. Add comment.
* gcc.target/powerpc/test_fpscr_rn_builtin_2.c: New test for the
return value of __builtin_set_fpscr_rn builtin.
const __ibm128 __builtin_pack_ibm128 (double, double);
PACK_IF packif {ibm128}
- void __builtin_set_fpscr_rn (const int[0,3]);
+ double __builtin_set_fpscr_rn (const int[0,3]);
SET_FPSCR_RN rs6000_set_fpscr_rn {nosoft}
const double __builtin_unpack_ibm128 (__ibm128, const int<1>);
/* Tell the user -mrop-protect is in play. */
if (rs6000_rop_protect)
rs6000_define_or_undefine_macro (define_p, "__ROP_PROTECT__");
+ /* Tell the user __builtin_set_fpscr_rn now returns the FPSCR fields
+ in a double. Originally the built-in returned void. */
+ if ((flags & OPTION_MASK_SOFT_FLOAT) == 0)
+ rs6000_define_or_undefine_macro (define_p,
+ "__SET_FPSCR_RN_RETURNS_FPSCR__");
}
void
[(set_attr "type" "fp")])
(define_expand "rs6000_set_fpscr_rn"
- [(match_operand:SI 0 "reg_or_cint_operand")]
+ [(use (match_operand:DF 0 "gpc_reg_operand"))
+ (use (match_operand:SI 1 "reg_or_cint_operand"))]
"TARGET_HARD_FLOAT"
{
rtx tmp_df = gen_reg_rtx (DFmode);
new rounding mode bits from operands[0][62:63] into FPSCR[62:63]. */
if (TARGET_P9_MISC)
{
- if (const_0_to_3_operand (operands[0], VOIDmode))
- emit_insn (gen_rs6000_mffscrni (tmp_df, operands[0]));
+ if (const_0_to_3_operand (operands[1], VOIDmode))
+ emit_insn (gen_rs6000_mffscrni (tmp_df, operands[1]));
else
{
- rtx op0 = convert_to_mode (DImode, operands[0], false);
- rtx src_df = simplify_gen_subreg (DFmode, op0, DImode, 0);
+ rtx op1 = convert_to_mode (DImode, operands[1], false);
+ rtx src_df = simplify_gen_subreg (DFmode, op1, DImode, 0);
emit_insn (gen_rs6000_mffscrn (tmp_df, src_df));
}
- DONE;
+ emit_move_insn (operands[0], tmp_df);
+ DONE;
}
- if (CONST_INT_P (operands[0]))
+ /* Emulate the behavior of the mffscrni, mffscrn instructions for earlier
+ ISAs. Return bits 29:31 (DRN) and bits 56:63 (VE, OE, UE, ZE, XE, NI,
+ RN) from the FPSCR. Set the RN field based on the value in operands[1].
+ */
+
+ /* Get the current FPSCR fields, bits 29:31 (DRN) and bits 56:63 (VE, OE, UE,
+ ZE, XE, NI, RN) from the FPSCR and return them. */
+
+ emit_insn (gen_rs6000_mffs (tmp_df));
+ rtx orig_df_in_di = simplify_gen_subreg (DImode, tmp_df, DFmode, 0);
+ rtx tmp_di1 = gen_reg_rtx (DImode);
+ emit_insn (gen_anddi3 (tmp_di1, orig_df_in_di,
+ GEN_INT (0x00000007000000FFULL)));
+ rtx tmp_rtn = simplify_gen_subreg (DFmode, tmp_di1, DImode, 0);
+ emit_move_insn (operands[0], tmp_rtn);
+
+ if (CONST_INT_P (operands[1]))
{
- if ((INTVAL (operands[0]) & 0x1) == 0x1)
+ if ((INTVAL (operands[1]) & 0x1) == 0x1)
emit_insn (gen_rs6000_mtfsb1 (GEN_INT (31)));
else
emit_insn (gen_rs6000_mtfsb0 (GEN_INT (31)));
- if ((INTVAL (operands[0]) & 0x2) == 0x2)
+ if ((INTVAL (operands[1]) & 0x2) == 0x2)
emit_insn (gen_rs6000_mtfsb1 (GEN_INT (30)));
else
emit_insn (gen_rs6000_mtfsb0 (GEN_INT (30)));
}
else
{
- rtx tmp_rn = gen_reg_rtx (DImode);
- rtx tmp_di = gen_reg_rtx (DImode);
-
/* Extract new RN mode from operand. */
- rtx op0 = convert_to_mode (DImode, operands[0], false);
- emit_insn (gen_anddi3 (tmp_rn, op0, GEN_INT (3)));
+ rtx op1 = convert_to_mode (DImode, operands[1], false);
+ rtx tmp_rn = gen_reg_rtx (DImode);
+ emit_insn (gen_anddi3 (tmp_rn, op1, GEN_INT (3)));
- /* Insert new RN mode into FSCPR. */
- emit_insn (gen_rs6000_mffs (tmp_df));
- tmp_di = simplify_gen_subreg (DImode, tmp_df, DFmode, 0);
- emit_insn (gen_anddi3 (tmp_di, tmp_di, GEN_INT (-4)));
- emit_insn (gen_iordi3 (tmp_di, tmp_di, tmp_rn));
+ /* Insert the new RN value from tmp_rn into FPSCR bit [62:63]. */
+ rtx tmp_di1 = gen_reg_rtx (DImode);
+ emit_insn (gen_anddi3 (tmp_di1, orig_df_in_di, GEN_INT (-4)));
+ rtx tmp_di2 = gen_reg_rtx (DImode);
+ emit_insn (gen_iordi3 (tmp_di2, tmp_di1, tmp_rn));
/* Need to write to field k=15. The fields are [0:15]. Hence with
L=0, W=0, FLM_i must be equal to 8, 16 = i + 8*(1-W). FLM is an
8-bit field[0:7]. Need to set the bit that corresponds to the
value of i that you want [0:7]. */
- tmp_df = simplify_gen_subreg (DFmode, tmp_di, DImode, 0);
+ tmp_df = simplify_gen_subreg (DFmode, tmp_di2, DImode, 0);
emit_insn (gen_rs6000_mtfsf (GEN_INT (0x01), tmp_df));
}
DONE;
void __builtin_mtfsf (const int, double);
void __builtin_mtfsb0 (const int);
void __builtin_mtfsb1 (const int);
-void __builtin_set_fpscr_rn (int);
+double __builtin_set_fpscr_rn (int);
@end smallexample
The @code{__builtin_ppc_get_timebase} and @code{__builtin_ppc_mftb}
as an argument. The valid bit range is between 0 and 31. The builtins map to
the @code{mtfsb0} and @code{mtfsb1} instructions which take the argument and
add 32. Hence these instructions only modify the FPSCR[32:63] bits by
-changing the specified bit to a zero or one respectively. The
-@code{__builtin_set_fpscr_rn} builtin allows changing both of the floating
-point rounding mode bits. The argument is a 2-bit value. The argument can
-either be a @code{const int} or stored in a variable. The builtin uses
-the ISA 3.0
-instruction @code{mffscrn} if available, otherwise it reads the FPSCR, masks
-the current rounding mode bits out and OR's in the new value.
+changing the specified bit to a zero or one respectively.
+
+The @code{__builtin_set_fpscr_rn} built-in allows changing both of the floating
+point rounding mode bits and returning the various FPSCR fields before the RN
+field is updated. The built-in returns a double consisting of the initial
+value of the FPSCR fields DRN, VE, OE, UE, ZE, XE, NI, and RN bit positions
+with all other bits set to zero. The built-in argument is a 2-bit value for the
+new RN field value. The argument can either be an @code{const int} or stored
+in a variable. Earlier versions of @code{__builtin_set_fpscr_rn} returned
+void. A @code{__SET_FPSCR_RN_RETURNS_FPSCR__} macro has been added. If
+defined, then the @code{__builtin_set_fpscr_rn} built-in returns the FPSCR
+fields. If not defined, the @code{__builtin_set_fpscr_rn} does not return a
+value. If the @option{-msoft-float} option is used, the
+@code{__builtin_set_fpscr_rn} built-in will not return a value.
@node Basic PowerPC Built-in Functions Available on ISA 2.05
@subsubsection Basic PowerPC Built-in Functions Available on ISA 2.05
-/* { dg-do run { target { powerpc*-*-* } } } */
-/* { dg-options "-O2 -std=c99" } */
+/* { dg-do run { target powerpc_fprs } } */
+/* { dg-options "-O2" } */
+
+/* Originally __builtin_set_fpscr_rn was defined to return void. It was
+ later extended to return a double with the various FPSCR bits. The
+ extended built-in is intended to be a drop in replacement for the original
+ version. This test is for the original version of the built-in and should
+ work exactly as before. */
#ifdef DEBUG
#include <stdio.h>
unsigned long long ll_value;
register double f14;
- /* __builtin_set_fpscr_rn() builtin can take a const or a variable
+ /* __builtin_set_fpscr_rn() built-in can take a const or a variable
value between 0 and 3 as the argument.
__builtin_mtfsb0 and __builtin_mtfsb1 argument must be a constant
30 or 31.
--- /dev/null
+/* { dg-do run { target powerpc_fprs } } */
+/* { dg-options "-O2" } */
+
+/* The __builtin_set_fpscr_rn built-in was originally defined to return
+ void. The built-in now returns a double containing the various FPSCR bits.
+ This test verifies the new return value. */
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#define RN_MASK 0x3LL /* RN field mask */
+#define FIELD_MASK 0x00000007000000FFULL
+
+union blah {
+ double d;
+ unsigned long long ll;
+} conv_val;
+
+void abort (void);
+
+double __attribute__ ((noipa)) wrap_set_fpscr_rn (int val)
+{
+ return __builtin_set_fpscr_rn (val);
+}
+
+double __attribute__ ((noipa)) wrap_const_fpscr_rn (int val)
+{
+ switch (val)
+ {
+ case 0: return __builtin_set_fpscr_rn (0x0);
+ case 1: return __builtin_set_fpscr_rn (0x1);
+ case 2: return __builtin_set_fpscr_rn (0x2);
+ case 3: return __builtin_set_fpscr_rn (0x3);
+ }
+}
+
+void check_builtin_set_fpscr_rn (unsigned long long initial_fpscr,
+ int new_RN, double result)
+{
+ register double f14;
+ unsigned long long masked_fpscr = initial_fpscr & FIELD_MASK;
+
+ conv_val.d = result;
+
+ /* Check the result. */
+ if (conv_val.ll != masked_fpscr)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_rn(%d) did not return expected value %llx.\n",
+ new_RN, masked_fpscr);
+ printf("fpscr_val_initial = 0x%llx\n", initial_fpscr);
+ printf("result = 0x%llx\n", conv_val.ll);
+#else
+ abort();
+#endif
+ }
+
+ /* Check to see if the RN field was updated. */
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+
+ if ((conv_val.ll & RN_MASK) != new_RN)
+#ifdef DEBUG
+ {
+ printf("ERROR, __builtin_set_fpscr_rn(%d) did not update RN to %llx.\n",
+ new_RN, new_RN);
+ printf(" conv_val.ll = 0x%llx\n", conv_val.ll);
+ }
+#else
+ abort();
+#endif
+}
+
+int
+main ()
+{
+ int i;
+ int val, bit;
+ double fpscr_val;
+ unsigned long long fpscr_val_initial;
+
+ unsigned long long ll_value;
+ union blah src_double;
+ register double f14;
+
+ /* If __SET_FPSCR_RN_RETURNS_FPSCR__ is defined, the __builtin_set_fpscr_rn()
+ builtin returns the FPSCR fields.*/
+
+ /* __builtin_set_fpscr_rn() builtin can take a constant or a variable
+ value between 0 and 3 as the argument.
+ __builtin_mtfsb0 and __builtin_mtfsb1 argument must be a constant
+ 30 or 31.
+ */
+
+ /* Test reading the FPSCR register */
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+
+ if (conv_val.d != __builtin_mffs())
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mffs() returned 0x%llx, not the expected value 0x%llx\n",
+ __builtin_mffs(), conv_val.d);
+#else
+ abort();
+#endif
+ }
+
+ /* Test return value from __builtin_set_fpscr_rn. The FPSCR fields (DRN, VE,
+ OE, UE, ZE, XE, NI, RN) are returned and the RN field of FPSCR is updated
+ with the specified argument for the built-in. */
+
+ /* Check immediate argument cases */
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+ fpscr_val_initial = conv_val.ll;
+
+ val = 0x0;
+ fpscr_val = wrap_const_fpscr_rn (val);
+ check_builtin_set_fpscr_rn (fpscr_val_initial, val, fpscr_val);
+
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+ fpscr_val_initial = conv_val.ll;
+
+ val = 0x3;
+ fpscr_val = wrap_const_fpscr_rn (val);
+ check_builtin_set_fpscr_rn (fpscr_val_initial, val, fpscr_val);
+
+ /* Check int argument cases */
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+ fpscr_val_initial = conv_val.ll;
+
+ val = 0x1;
+ fpscr_val = wrap_set_fpscr_rn (val);
+ check_builtin_set_fpscr_rn (fpscr_val_initial, val, fpscr_val);
+
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+ fpscr_val_initial = conv_val.ll;
+
+ val = 0x2;
+ fpscr_val = wrap_set_fpscr_rn (val);
+ check_builtin_set_fpscr_rn (fpscr_val_initial, val, fpscr_val);
+ return 0;
+}