This patch adds builtins to load and store the PowerPC floating point status and control register.
* config/rs6000/rs6000.c (rs6000_expand_mtfsf_builtin): New. (rs6000_expand_builtin): Handle mffs and mtfsf. (rs6000_init_builtins): Define mffs and mtfsf. * config/rs6000/rs6000.md (UNSPECV_MFFS, UNSPECV_MTFSF): New constants. (rs6000_mffs): New pattern. (rs6000_mtfsf): New pattern. Index: rs6000-builtin.def =================================================================== --- rs6000-builtin.def (revision 206552) +++ rs6000-builtin.def (working copy) @@ -1752,6 +1752,14 @@ BU_SPECIAL_X (RS6000_BUILTIN_MFTB, "__builtin_ppc_mftb", RS6000_BTM_ALWAYS, RS6000_BTC_MISC) +BU_SPECIAL_X (RS6000_BUILTIN_MFFS, "__builtin_mffs", + 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) + /* Darwin CfString builtin. */ BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS, RS6000_BTC_MISC) Index: rs6000.c =================================================================== --- rs6000.c (revision 206552) +++ rs6000.c (working copy) @@ -11469,6 +11470,48 @@ static rtx +rs6000_expand_mtfsf_builtin (enum insn_code icode, tree exp, rtx target) +{ + rtx pat; + tree arg0 = CALL_EXPR_ARG (exp, 0); + tree arg1 = CALL_EXPR_ARG (exp, 1); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + enum machine_mode mode0 = insn_data[icode].operand[0].mode; + enum machine_mode mode1 = insn_data[icode].operand[1].mode; + + 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 || arg1 == error_mark_node) + return const0_rtx; + + if (GET_CODE (op0) != CONST_INT + || INTVAL (op0) > 255 + || INTVAL (op0) < 0) + { + error ("argument 1 must be an 8-bit field value"); + return const0_rtx; + } + + if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + + if (! (*insn_data[icode].operand[1].predicate) (op1, mode1)) + 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_unop_builtin (enum insn_code icode, tree exp, rtx target) { rtx pat; @@ -13277,6 +13320,12 @@ : CODE_FOR_rs6000_mftb_si), target); + case RS6000_BUILTIN_MFFS: + return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target); + + case RS6000_BUILTIN_MTFSF: + return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp, target); + case ALTIVEC_BUILTIN_MASK_FOR_LOAD: case ALTIVEC_BUILTIN_MASK_FOR_STORE: { @@ -13584,6 +13633,14 @@ NULL_TREE); def_builtin ("__builtin_ppc_mftb", ftype, RS6000_BUILTIN_MFTB); + ftype = build_function_type_list (double_type_node, NULL_TREE); + def_builtin ("__builtin_mffs", ftype, RS6000_BUILTIN_MFFS); + + ftype = build_function_type_list (void_type_node, + intSI_type_node, double_type_node, + NULL_TREE); + def_builtin ("__builtin_mtfsf", ftype, RS6000_BUILTIN_MTFSF); + #if TARGET_XCOFF /* AIX libm provides clog as __clog. */ if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) Index: rs6000.md =================================================================== --- rs6000.md (revision 206552) +++ rs6000.md (working copy) @@ -140,6 +140,8 @@ UNSPECV_ISYNC ; isync instruction UNSPECV_MFTB ; move from time base UNSPECV_NLGR ; non-local goto receiver + UNSPECV_MFFS ; Move from FPSCR + UNSPECV_MTFSF ; Move to FPSCR Fields ]) @@ -15587,6 +15589,20 @@ }) +(define_insn "rs6000_mffs" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (unspec_volatile:DF [(const_int 0)] UNSPECV_MFFS))] + "TARGET_HARD_FLOAT && TARGET_FPRS" + "mffs %0") + +(define_insn "rs6000_mtfsf" + [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i") + (match_operand:DF 1 "gpc_reg_operand" "d")] + UNSPECV_MTFSF)] + "TARGET_HARD_FLOAT && TARGET_FPRS" + "mtfsf %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 ;; register that is being loaded. The fused ops must be physically adjacent.