+2018-10-01 Carl Love <cel@us.ibm.com>
+
+ * config/rs6000/rs6000-builtin.def (__builtin_mffsl): New.
+ (__builtin_mtfsb0): New.
+ (__builtin_mtfsb1): New.
+ ( __builtin_set_fpscr_rn): New.
+ (__builtin_set_fpscr_drn): New.
+ * config/rs6000/rs6000.c (rs6000_expand_mtfsb_builtin): Add.
+ (rs6000_expand_set_fpscr_rn_builtin): Add.
+ (rs6000_expand_set_fpscr_drn_builtin): Add.
+ (rs6000_expand_builtin): Add case statement entries for
+ RS6000_BUILTIN_MTFSB0, RS6000_BUILTIN_MTFSB1,
+ RS6000_BUILTIN_SET_FPSCR_RN, RS6000_BUILTIN_SET_FPSCR_DRN,
+ RS6000_BUILTIN_MFFSL.
+ (rs6000_init_builtins): Add ftype initialization and def_builtin
+ calls for __builtin_mffsl, __builtin_mtfsb0, __builtin_mtfsb1,
+ __builtin_set_fpscr_rn, __builtin_set_fpscr_drn.
+ * config/rs6000.md (rs6000_mtfsb0, rs6000_mtfsb1, rs6000_mffscrn,
+ rs6000_mffscdrn): Add define_insn.
+ (rs6000_set_fpscr_rn, rs6000_set_fpscr_drn): Add define_expand.
+ * doc/extend.texi: Add documentation for the builtins.
+
2018-10-01 Richard Biener <rguenther@suse.de>
PR tree-optimization/87465
BU_SPECIAL_X (RS6000_BUILTIN_MFFS, "__builtin_mffs",
RS6000_BTM_ALWAYS, RS6000_BTC_MISC)
+BU_SPECIAL_X (RS6000_BUILTIN_MFFSL, "__builtin_mffsl",
+ RS6000_BTM_ALWAYS, RS6000_BTC_MISC)
+
RS6000_BUILTIN_X (RS6000_BUILTIN_MTFSF, "__builtin_mtfsf",
RS6000_BTM_ALWAYS,
RS6000_BTC_MISC | RS6000_BTC_UNARY | RS6000_BTC_VOID,
CODE_FOR_rs6000_mtfsf)
+RS6000_BUILTIN_X (RS6000_BUILTIN_MTFSB0, "__builtin_mtfsb0",
+ RS6000_BTM_ALWAYS,
+ RS6000_BTC_MISC | RS6000_BTC_UNARY | RS6000_BTC_VOID,
+ CODE_FOR_rs6000_mtfsb0)
+
+RS6000_BUILTIN_X (RS6000_BUILTIN_MTFSB1, "__builtin_mtfsb1",
+ RS6000_BTM_ALWAYS,
+ RS6000_BTC_MISC | RS6000_BTC_UNARY | RS6000_BTC_VOID,
+ CODE_FOR_rs6000_mtfsb1)
+
+RS6000_BUILTIN_X (RS6000_BUILTIN_SET_FPSCR_RN, "__builtin_set_fpscr_rn",
+ RS6000_BTM_ALWAYS,
+ RS6000_BTC_MISC | RS6000_BTC_UNARY| RS6000_BTC_VOID,
+ CODE_FOR_rs6000_set_fpscr_rn)
+
+RS6000_BUILTIN_X (RS6000_BUILTIN_SET_FPSCR_DRN, "__builtin_set_fpscr_drn",
+ RS6000_BTM_ALWAYS,
+ RS6000_BTC_MISC | RS6000_BTM_64BIT | RS6000_BTC_UNARY
+ | RS6000_BTC_VOID,
+ CODE_FOR_rs6000_set_fpscr_drn)
+
BU_SPECIAL_X (RS6000_BUILTIN_CPU_INIT, "__builtin_cpu_init",
RS6000_BTM_ALWAYS, RS6000_BTC_MISC)
/* Builtin not supported on this processor. */
return 0;
+ if (icode == CODE_FOR_rs6000_mffsl
+ && rs6000_isa_flags_explicit & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("__builtin_mffsl() not supported with -msoft-float");
+ return const0_rtx;
+ }
+
if (target == 0
|| GET_MODE (target) != tmode
|| ! (*insn_data[icode].operand[0].predicate) (target, tmode))
op1 = copy_to_mode_reg (mode1, op1);
pat = GEN_FCN (icode) (op0, op1);
+ if (!pat)
+ return const0_rtx;
+ emit_insn (pat);
+
+ return NULL_RTX;
+}
+
+static rtx
+rs6000_expand_mtfsb_builtin (enum insn_code icode, tree exp)
+{
+ rtx pat;
+ tree arg0 = CALL_EXPR_ARG (exp, 0);
+ rtx op0 = expand_normal (arg0);
+
+ if (icode == CODE_FOR_nothing)
+ /* Builtin not supported on this processor. */
+ return 0;
+
+ if (rs6000_isa_flags_explicit & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("__builtin_mtfsb0 and __builtin_mtfsb1 not supported with -msoft-float");
+ return const0_rtx;
+ }
+
+ /* If we got invalid arguments bail out before generating bad rtl. */
+ if (arg0 == error_mark_node)
+ return const0_rtx;
+
+ /* Only allow bit numbers 0 to 31. */
+ if (!u5bit_cint_operand (op0, VOIDmode))
+ {
+ error ("Argument must be a constant between 0 and 31.");
+ return const0_rtx;
+ }
+
+ pat = GEN_FCN (icode) (op0);
+ if (!pat)
+ return const0_rtx;
+ emit_insn (pat);
+
+ return NULL_RTX;
+}
+
+static rtx
+rs6000_expand_set_fpscr_rn_builtin (enum insn_code icode, tree exp)
+{
+ rtx pat;
+ tree arg0 = CALL_EXPR_ARG (exp, 0);
+ rtx op0 = expand_normal (arg0);
+ machine_mode mode0 = insn_data[icode].operand[0].mode;
+
+ if (icode == CODE_FOR_nothing)
+ /* Builtin not supported on this processor. */
+ return 0;
+
+ if (rs6000_isa_flags_explicit & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("__builtin_set_fpscr_rn not supported with -msoft-float");
+ return const0_rtx;
+ }
+
+ /* If we got invalid arguments bail out before generating bad rtl. */
+ if (arg0 == error_mark_node)
+ return const0_rtx;
+
+ /* If the argument is a constant, check the range. Argument can only be a
+ 2-bit value. Unfortunately, can't check the range of the value at
+ compile time if the argument is a variable. The least significant two
+ bits of the argument, regardless of type, are used to set the rounding
+ mode. All other bits are ignored. */
+ if (GET_CODE (op0) == CONST_INT && !const_0_to_3_operand(op0, VOIDmode))
+ {
+ error ("Argument must be a value between 0 and 3.");
+ return const0_rtx;
+ }
+
+ if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ pat = GEN_FCN (icode) (op0);
+ if (!pat)
+ return const0_rtx;
+ emit_insn (pat);
+
+ return NULL_RTX;
+}
+static rtx
+rs6000_expand_set_fpscr_drn_builtin (enum insn_code icode, tree exp)
+{
+ rtx pat;
+ tree arg0 = CALL_EXPR_ARG (exp, 0);
+ rtx op0 = expand_normal (arg0);
+ machine_mode mode0 = insn_data[icode].operand[0].mode;
+
+ if (TARGET_32BIT)
+ /* Builtin not supported in 32-bit mode. */
+ fatal_error (input_location,
+ "__builtin_set_fpscr_drn is not supported in 32-bit mode.");
+
+ if (rs6000_isa_flags_explicit & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("__builtin_set_fpscr_drn not supported with -msoft-float");
+ return const0_rtx;
+ }
+
+ if (icode == CODE_FOR_nothing)
+ /* Builtin not supported on this processor. */
+ return 0;
+
+ /* If we got invalid arguments bail out before generating bad rtl. */
+ if (arg0 == error_mark_node)
+ return const0_rtx;
+
+ /* If the argument is a constant, check the range. Agrument can only be a
+ 3-bit value. Unfortunately, can't check the range of the value at
+ compile time if the argument is a variable. The least significant two
+ bits of the argument, regardless of type, are used to set the rounding
+ mode. All other bits are ignored. */
+ if (GET_CODE (op0) == CONST_INT && !const_0_to_7_operand(op0, VOIDmode))
+ {
+ error ("Argument must be a value between 0 and 7.");
+ return const0_rtx;
+ }
+
+ if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ pat = GEN_FCN (icode) (op0);
if (! pat)
return const0_rtx;
emit_insn (pat);
case RS6000_BUILTIN_MFFS:
return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+ case RS6000_BUILTIN_MTFSB1:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_RN:
+ return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
+ exp);
+
+ case RS6000_BUILTIN_SET_FPSCR_DRN:
+ return
+ rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+ exp);
+
+ case RS6000_BUILTIN_MFFSL:
+ return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
case RS6000_BUILTIN_MTFSF:
return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
ftype = build_function_type_list (double_type_node, NULL_TREE);
def_builtin ("__builtin_mffs", ftype, RS6000_BUILTIN_MFFS);
+ ftype = build_function_type_list (double_type_node, NULL_TREE);
+ def_builtin ("__builtin_mffsl", ftype, RS6000_BUILTIN_MFFSL);
+
+ ftype = build_function_type_list (void_type_node,
+ intSI_type_node,
+ NULL_TREE);
+ def_builtin ("__builtin_mtfsb0", ftype, RS6000_BUILTIN_MTFSB0);
+
+ ftype = build_function_type_list (void_type_node,
+ intSI_type_node,
+ NULL_TREE);
+ def_builtin ("__builtin_mtfsb1", ftype, RS6000_BUILTIN_MTFSB1);
+
+ ftype = build_function_type_list (void_type_node,
+ intDI_type_node,
+ NULL_TREE);
+ def_builtin ("__builtin_set_fpscr_rn", ftype, RS6000_BUILTIN_SET_FPSCR_RN);
+
+ ftype = build_function_type_list (void_type_node,
+ intDI_type_node,
+ NULL_TREE);
+ def_builtin ("__builtin_set_fpscr_drn", ftype, RS6000_BUILTIN_SET_FPSCR_DRN);
+
ftype = build_function_type_list (void_type_node,
intSI_type_node, double_type_node,
NULL_TREE);
UNSPECV_MFTB ; move from time base
UNSPECV_NLGR ; non-local goto receiver
UNSPECV_MFFS ; Move from FPSCR
- UNSPECV_MTFSF ; Move to FPSCR Fields
+ UNSPECV_MFFSL ; Move from FPSCR light instruction version
+ UNSPECV_MFFSCRN ; Move from FPSCR float rounding mode
+ UNSPECV_MFFSCDRN ; Move from FPSCR decimal float rounding mode
+ UNSPECV_MTFSF ; Move to FPSCR Fields 8 to 15
+ UNSPECV_MTFSF_HI ; Move to FPSCR Fields 0 to 7
+ UNSPECV_MTFSB0 ; Set FPSCR Field bit to 0
+ UNSPECV_MTFSB1 ; Set FPSCR Field bit to 1
UNSPECV_SPLIT_STACK_RETURN ; A camouflaged return
UNSPECV_SPEC_BARRIER ; Speculation barrier
])
xscvdpuxds %x0,%x1"
[(set_attr "type" "fp")])
+(define_insn "rs6000_mtfsb0"
+ [(unspec_volatile [(match_operand:SI 0 "u5bit_cint_operand" "n")]
+ UNSPECV_MTFSB0)]
+ "TARGET_HARD_FLOAT"
+ "mtfsb0 %0"
+ [(set_attr "type" "fp")])
+
+(define_insn "rs6000_mtfsb1"
+ [(unspec_volatile [(match_operand:SI 0 "u5bit_cint_operand" "n")]
+ UNSPECV_MTFSB1)]
+ "TARGET_HARD_FLOAT"
+ "mtfsb1 %0"
+ [(set_attr "type" "fp")])
+
+(define_insn "rs6000_mffscrn"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+ (unspec_volatile:DF [(match_operand:DF 1 "gpc_reg_operand" "d")]
+ UNSPECV_MFFSCRN))]
+ "TARGET_P9_MISC"
+ "mffscrn %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "rs6000_mffscdrn"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+ (unspec_volatile:DF [(const_int 0)] UNSPECV_MFFSCDRN))
+ (use (match_operand:DF 1 "gpc_reg_operand" "d"))]
+ "TARGET_P9_MISC"
+ "mffscdrn %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_expand "rs6000_set_fpscr_rn"
+ [(match_operand 0 "reg_or_cint_operand")]
+ "TARGET_HARD_FLOAT"
+{
+ rtx tmp_df = gen_reg_rtx (DFmode);
+
+ /* The floating point rounding control bits are FPSCR[62:63]. Put the
+ new rounding mode bits from operands[0][62:63] into FPSCR[62:63]. */
+ if (TARGET_P9_MISC)
+ {
+ rtx src_df = gen_reg_rtx (DImode);
+
+ src_df = simplify_gen_subreg (DFmode, operands[0], DImode, 0);
+ emit_insn (gen_rs6000_mffscrn (tmp_df, src_df));
+ DONE;
+ }
+
+ if (CONST_INT_P (operands[0]))
+ {
+ if ((INTVAL (operands[0]) & 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)
+ 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. */
+ emit_insn (gen_anddi3 (tmp_rn, operands[0], GEN_INT (0x3)));
+
+ /* 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));
+
+ /* 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);
+ emit_insn (gen_rs6000_mtfsf (GEN_INT (0x01), tmp_df));
+ }
+ DONE;
+})
+
+(define_expand "rs6000_set_fpscr_drn"
+ [(match_operand:DI 0 "gpc_reg_operand")]
+ "TARGET_HARD_FLOAT"
+{
+ rtx tmp_df = gen_reg_rtx (DFmode);
+
+ /* The decimal floating point rounding control bits are FPSCR[29:31]. Put the
+ new rounding mode bits from operands[0][61:63] into FPSCR[29:31]. */
+ if (TARGET_P9_MISC)
+ {
+ rtx src_df = gen_reg_rtx (DFmode);
+
+ emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
+ src_df = simplify_gen_subreg (DFmode, operands[0], DImode, 0);
+ emit_insn (gen_rs6000_mffscdrn (tmp_df, src_df));
+ }
+ else
+ {
+ rtx tmp_rn = gen_reg_rtx (DImode);
+ rtx tmp_di = gen_reg_rtx (DImode);
+
+ /* Extract new DRN mode from operand. */
+ emit_insn (gen_anddi3 (tmp_rn, operands[0], GEN_INT (0x7)));
+ emit_insn (gen_ashldi3 (tmp_rn, tmp_rn, GEN_INT (32)));
+
+ /* 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 (0xFFFFFFF8FFFFFFFF)));
+ emit_insn (gen_iordi3 (tmp_di, tmp_di, tmp_rn));
+
+ /* Need to write to field 7. The fields are [0:15]. The equation to
+ select the field is i + 8*(1-W). Hence with L=0 and W=1, need to set
+ i to 0x1 to get field 7 where i selects the field. */
+ tmp_df = simplify_gen_subreg (DFmode, tmp_di, DImode, 0);
+ emit_insn (gen_rs6000_mtfsf_hi (GEN_INT (0x01), tmp_df));
+ }
+ DONE;
+})
+
;; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
;; rather than (set (subreg:SI (reg)) (fix:SI ...))
;; because the first makes it clear that operand 0 is not live
})
\f
+;; The ISA 3.0 mffsl instruction is a lower latency instruction
+;; for reading bits [29:31], [45:51] and [56:63] of the FPSCR.
+(define_insn "rs6000_mffsl_hw"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+ (unspec_volatile:DF [(const_int 0)] UNSPECV_MFFSL))]
+ "TARGET_HARD_FLOAT"
+ "mffsl %0")
+
+(define_expand "rs6000_mffsl"
+ [(set (match_operand:DF 0 "gpc_reg_operand")
+ (unspec_volatile:DF [(const_int 0)] UNSPECV_MFFSL))]
+ "TARGET_HARD_FLOAT"
+{
+ /* If the low latency mffsl instruction (ISA 3.0) is available use it,
+ otherwise fall back to the older mffs instruction to emulate the mffsl
+ instruction. */
+
+ if (!TARGET_P9_MISC)
+ {
+ rtx tmp_di = gen_reg_rtx (DImode);
+ rtx tmp_df = gen_reg_rtx (DFmode);
+
+ /* The mffs instruction reads the entire FPSCR. Emulate the mffsl
+ instruction using the mffs instruction and masking off the bits
+ the mmsl instruciton actually reads. */
+ 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 (0x70007f0ffLL)));
+
+ operands[0] = simplify_gen_subreg (DFmode, tmp_di, DImode, 0);
+ DONE;
+ }
+
+ emit_insn (gen_rs6000_mffsl_hw (operands[0]));
+ DONE;
+})
+
(define_insn "rs6000_mffs"
[(set (match_operand:DF 0 "gpc_reg_operand" "=d")
(unspec_volatile:DF [(const_int 0)] UNSPECV_MFFS))]
"TARGET_HARD_FLOAT"
"mtfsf %0,%1")
+(define_insn "rs6000_mtfsf_hi"
+ [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n")
+ (match_operand:DF 1 "gpc_reg_operand" "d")]
+ UNSPECV_MTFSF_HI)]
+ "TARGET_HARD_FLOAT"
+ "mtfsf %0,%1,0,1")
+
\f
;; Power8 fusion support for fusing an addis instruction with a D-form load of
;; a GPR. The addis instruction must be adjacent to the load, and use the same
unsigned long __builtin_ppc_mftb ();
__ibm128 __builtin_unpack_ibm128 (__ibm128, int);
__ibm128 __builtin_pack_ibm128 (double, double);
+double __builtin_mffs (void);
+void __builtin_mtfsb0 (const int);
+void __builtin_mtfsb1 (const int);
+void __builtin_set_fpscr_rn (int);
@end smallexample
The @code{__builtin_ppc_get_timebase} and @code{__builtin_ppc_mftb}
instructions and always returns the 64 bits of the Time Base Register.
The @code{__builtin_ppc_mftb} function always generates one instruction and
returns the Time Base Register value as an unsigned long, throwing away
-the most significant word on 32-bit environments.
+the most significant word on 32-bit environments. The @code{__builtin_mffs}
+return the value of the FPSCR register. Note, ISA 3.0 supports the
+@code{__builtin_mffsl()} which permits software to read the control and
+non-sticky status bits in the FSPCR without the higher latency associated with
+accessing the sticky status bits. The
+@code{__builtin_mtfsb0} and @code{__builtin_mtfsb1} take the bit to change
+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 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.
@node Basic PowerPC Built-in Functions Available on ISA 2.05
@subsubsection Basic PowerPC Built-in Functions Available on ISA 2.05
when hardware decimal floating point
(@option{-mhard-dfp}) is available:
@smallexample
+void __builtin_set_fpscr_drn(int);
_Decimal64 __builtin_ddedpd (int, _Decimal64);
_Decimal128 __builtin_ddedpdq (int, _Decimal128);
_Decimal64 __builtin_denbcd (int, _Decimal64);
long long __builtin_dxexq (_Decimal128);
_Decimal128 __builtin_pack_dec128 (unsigned long long, unsigned long long);
unsigned long long __builtin_unpack_dec128 (_Decimal128, int);
+
+The @code{__builtin_set_fpscr_drn} builtin allows changing the three decimal
+floating point rounding mode bits. The argument is a 3-bit value. The
+argument can either be a const int or the value can be stored in a variable.
+The builtin uses the ISA 3.0 instruction @code{mffscdrn} if available.
+Otherwise the builtin reads the FPSCR, masks the current decimal rounding
+mode bits out and OR's in the new value.
+
@end smallexample
The following functions require @option{-mhard-float},
int __builtin_dfp_dtstsfi_ov (unsigned int comparison, _Decimal128 value);
int __builtin_dfp_dtstsfi_ov_dd (unsigned int comparison, _Decimal64 value);
int __builtin_dfp_dtstsfi_ov_td (unsigned int comparison, _Decimal128 value);
+
+double __builtin_mffsl(void);
+
@end smallexample
The @code{__builtin_byte_in_set} function requires a
64-bit environment supporting ISA 3.0 or later. This function returns
require that the type of the @code{value} argument be
@code{__Decimal64} and @code{__Decimal128} respectively.
+The @code{__builtin_mffsl} uses the ISA 3.0 @code{mffsl} instruction to read
+the FPSCR. The instruction is a lower latency version of the @code{mffs}
+instruction. If the @code{mffsl} instruction is not available, then the
+builtin uses the older @code{mffs} instruction to read the FPSCR.
+
+
@node PowerPC AltiVec/VSX Built-in Functions
@subsection PowerPC AltiVec/VSX Built-in Functions
+2018-10-01 Carl Love <cel@us.ibm.com>
+
+ * gcc.target/powerpc/test_mffsl-p9.c: New file.
+ * gcc.target/powerpc/test_fpscr_rn_builtin.c: New file.
+ * gcc.target/powerpc/test_fpscr_drn_builtin.c: New file.
+ * gcc.target/powerpc/test_fpscr_rn_builtin_error.c: New file.
+ * gcc.target/powerpc/test_fpscr_drn_builtin_error.c: New file.
+
2018-10-01 Paul Thomas <pault@gcc.gnu.org>
PR fortran/65677
--- /dev/null
+/* { dg-do run { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target dfp_hw } */
+/* { dg-options "-O2 -std=c99" } */
+
+#include <altivec.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#define DRN_MASK 0x700000000LL /* DRN field mask */
+
+void abort (void);
+
+int main ()
+{
+ int i;
+ int val, bit;
+ double fpscr_val;
+ union blah {
+ double d;
+ unsigned long long ll;
+ } conv_val;
+
+ unsigned long long ll_value;
+ register double f14;
+
+ /* __builtin_set_fpscr_drn() builtin can take a const or a variable
+ value between 0 and 7 as the argument.
+ */
+
+ /* Test builtin decimal float rounding mode with const argument. */
+ __builtin_set_fpscr_drn(7);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & DRN_MASK;
+
+ if (ll_value != 0x700000000)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_drn(7) did not set rounding mode to 7.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_set_fpscr_drn(2);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & DRN_MASK;
+
+ if (ll_value != 0x200000000)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_drn(2) did not set rounding mode to 2.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_set_fpscr_drn(5);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & DRN_MASK;
+
+ if (ll_value != 0x500000000)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_drn(5) did not set rounding mode to 5.\n");
+#else
+ abort();
+#endif
+ }
+
+ /* Test builtin decimal float rounding mode with variable as argument. */
+ val = 7;
+ __builtin_set_fpscr_drn(val);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & DRN_MASK;
+
+ if (ll_value != ((unsigned long long)val << 32))
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_drn(val=%d) did not set rounding mode to %d.\n",
+ val, val);
+#else
+ abort();
+#endif
+ }
+
+ val = 0;
+ __builtin_set_fpscr_drn(val);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & DRN_MASK;
+
+ if (ll_value != ((unsigned long long)val << 32))
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_drn(val=%d) did not set rounding mode to %d.\n",
+ val, val);
+#else
+ abort();
+#endif
+ }
+
+ val = 2;
+ __builtin_set_fpscr_drn(val);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & DRN_MASK;
+
+ if (ll_value != ((unsigned long long)val << 32))
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_drn(val=%d) did not set rounding mode to %d.\n",
+ val, val);
+#else
+ abort();
+#endif
+ }
+}
--- /dev/null
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-require-effective-target dfp_hw } */
+/* { dg-options "-O2 -std=c99" } */
+
+#include <altivec.h>
+
+int main ()
+{
+
+ /* Test builin with out of range arguments. The builtin
+ __builtin_set_fpscr_drn() also support a variable as an argument but
+ can't test variable value at compile time. */
+
+ __builtin_set_fpscr_drn(-1); /* { dg-error "Argument must be a value between 0 and 7" } */
+ __builtin_set_fpscr_drn(8); /* { dg-error "Argument must be a value between 0 and 7" } */
+
+}
+
--- /dev/null
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-options "-O2 -std=c99" } */
+
+#include <altivec.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#define RN_MASK 0x3LL /* RN field mask */
+
+void abort (void);
+
+int main ()
+{
+ int i;
+ int val, bit;
+ double fpscr_val;
+ union blah {
+ double d;
+ unsigned long long ll;
+ } conv_val;
+
+ unsigned long long ll_value;
+ register double f14;
+
+ /* __builtin_set_fpscr_rn() builtin 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.
+ */
+
+ /* 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 expecected value 0x%llx\n",
+ __builtin_mffs(), conv_val.d);
+#else
+ abort();
+#endif
+ }
+
+ /* Test float rounding mode builtin with const value argument. */
+ __builtin_set_fpscr_rn(3);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & RN_MASK;
+
+ if (ll_value != 3)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_rn(3) returned 0x%llx, not the expecected value 0x%x\n",
+ ll_value, 3);
+#else
+ abort();
+#endif
+ }
+
+ val = 2;
+ __builtin_set_fpscr_rn(val);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & RN_MASK;
+
+ if (ll_value != val)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_rn(val=%d) returned 0x%llx, not the expecected value 0x%x\n",
+ val, ll_value, val);
+#else
+ abort();
+#endif
+ }
+
+ /* Reset to 0 for testing */
+ val = 0;
+ __builtin_set_fpscr_rn(val);
+
+ __builtin_mtfsb1(31);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & 0x1LL;
+
+ if (ll_value != 1)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mtfsb1(31) did not set the bit to a 1.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_mtfsb0(31);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & 0x1LL;
+
+ if (ll_value != 0)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mtfsb0(31) did not set the bit to a 0.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_mtfsb1(30);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & 0x2LL;
+
+ if (ll_value != 2)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mtfsb1(31) did not set the bit to a 1.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_mtfsb0(30);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & 0x2LL;
+
+ if (ll_value != 0)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mtfsb1(31) did not set the bit to a 0.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_mtfsb1(0);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & (0x1LL << (31-0));
+
+ if (ll_value != (0x1LL << (31-0)))
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mtfsb1(0) did not set the bit to a 1.\n");
+#else
+ abort();
+#endif
+ }
+
+ __builtin_mtfsb0(0);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & (0x1LL << (31-0));
+
+ if (ll_value != 0)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mtfsb0(0) did not set the bit to a 0.\n");
+#else
+ abort();
+#endif
+ }
+
+
+ /* Test builtin float rounding mode with variable as argument. */
+ val = 0;
+ __builtin_set_fpscr_rn(val);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & RN_MASK;
+
+ if (ll_value != val)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_rn(val=%d) did not set rounding mode to %x.\n",
+ val, val);
+#else
+ abort();
+#endif
+ }
+
+ val = 3;
+ __builtin_set_fpscr_rn(val);
+ conv_val.d = __builtin_mffs();
+ ll_value = conv_val.ll & RN_MASK;
+
+ if (ll_value != val)
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_set_fpscr_rn(val=%d) did not set rounding mode to %x.\n",
+ val, val);
+#else
+ abort();
+#endif
+ }
+}
--- /dev/null
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-options "-O2 -std=c99" } */
+
+#include <altivec.h>
+
+int main ()
+{
+
+ /* Test builin with out of range arguments. Can only test for constant
+ int arguments. The builtins __builtin_set_fpscr_rn() also supports a
+ variable as an argument but can't test variable value at compile time. */
+
+ __builtin_mtfsb0(-1); /* { dg-error "Argument must be a constant between 0 and 31" } */
+ __builtin_mtfsb0(32); /* { dg-error "Argument must be a constant between 0 and 31" } */
+
+ __builtin_mtfsb1(-1); /* { dg-error "Argument must be a constant between 0 and 31" } */
+ __builtin_mtfsb1(32); /* { dg-error "Argument must be a constant between 0 and 31" } */
+
+ __builtin_set_fpscr_rn(-1); /* { dg-error "Argument must be a value between 0 and 3" } */
+ __builtin_set_fpscr_rn(4); /* { dg-error "Argument must be a value between 0 and 3" } */
+}
+
--- /dev/null
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-options "-O2 -std=c99" } */
+
+#include <altivec.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+void abort (void);
+
+int main ()
+{
+
+ register double f14;
+ union blah {
+ double d;
+ unsigned long long ll;
+ } conv_val;
+
+ /* Test reading the FPSCR register. */
+ __asm __volatile ("mffs %0" : "=f"(f14));
+ conv_val.d = f14;
+
+ if (conv_val.d != __builtin_mffsl())
+ {
+#ifdef DEBUG
+ printf("ERROR, __builtin_mffsl() returned 0x%llx, not the expecected value 0x%llx\n",
+ __builtin_mffsl(), conv_val.d);
+#else
+ abort();
+#endif
+ }
+}