Commit 2da14663 by Carl Love Committed by Carl Love

rs6000-builtin.def (__builtin_mffsl): New.

gcc/ChangeLog:

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.

gcc/testsuite/ChangeLog:

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.

From-SVN: r264762
parent 3553df86
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
......@@ -2486,11 +2486,35 @@ BU_SPECIAL_X (RS6000_BUILTIN_MFTB, "__builtin_ppc_mftb",
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)
......
......@@ -13260,6 +13260,13 @@ rs6000_expand_zeroop_builtin (enum insn_code icode, rtx target)
/* 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))
......@@ -13308,6 +13315,134 @@ rs6000_expand_mtfsf_builtin (enum insn_code icode, tree exp)
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);
......@@ -16066,6 +16201,24 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
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);
......@@ -16449,6 +16602,29 @@ rs6000_init_builtins (void)
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);
......@@ -163,7 +163,13 @@
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
])
......@@ -5811,6 +5817,129 @@
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
......@@ -13507,6 +13636,43 @@
})
;; 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))]
......@@ -13520,6 +13686,13 @@
"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")
;; 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
......
......@@ -15781,6 +15781,10 @@ uint64_t __builtin_ppc_get_timebase ();
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}
......@@ -15789,7 +15793,21 @@ functions generate instructions to read the Time Base Register. The
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
......@@ -15825,6 +15843,7 @@ The following built-in functions are available
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);
......@@ -15839,6 +15858,14 @@ long long __builtin_dxex (_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},
......@@ -16040,6 +16067,9 @@ int __builtin_dfp_dtstsfi_ov (unsigned int comparison, _Decimal64 value);
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
......@@ -16091,6 +16121,12 @@ The @code{__builtin_dfp_dtstsfi_ov_dd} and
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
......
/* { 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
}
}
/* { 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" } */
}
/* { 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
}
}
/* { 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" } */
}
/* { 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
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment