diff mbox series

rs6000, Add bcd builtings listed in appendix B of the ABI

Message ID fcd65e2bc7da9191e75fc4ecaac6334a8f02ef77.camel@us.ibm.com
State New
Headers show
Series rs6000, Add bcd builtings listed in appendix B of the ABI | expand

Commit Message

Carl Love Oct. 24, 2020, 1:56 a.m. UTC
Gcc maintainers:

The following patch adds support for the built-ins listed in Table B.1,
"Binary-Coded Decimal Built-In Functions" of the "64-Bit ELF V2 ABI
Specification", July 30, 2019.

The built-ins adds support the V16QI type for addition, subtraction and
comparison as sepcified in the Table B.1.  Note, the V1TI type was
previously supported for add, subtract and comparison.  The builtins
for test for valid value, multiply by 10, divide by 10 and conversion
to DFP value are also added for the V16QI type as specified in Table
B.1.

The patch includes adding the #include <altivec.h> to the existing bcd-
2.c and bcd-3.c tests so they will pass the regression tests as the
builtins names are now listed in altivec.h rather then just using
internal names.

The patch was compiled and tested on:

  powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions. 

Please let me know if this patch is acceptable for mainline.  Thanks.

                Carl Love
--------------------------------------------------

gcc/ChangeLog

2020-10-22  Carl Love  <cel@us.ibm.com>

	* config/rs6000/altivec.h (__builtin_bcdadd, __builtin_bcdadd_lt,
	__builtin_bcdadd_eq, __builtin_bcdadd_gt, __builtin_bcdadd_ofl,
	__builtin_bcdadd_ov, __builtin_bcdsub, __builtin_bcdsub_lt,
	__builtin_bcdsub_eq, __builtin_bcdsub_gt, __builtin_bcdsub_ofl,
	__builtin_bcdsub_ov, __builtin_bcdinvalid, __builtin_bcdmul10,
	__builtin_bcddiv10, __builtin_bcd2dfp, __builtin_bcdcmpeq,
 	__builtin_bcdcmpgt, __builtin_bcdcmplt, __builtin_bcdcmpge,
	__builtin_bcdcmple): Add defines.
	* config/rs6000/altivec.md: Add UNSPEC_BCDSHIFT.
	(BCD_TEST): Add le, ge to code iterator.
	Add VBCD mode iterator.
	(bcd<bcd_add_sub>_test, *bcd<bcd_add_sub>_test2,
	bcd<bcd_add_sub>_<code>, bcd<bcd_add_sub>_<code>): Add mode to name.
	Change iterator from V1TI to VBCD.
	(*bcdinvalid_<mode>, bcdshift_v16qi): New define_insn.
	(bcdinvalid_<mode>, bcdmul10_v16qi, bcddiv10_v16qi): New define.
	config/rs6000/dfp.md (dfp_denbcd_v16qi_inst): New define_insn.
	(dfp_denbcd_v16qi): New define_expand.
	* confit/rs6000/rs6000-builtin.def (BU_P8V_MISC_1): New define.
	(BCDADD): Replaced with BCDADD_V1TI and BCDADD_V16QI.
	(BCDADD_LT): Replaced with BCDADD_LT_V1TI and BCDADD_LT_V16QI.
	(BCDADD_EQ): Replaced with BCDADD_EQ_V1TI and BCDADD_EQ_V16QI.
	(BCDADD_GT): Replaced with BCDADD_GT_V1TI and BCDADD_GT_V16QI.
	(BCDADD_OV): Replaced with BCDADD_OV_V1TI and BCDADD_OV_V16QI.
	(BCDSUB_V1TI, BCDSUB_V16QI, BCDSUB_LT_V1TI, BCDSUB_LT_V16QI,
	BCDSUB_LE_V1TI, BCDSUB_LE_V16QI, BCDSUB_EQ_V1TI, BCDSUB_EQ_V16QI,
	BCDSUB_GT_V1TI, BCDSUB_GT_V16QI, BCDSUB_GE_V1TI, BCDSUB_GE_V16QI,
	BCDSUB_OV_V1TI, BCDSUB_OV_V16QI, BCDINVALID_V1TI, BCDINVALID_V16QI,
	BCDMUL10_V16QI, BCDDIV10_V16QI, DENBCD_V16QI): New builtin definitions.
	(BCDADD, BCDADD_LT, BCDADD_EQ, BCDADD_GT, BCDADD_OV, BCDSUB, BCDSUB_LT,
	BCDSUB_LE, BCDSUB_EQ, BCDSUB_GT, BCDSUB_GE, BCDSUB_OV, BCDINVALID,
	BCDMUL10, BCDDIV10, DENBCD): New overload definitions.
	config/rs6000/rs6000-call.c (P8V_BUILTIN_VEC_BCDADD, P8V_BUILTIN_VEC_BCDADD_LT,
	P8V_BUILTIN_VEC_BCDADD_EQ, P8V_BUILTIN_VEC_BCDADD_GT, P8V_BUILTIN_VEC_BCDADD_OV,
	P8V_BUILTIN_VEC_BCDINVALID, P9V_BUILTIN_VEC_BCDMUL10, P8V_BUILTIN_VEC_DENBCD.
	P8V_BUILTIN_VEC_BCDSUB, P8V_BUILTIN_VEC_BCDSUB_LT, P8V_BUILTIN_VEC_BCDSUB_LE,
	P8V_BUILTIN_VEC_BCDSUB_EQ, P8V_BUILTIN_VEC_BCDSUB_GT, P8V_BUILTIN_VEC_BCDSUB_GE,
	P8V_BUILTIN_VEC_BCDSUB_OV): New overloaded specifications.
	(CODE_FOR_bcdadd): Replaced with CODE_FOR_bcdadd_v16qi and CODE_FOR_bcdadd_v1ti.
	(CODE_FOR_bcdadd_lt): Replaced with CODE_FOR_bcdadd_lt_v16qi and CODE_FOR_bcdadd_lt_v1ti.
	(CODE_FOR_bcdadd_eq): Replaced with CODE_FOR_bcdadd_eq_v16qi and CODE_FOR_bcdadd_eq_v1ti.
	(CODE_FOR_bcdadd_gt): Replaced with CODE_FOR_bcdadd_gt_v16qi and CODE_FOR_bcdadd_gt_v1ti.
	(CODE_FOR_bcdsub): Replaced with CODE_FOR_bcdsub_v16qi and CODE_FOR_bcdsub_v1ti.
	(CODE_FOR_bcdsub_lt): Replaced with CODE_FOR_bcdsub_lt_v16qi and CODE_FOR_bcdsub_lt_v1ti.
	(CODE_FOR_bcdsub_eq): Replaced with CODE_FOR_bcdsub_eq_v16qi and CODE_FOR_bcdsub_eq_v1ti.
	(CODE_FOR_bcdsub_gt): Replaced with CODE_FOR_bcdsub_gt_v16qi and CODE_FOR_bcdsub_gt_v1ti.
	(rs6000_expand_ternop_builtin):  Add CODE_FOR_dfp_denbcd_v16qi to else if.
	* doc/extend.texi: Add documentation for new builtins.
	* testsuite/gcc.target/powerpc/bcd-3.c: Add include altivec.h.
	* testsuite/gcc.target/powerpc/bcd-4.c: New test.
---
 gcc/config/rs6000/altivec.h              |  25 ++
 gcc/config/rs6000/altivec.md             | 104 ++++-
 gcc/config/rs6000/dfp.md                 |  22 +
 gcc/config/rs6000/rs6000-builtin.def     |  67 ++-
 gcc/config/rs6000/rs6000-call.c          | 103 ++++-
 gcc/doc/extend.texi                      |  13 +
 gcc/testsuite/gcc.target/powerpc/bcd-2.c |   2 +
 gcc/testsuite/gcc.target/powerpc/bcd-3.c |   2 +
 gcc/testsuite/gcc.target/powerpc/bcd-4.c | 519 +++++++++++++++++++++++
 9 files changed, 821 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/bcd-4.c

Comments

David Edelsohn Oct. 24, 2020, 3:29 p.m. UTC | #1
Hi, Carl

Not commenting on the implementation.

Please stop using powerpc*-*-* in the test cases.  The test cases
already are in the gcc.target/powerpc directory.

Do the test cases really need lp64, or should this require something
like int128?

Thanks, David

On Fri, Oct 23, 2020 at 9:56 PM Carl Love <cel@us.ibm.com> wrote:
>
>
> Gcc maintainers:
>
> The following patch adds support for the built-ins listed in Table B.1,
> "Binary-Coded Decimal Built-In Functions" of the "64-Bit ELF V2 ABI
> Specification", July 30, 2019.
>
> The built-ins adds support the V16QI type for addition, subtraction and
> comparison as sepcified in the Table B.1.  Note, the V1TI type was
> previously supported for add, subtract and comparison.  The builtins
> for test for valid value, multiply by 10, divide by 10 and conversion
> to DFP value are also added for the V16QI type as specified in Table
> B.1.
>
> The patch includes adding the #include <altivec.h> to the existing bcd-
> 2.c and bcd-3.c tests so they will pass the regression tests as the
> builtins names are now listed in altivec.h rather then just using
> internal names.
>
> The patch was compiled and tested on:
>
>   powerpc64le-unknown-linux-gnu (Power 9 LE)
>
> with no regressions.
>
> Please let me know if this patch is acceptable for mainline.  Thanks.
>
>                 Carl Love
> --------------------------------------------------
>
> gcc/ChangeLog
>
> 2020-10-22  Carl Love  <cel@us.ibm.com>
>
>         * config/rs6000/altivec.h (__builtin_bcdadd, __builtin_bcdadd_lt,
>         __builtin_bcdadd_eq, __builtin_bcdadd_gt, __builtin_bcdadd_ofl,
>         __builtin_bcdadd_ov, __builtin_bcdsub, __builtin_bcdsub_lt,
>         __builtin_bcdsub_eq, __builtin_bcdsub_gt, __builtin_bcdsub_ofl,
>         __builtin_bcdsub_ov, __builtin_bcdinvalid, __builtin_bcdmul10,
>         __builtin_bcddiv10, __builtin_bcd2dfp, __builtin_bcdcmpeq,
>         __builtin_bcdcmpgt, __builtin_bcdcmplt, __builtin_bcdcmpge,
>         __builtin_bcdcmple): Add defines.
>         * config/rs6000/altivec.md: Add UNSPEC_BCDSHIFT.
>         (BCD_TEST): Add le, ge to code iterator.
>         Add VBCD mode iterator.
>         (bcd<bcd_add_sub>_test, *bcd<bcd_add_sub>_test2,
>         bcd<bcd_add_sub>_<code>, bcd<bcd_add_sub>_<code>): Add mode to name.
>         Change iterator from V1TI to VBCD.
>         (*bcdinvalid_<mode>, bcdshift_v16qi): New define_insn.
>         (bcdinvalid_<mode>, bcdmul10_v16qi, bcddiv10_v16qi): New define.
>         config/rs6000/dfp.md (dfp_denbcd_v16qi_inst): New define_insn.
>         (dfp_denbcd_v16qi): New define_expand.
>         * confit/rs6000/rs6000-builtin.def (BU_P8V_MISC_1): New define.
>         (BCDADD): Replaced with BCDADD_V1TI and BCDADD_V16QI.
>         (BCDADD_LT): Replaced with BCDADD_LT_V1TI and BCDADD_LT_V16QI.
>         (BCDADD_EQ): Replaced with BCDADD_EQ_V1TI and BCDADD_EQ_V16QI.
>         (BCDADD_GT): Replaced with BCDADD_GT_V1TI and BCDADD_GT_V16QI.
>         (BCDADD_OV): Replaced with BCDADD_OV_V1TI and BCDADD_OV_V16QI.
>         (BCDSUB_V1TI, BCDSUB_V16QI, BCDSUB_LT_V1TI, BCDSUB_LT_V16QI,
>         BCDSUB_LE_V1TI, BCDSUB_LE_V16QI, BCDSUB_EQ_V1TI, BCDSUB_EQ_V16QI,
>         BCDSUB_GT_V1TI, BCDSUB_GT_V16QI, BCDSUB_GE_V1TI, BCDSUB_GE_V16QI,
>         BCDSUB_OV_V1TI, BCDSUB_OV_V16QI, BCDINVALID_V1TI, BCDINVALID_V16QI,
>         BCDMUL10_V16QI, BCDDIV10_V16QI, DENBCD_V16QI): New builtin definitions.
>         (BCDADD, BCDADD_LT, BCDADD_EQ, BCDADD_GT, BCDADD_OV, BCDSUB, BCDSUB_LT,
>         BCDSUB_LE, BCDSUB_EQ, BCDSUB_GT, BCDSUB_GE, BCDSUB_OV, BCDINVALID,
>         BCDMUL10, BCDDIV10, DENBCD): New overload definitions.
>         config/rs6000/rs6000-call.c (P8V_BUILTIN_VEC_BCDADD, P8V_BUILTIN_VEC_BCDADD_LT,
>         P8V_BUILTIN_VEC_BCDADD_EQ, P8V_BUILTIN_VEC_BCDADD_GT, P8V_BUILTIN_VEC_BCDADD_OV,
>         P8V_BUILTIN_VEC_BCDINVALID, P9V_BUILTIN_VEC_BCDMUL10, P8V_BUILTIN_VEC_DENBCD.
>         P8V_BUILTIN_VEC_BCDSUB, P8V_BUILTIN_VEC_BCDSUB_LT, P8V_BUILTIN_VEC_BCDSUB_LE,
>         P8V_BUILTIN_VEC_BCDSUB_EQ, P8V_BUILTIN_VEC_BCDSUB_GT, P8V_BUILTIN_VEC_BCDSUB_GE,
>         P8V_BUILTIN_VEC_BCDSUB_OV): New overloaded specifications.
>         (CODE_FOR_bcdadd): Replaced with CODE_FOR_bcdadd_v16qi and CODE_FOR_bcdadd_v1ti.
>         (CODE_FOR_bcdadd_lt): Replaced with CODE_FOR_bcdadd_lt_v16qi and CODE_FOR_bcdadd_lt_v1ti.
>         (CODE_FOR_bcdadd_eq): Replaced with CODE_FOR_bcdadd_eq_v16qi and CODE_FOR_bcdadd_eq_v1ti.
>         (CODE_FOR_bcdadd_gt): Replaced with CODE_FOR_bcdadd_gt_v16qi and CODE_FOR_bcdadd_gt_v1ti.
>         (CODE_FOR_bcdsub): Replaced with CODE_FOR_bcdsub_v16qi and CODE_FOR_bcdsub_v1ti.
>         (CODE_FOR_bcdsub_lt): Replaced with CODE_FOR_bcdsub_lt_v16qi and CODE_FOR_bcdsub_lt_v1ti.
>         (CODE_FOR_bcdsub_eq): Replaced with CODE_FOR_bcdsub_eq_v16qi and CODE_FOR_bcdsub_eq_v1ti.
>         (CODE_FOR_bcdsub_gt): Replaced with CODE_FOR_bcdsub_gt_v16qi and CODE_FOR_bcdsub_gt_v1ti.
>         (rs6000_expand_ternop_builtin):  Add CODE_FOR_dfp_denbcd_v16qi to else if.
>         * doc/extend.texi: Add documentation for new builtins.
>         * testsuite/gcc.target/powerpc/bcd-3.c: Add include altivec.h.
>         * testsuite/gcc.target/powerpc/bcd-4.c: New test.
> ---
>  gcc/config/rs6000/altivec.h              |  25 ++
>  gcc/config/rs6000/altivec.md             | 104 ++++-
>  gcc/config/rs6000/dfp.md                 |  22 +
>  gcc/config/rs6000/rs6000-builtin.def     |  67 ++-
>  gcc/config/rs6000/rs6000-call.c          | 103 ++++-
>  gcc/doc/extend.texi                      |  13 +
>  gcc/testsuite/gcc.target/powerpc/bcd-2.c |   2 +
>  gcc/testsuite/gcc.target/powerpc/bcd-3.c |   2 +
>  gcc/testsuite/gcc.target/powerpc/bcd-4.c | 519 +++++++++++++++++++++++
>  9 files changed, 821 insertions(+), 36 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/powerpc/bcd-4.c
>
> diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
> index df10a8c498d..e1884f51bd8 100644
> --- a/gcc/config/rs6000/altivec.h
> +++ b/gcc/config/rs6000/altivec.h
> @@ -497,8 +497,33 @@
>
>  #define vec_xlx __builtin_vec_vextulx
>  #define vec_xrx __builtin_vec_vexturx
> +
>  #endif
>
> +/* BCD builtins, map ABI builtin name to existing builtin name.  */
> +#define __builtin_bcdadd     __builtin_vec_bcdadd
> +#define __builtin_bcdadd_lt  __builtin_vec_bcdadd_lt
> +#define __builtin_bcdadd_eq  __builtin_vec_bcdadd_eq
> +#define __builtin_bcdadd_gt  __builtin_vec_bcdadd_gt
> +#define __builtin_bcdadd_ofl __builtin_vec_bcdadd_ov
> +#define __builtin_bcdadd_ov  __builtin_vec_bcdadd_ov
> +#define __builtin_bcdsub     __builtin_vec_bcdsub
> +#define __builtin_bcdsub_lt  __builtin_vec_bcdsub_lt
> +#define __builtin_bcdsub_eq  __builtin_vec_bcdsub_eq
> +#define __builtin_bcdsub_gt  __builtin_vec_bcdsub_gt
> +#define __builtin_bcdsub_ofl __builtin_vec_bcdsub_ov
> +#define __builtin_bcdsub_ov  __builtin_vec_bcdsub_ov
> +#define __builtin_bcdinvalid __builtin_vec_bcdinvalid
> +#define __builtin_bcdmul10   __builtin_vec_bcdmul10
> +#define __builtin_bcddiv10   __builtin_vec_bcddiv10
> +#define __builtin_bcd2dfp    __builtin_vec_denb2dfp
> +#define __builtin_bcdcmpeq(a,b)   __builtin_vec_bcdsub_eq(a,b,0)
> +#define __builtin_bcdcmpgt(a,b)   __builtin_vec_bcdsub_gt(a,b,0)
> +#define __builtin_bcdcmplt(a,b)   __builtin_vec_bcdsub_lt(a,b,0)
> +#define __builtin_bcdcmpge(a,b)   __builtin_vec_bcdsub_ge(a,b,0)
> +#define __builtin_bcdcmple(a,b)   __builtin_vec_bcdsub_le(a,b,0)
> +
> +
>  /* Predicates.
>     For C++, we use templates in order to allow non-parenthesized arguments.
>     For C, instead, we use macros since non-parenthesized arguments were
> diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
> index 0a2e634d6b0..6a6ce0f84ed 100644
> --- a/gcc/config/rs6000/altivec.md
> +++ b/gcc/config/rs6000/altivec.md
> @@ -160,6 +160,7 @@
>     UNSPEC_BCDADD
>     UNSPEC_BCDSUB
>     UNSPEC_BCD_OVERFLOW
> +   UNSPEC_BCDSHIFT
>     UNSPEC_VRLMI
>     UNSPEC_VRLNM
>     UNSPEC_VCFUGED
> @@ -4410,12 +4411,13 @@
>  (define_int_attr bcd_add_sub [(UNSPEC_BCDADD "add")
>                               (UNSPEC_BCDSUB "sub")])
>
> -(define_code_iterator BCD_TEST [eq lt gt unordered])
> +(define_code_iterator BCD_TEST [eq lt le gt ge unordered])
> +(define_mode_iterator VBCD [V1TI V16QI])
>
> -(define_insn "bcd<bcd_add_sub>"
> -  [(set (match_operand:V1TI 0 "gpc_reg_operand" "=v")
> -       (unspec:V1TI [(match_operand:V1TI 1 "gpc_reg_operand" "v")
> -                     (match_operand:V1TI 2 "gpc_reg_operand" "v")
> +(define_insn "bcd<bcd_add_sub>_<mode>"
> +  [(set (match_operand:VBCD 0 "register_operand" "=v")
> +       (unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
> +                     (match_operand:VBCD 2 "register_operand" "v")
>                       (match_operand:QI 3 "const_0_to_1_operand" "n")]
>                      UNSPEC_BCD_ADD_SUB))
>     (clobber (reg:CCFP CR6_REGNO))]
> @@ -4428,23 +4430,23 @@
>  ;; UNORDERED test on an integer type (like V1TImode) is not defined.  The type
>  ;; probably should be one that can go in the VMX (Altivec) registers, so we
>  ;; can't use DDmode or DFmode.
> -(define_insn "*bcd<bcd_add_sub>_test"
> +(define_insn "*bcd<bcd_add_sub>_test_<mode>"
>    [(set (reg:CCFP CR6_REGNO)
>         (compare:CCFP
> -        (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "v")
> -                      (match_operand:V1TI 2 "register_operand" "v")
> +        (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")
> +                      (match_operand:VBCD 2 "register_operand" "v")
>                        (match_operand:QI 3 "const_0_to_1_operand" "i")]
>                       UNSPEC_BCD_ADD_SUB)
>          (match_operand:V2DF 4 "zero_constant" "j")))
> -   (clobber (match_scratch:V1TI 0 "=v"))]
> +   (clobber (match_scratch:VBCD 0 "=v"))]
>    "TARGET_P8_VECTOR"
>    "bcd<bcd_add_sub>. %0,%1,%2,%3"
>    [(set_attr "type" "vecsimple")])
>
> -(define_insn "*bcd<bcd_add_sub>_test2"
> -  [(set (match_operand:V1TI 0 "register_operand" "=v")
> -       (unspec:V1TI [(match_operand:V1TI 1 "register_operand" "v")
> -                     (match_operand:V1TI 2 "register_operand" "v")
> +(define_insn "*bcd<bcd_add_sub>_test2_<mode>"
> +  [(set (match_operand:VBCD 0 "register_operand" "=v")
> +       (unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
> +                     (match_operand:VBCD 2 "register_operand" "v")
>                       (match_operand:QI 3 "const_0_to_1_operand" "i")]
>                      UNSPEC_BCD_ADD_SUB))
>     (set (reg:CCFP CR6_REGNO)
> @@ -4540,15 +4542,15 @@
>  }
>     [(set_attr "type" "vecsimple")])
>
> -(define_expand "bcd<bcd_add_sub>_<code>"
> +(define_expand "bcd<bcd_add_sub>_<code>_<mode>"
>    [(parallel [(set (reg:CCFP CR6_REGNO)
>                    (compare:CCFP
> -                   (unspec:V2DF [(match_operand:V1TI 1 "register_operand")
> -                                 (match_operand:V1TI 2 "register_operand")
> +                   (unspec:V2DF [(match_operand:VBCD 1 "register_operand")
> +                                 (match_operand:VBCD 2 "register_operand")
>                                   (match_operand:QI 3 "const_0_to_1_operand")]
>                                  UNSPEC_BCD_ADD_SUB)
>                     (match_dup 4)))
> -             (clobber (match_scratch:V1TI 5))])
> +             (clobber (match_scratch:VBCD 5))])
>     (set (match_operand:SI 0 "register_operand")
>         (BCD_TEST:SI (reg:CCFP CR6_REGNO)
>                      (const_int 0)))]
> @@ -4557,6 +4559,74 @@
>    operands[4] = CONST0_RTX (V2DFmode);
>  })
>
> +(define_insn "*bcdinvalid_<mode>"
> +  [(set (reg:CCFP CR6_REGNO)
> +       (compare:CCFP
> +        (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")]
> +                     UNSPEC_BCDADD)
> +        (match_operand:V2DF 2 "zero_constant" "j")))
> +   (clobber (match_scratch:VBCD 0 "=v"))]
> +  "TARGET_P8_VECTOR"
> +  "bcdadd. %0,%1,%1,0"
> +  [(set_attr "type" "vecsimple")])
> +
> +(define_expand "bcdinvalid_<mode>"
> +  [(parallel [(set (reg:CCFP CR6_REGNO)
> +                  (compare:CCFP
> +                   (unspec:V2DF [(match_operand:VBCD 1 "register_operand")]
> +                                UNSPEC_BCDADD)
> +                   (match_dup 2)))
> +             (clobber (match_scratch:VBCD 3))])
> +   (set (match_operand:SI 0 "register_operand")
> +       (unordered:SI (reg:CCFP CR6_REGNO)
> +                     (const_int 0)))]
> +  "TARGET_P8_VECTOR"
> +{
> +  operands[2] = CONST0_RTX (V2DFmode);
> +})
> +
> +(define_insn "bcdshift_v16qi"
> +  [(set (match_operand:V16QI 0 "register_operand" "=v")
> +       (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
> +                      (match_operand:V16QI 2 "register_operand" "v")
> +                      (match_operand:QI 3 "const_0_to_1_operand" "n")]
> +                    UNSPEC_BCDSHIFT))
> +   (clobber (reg:CCFP CR6_REGNO))]
> +  "TARGET_P8_VECTOR"
> +  "bcds. %0,%1,%2,%3"
> +  [(set_attr "type" "vecsimple")])
> +
> +(define_expand "bcdmul10_v16qi"
> +  [(set (match_operand:V16QI 0 "register_operand")
> +       (unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
> +                     UNSPEC_BCDSHIFT))
> +   (clobber (reg:CCFP CR6_REGNO))]
> +  "TARGET_P9_VECTOR"
> +{
> +  rtx one = gen_reg_rtx (V16QImode);
> +
> +  emit_insn (gen_altivec_vspltisb (one, const1_rtx));
> +  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
> +
> +  DONE;
> +})
> +
> +(define_expand "bcddiv10_v16qi"
> +  [(set (match_operand:V16QI 0 "register_operand")
> +       (unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
> +                     UNSPEC_BCDSHIFT))
> +   (clobber (reg:CCFP CR6_REGNO))]
> +  "TARGET_P9_VECTOR"
> +{
> +  rtx one = gen_reg_rtx (V16QImode);
> +
> +  emit_insn (gen_altivec_vspltisb (one, constm1_rtx));
> +  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
> +
> +  DONE;
> +})
> +
> +
>  ;; Peephole2 pattern to combine a bcdadd/bcdsub that calculates the value and
>  ;; the bcdadd/bcdsub that tests the value.  The combiner won't work since
>  ;; CR6 is a hard coded register.  Unfortunately, all of the Altivec predicate
> diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md
> index 8f822732bac..9a952300cd6 100644
> --- a/gcc/config/rs6000/dfp.md
> +++ b/gcc/config/rs6000/dfp.md
> @@ -273,6 +273,28 @@
>    "denbcd<q> %1,%0,%2"
>    [(set_attr "type" "dfp")])
>
> +(define_insn "dfp_denbcd_v16qi_inst"
> +  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
> +       (unspec:TD [(match_operand:QI 1 "const_0_to_1_operand" "i")
> +                   (match_operand:V16QI 2 "register_operand" "d")]
> +                  UNSPEC_DENBCD))]
> +  "TARGET_DFP"
> +  "denbcdq %1,%0,%2"
> +  [(set_attr "type" "dfp")])
> +
> +(define_expand "dfp_denbcd_v16qi"
> +  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
> +       (unspec:TD [(match_operand:V16QI 1 "register_operand" "v")]
> +                  UNSPEC_DENBCD))]
> +  "TARGET_DFP"
> + {
> +   // Move vs128 upper 64-bits and lower 64-bits to fp register pair
> +   convert_move (operands[0], operands[1], true);
> +   emit_insn (gen_dfp_denbcd_v16qi_inst (operands[0], GEN_INT(1),
> +                                        operands[0]));
> +   DONE;
> + })
> +
>  (define_insn "dfp_dxex_<mode>"
>    [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
>         (unspec:DI [(match_operand:DDTD 1 "gpc_reg_operand" "d")]
> diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
> index 5b05da87f4b..a58102c3785 100644
> --- a/gcc/config/rs6000/rs6000-builtin.def
> +++ b/gcc/config/rs6000/rs6000-builtin.def
> @@ -696,6 +696,14 @@
>  /* Miscellaneous builtins for instructions added in ISA 2.07.  These
>     instructions do require the ISA 2.07 vector support, but they aren't vector
>     instructions.  */
> +#define BU_P8V_MISC_1(ENUM, NAME, ATTR, ICODE)                         \
> +  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,             /* ENUM */      \
> +                   "__builtin_" NAME,                  /* NAME */      \
> +                   RS6000_BTM_P8_VECTOR,               /* MASK */      \
> +                   (RS6000_BTC_ ## ATTR                /* ATTR */      \
> +                    | RS6000_BTC_UNARY),                               \
> +                   CODE_FOR_ ## ICODE)                 /* ICODE */
> +
>  #define BU_P8V_MISC_3(ENUM, NAME, ATTR, ICODE)                         \
>    RS6000_BUILTIN_3 (MISC_BUILTIN_ ## ENUM,             /* ENUM */      \
>                     "__builtin_" NAME,                  /* NAME */      \
> @@ -2668,16 +2676,55 @@ BU_P7_MISC_1 (CBCDTD,           "cbcdtd",       CONST,  cbcdtd)
>  BU_P7_MISC_2 (ADDG6S,          "addg6s",       CONST,  addg6s)
>
>  /* 3 argument BCD functions added in ISA 2.07.  */
> -BU_P8V_MISC_3 (BCDADD,         "bcdadd",       CONST,  bcdadd)
> -BU_P8V_MISC_3 (BCDADD_LT,      "bcdadd_lt",    CONST,  bcdadd_lt)
> -BU_P8V_MISC_3 (BCDADD_EQ,      "bcdadd_eq",    CONST,  bcdadd_eq)
> -BU_P8V_MISC_3 (BCDADD_GT,      "bcdadd_gt",    CONST,  bcdadd_gt)
> -BU_P8V_MISC_3 (BCDADD_OV,      "bcdadd_ov",    CONST,  bcdadd_unordered)
> -BU_P8V_MISC_3 (BCDSUB,         "bcdsub",       CONST,  bcdsub)
> -BU_P8V_MISC_3 (BCDSUB_LT,      "bcdsub_lt",    CONST,  bcdsub_lt)
> -BU_P8V_MISC_3 (BCDSUB_EQ,      "bcdsub_eq",    CONST,  bcdsub_eq)
> -BU_P8V_MISC_3 (BCDSUB_GT,      "bcdsub_gt",    CONST,  bcdsub_gt)
> -BU_P8V_MISC_3 (BCDSUB_OV,      "bcdsub_ov",    CONST,  bcdsub_unordered)
> +BU_P8V_MISC_3 (BCDADD_V1TI,    "bcdadd_v1ti",  CONST,  bcdadd_v1ti)
> +BU_P8V_MISC_3 (BCDADD_V16QI,   "bcdadd_v16qi", CONST,  bcdadd_v16qi)
> +BU_P8V_MISC_3 (BCDADD_LT_V1TI, "bcdadd_lt_v1ti",  CONST, bcdadd_lt_v1ti)
> +BU_P8V_MISC_3 (BCDADD_LT_V16QI,        "bcdadd_lt_v16qi", CONST, bcdadd_lt_v16qi)
> +BU_P8V_MISC_3 (BCDADD_EQ_V1TI, "bcdadd_eq_v1ti",  CONST, bcdadd_eq_v1ti)
> +BU_P8V_MISC_3 (BCDADD_EQ_V16QI,        "bcdadd_eq_v16qi", CONST, bcdadd_eq_v16qi)
> +BU_P8V_MISC_3 (BCDADD_GT_V1TI, "bcdadd_gt_v1ti",  CONST, bcdadd_gt_v1ti)
> +BU_P8V_MISC_3 (BCDADD_GT_V16QI,        "bcdadd_gt_v16qi", CONST, bcdadd_gt_v16qi)
> +BU_P8V_MISC_3 (BCDADD_OV_V1TI, "bcdadd_ov_v1ti",  CONST, bcdadd_unordered_v1ti)
> +BU_P8V_MISC_3 (BCDADD_OV_V16QI,        "bcdadd_ov_v16qi", CONST, bcdadd_unordered_v16qi)
> +
> +BU_P8V_MISC_3 (BCDSUB_V1TI,    "bcdsub_v1ti",  CONST,  bcdsub_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_V16QI,   "bcdsub_v16qi", CONST,  bcdsub_v16qi)
> +BU_P8V_MISC_3 (BCDSUB_LT_V1TI, "bcdsub_lt_v1ti",  CONST, bcdsub_lt_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_LT_V16QI,        "bcdsub_lt_v16qi", CONST, bcdsub_lt_v16qi)
> +BU_P8V_MISC_3 (BCDSUB_LE_V1TI, "bcdsub_le_v1ti",  CONST, bcdsub_le_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_LE_V16QI,        "bcdsub_le_v16qi", CONST, bcdsub_le_v16qi)
> +BU_P8V_MISC_3 (BCDSUB_EQ_V1TI, "bcdsub_eq_v1ti",  CONST, bcdsub_eq_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_EQ_V16QI,        "bcdsub_eq_v16qi", CONST, bcdsub_eq_v16qi)
> +BU_P8V_MISC_3 (BCDSUB_GT_V1TI, "bcdsub_gt_v1ti",  CONST, bcdsub_gt_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_GT_V16QI,        "bcdsub_gt_v16qi", CONST, bcdsub_gt_v16qi)
> +BU_P8V_MISC_3 (BCDSUB_GE_V1TI, "bcdsub_ge_v1ti",  CONST, bcdsub_ge_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_GE_V16QI,        "bcdsub_ge_v16qi", CONST, bcdsub_ge_v16qi)
> +BU_P8V_MISC_3 (BCDSUB_OV_V1TI, "bcdsub_ov_v1ti",  CONST, bcdsub_unordered_v1ti)
> +BU_P8V_MISC_3 (BCDSUB_OV_V16QI,        "bcdsub_ov_v16qi", CONST, bcdsub_unordered_v16qi)
> +
> +BU_P8V_MISC_1 (BCDINVALID_V1TI,        "bcdinvalid_v1ti",  CONST, bcdinvalid_v1ti)
> +BU_P8V_MISC_1 (BCDINVALID_V16QI, "bcdinvalid_v16qi", CONST, bcdinvalid_v16qi)
> +
> +BU_P9V_AV_1 (BCDMUL10_V16QI, "bcdmul10_v16qi", CONST, bcdmul10_v16qi)
> +BU_P9V_AV_1 (BCDDIV10_V16QI, "bcddiv10_v16qi", CONST, bcddiv10_v16qi)
> +BU_P8V_MISC_1 (DENBCD_V16QI,   "denb2dfp_v16qi", CONST, dfp_denbcd_v16qi)
> +
> +BU_P8V_OVERLOAD_3 (BCDADD,     "bcdadd")
> +BU_P8V_OVERLOAD_3 (BCDADD_LT,  "bcdadd_lt")
> +BU_P8V_OVERLOAD_3 (BCDADD_EQ,  "bcdadd_eq")
> +BU_P8V_OVERLOAD_3 (BCDADD_GT,  "bcdadd_gt")
> +BU_P8V_OVERLOAD_3 (BCDADD_OV,  "bcdadd_ov")
> +BU_P8V_OVERLOAD_3 (BCDSUB,     "bcdsub")
> +BU_P8V_OVERLOAD_3 (BCDSUB_LT,  "bcdsub_lt")
> +BU_P8V_OVERLOAD_3 (BCDSUB_LE,  "bcdsub_le")
> +BU_P8V_OVERLOAD_3 (BCDSUB_EQ,  "bcdsub_eq")
> +BU_P8V_OVERLOAD_3 (BCDSUB_GT,  "bcdsub_gt")
> +BU_P8V_OVERLOAD_3 (BCDSUB_GE,  "bcdsub_ge")
> +BU_P8V_OVERLOAD_3 (BCDSUB_OV,  "bcdsub_ov")
> +BU_P8V_OVERLOAD_1 (BCDINVALID, "bcdinvalid")
> +BU_P9V_OVERLOAD_1 (BCDMUL10,   "bcdmul10")
> +BU_P9V_OVERLOAD_1 (BCDDIV10,   "bcddiv10")
> +BU_P8V_OVERLOAD_1 (DENBCD,     "denb2dfp")
>
>  /* 2 argument pack/unpack 128-bit floating point types.  */
>  BU_DFP_MISC_2 (PACK_TD,                "pack_dec128",          CONST,  packtd)
> diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
> index b044778a7ae..92378e958a9 100644
> --- a/gcc/config/rs6000/rs6000-call.c
> +++ b/gcc/config/rs6000/rs6000-call.c
> @@ -985,6 +985,82 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = {
>      RS6000_BTI_unsigned_V4SI, RS6000_BTI_V4SF, RS6000_BTI_INTSI, 0 },
>    { ALTIVEC_BUILTIN_VEC_CTU, VSX_BUILTIN_XVCVDPUXDS_SCALE,
>      RS6000_BTI_unsigned_V2DI, RS6000_BTI_V2DF, RS6000_BTI_INTSI, 0 },
> +
> +  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V1TI,
> +    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, 0, 0 },
> +  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI, 0, 0 },
> +
> +  { P9V_BUILTIN_VEC_BCDMUL10, P9V_BUILTIN_BCDMUL10_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
> +  { P9V_BUILTIN_VEC_BCDDIV10, P9V_BUILTIN_BCDDIV10_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
> +
> +  { P8V_BUILTIN_VEC_DENBCD, MISC_BUILTIN_DENBCD_V16QI,
> +    RS6000_BTI_dfloat128, RS6000_BTI_unsigned_V16QI, 0, 0 },
> +
> +  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V1TI,
> +    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V1TI,
> +    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
> +  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V16QI,
> +    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
> +    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
> +
> +
>    { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVSP,
>      RS6000_BTI_V4SF, RS6000_BTI_V4SF, RS6000_BTI_V4SF, 0 },
>    { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVDP,
> @@ -10570,14 +10646,22 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
>      }
>    else if (icode == CODE_FOR_vsx_set_v2df
>             || icode == CODE_FOR_vsx_set_v2di
> -          || icode == CODE_FOR_bcdadd
> -          || icode == CODE_FOR_bcdadd_lt
> -          || icode == CODE_FOR_bcdadd_eq
> -          || icode == CODE_FOR_bcdadd_gt
> -          || icode == CODE_FOR_bcdsub
> -          || icode == CODE_FOR_bcdsub_lt
> -          || icode == CODE_FOR_bcdsub_eq
> -          || icode == CODE_FOR_bcdsub_gt)
> +          || icode == CODE_FOR_bcdadd_v16qi
> +          || icode == CODE_FOR_bcdadd_v1ti
> +          || icode == CODE_FOR_bcdadd_lt_v16qi
> +          || icode == CODE_FOR_bcdadd_lt_v1ti
> +          || icode == CODE_FOR_bcdadd_eq_v16qi
> +          || icode == CODE_FOR_bcdadd_eq_v1ti
> +          || icode == CODE_FOR_bcdadd_gt_v16qi0001-Add-bcd-builtings-listed-in-appendix-B-of-the-ABI.patch
> +          || icode == CODE_FOR_bcdadd_gt_v1ti
> +          || icode == CODE_FOR_bcdsub_v16qi
> +          || icode == CODE_FOR_bcdsub_v1ti
> +          || icode == CODE_FOR_bcdsub_lt_v16qi
> +          || icode == CODE_FOR_bcdsub_lt_v1ti
> +          || icode == CODE_FOR_bcdsub_eq_v16qi
> +          || icode == CODE_FOR_bcdsub_eq_v1ti
> +          || icode == CODE_FOR_bcdsub_gt_v16qi
> +          || icode == CODE_FOR_bcdsub_gt_v1ti)
>      {
>        /* Only allow 1-bit unsigned literals.  */
>        STRIP_NOPS (arg2);
> @@ -10601,7 +10685,8 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
>         }
>      }
>    else if (icode == CODE_FOR_dfp_denbcd_dd
> -          || icode == CODE_FOR_dfp_denbcd_td)
> +          || icode == CODE_FOR_dfp_denbcd_td
> +          || icode == CODE_FOR_dfp_denbcd_v16qi)
>      {
>        /* Only allow 1-bit unsigned literals.  */
>        STRIP_NOPS (arg0);
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 5be1cbecf60..0b701ee506f 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -20161,15 +20161,28 @@ __int128 vec_vsubuqm (__int128, __int128);
>  __uint128 vec_vsubuqm (__uint128, __uint128);
>
>  vector __int128 __builtin_bcdadd (vector __int128, vector __int128, const int);
> +vector unsigned char __builtin_bcdadd (vector unsigned char, vector unsigned char,
> +                                       const int);
>  int __builtin_bcdadd_lt (vector __int128, vector __int128, const int);
> +int __builtin_bcdadd_lt (vector unsigned char, vector unsigned char, const int);
>  int __builtin_bcdadd_eq (vector __int128, vector __int128, const int);
> +int __builtin_bcdadd_eq (vector unsigned char, vector unsigned char, const int);
>  int __builtin_bcdadd_gt (vector __int128, vector __int128, const int);
> +int __builtin_bcdadd_gt (vector unsigned char, vector unsigned char, const int);
>  int __builtin_bcdadd_ov (vector __int128, vector __int128, const int);
> +int __builtin_bcdadd_ov (vector unsigned char, vector unsigned char, const int);
> +
>  vector __int128 __builtin_bcdsub (vector __int128, vector __int128, const int);
> +vector unsigned char __builtin_bcdsub (vector unsigned char, vector unsigned char,
> +                                       const int);
>  int __builtin_bcdsub_lt (vector __int128, vector __int128, const int);
> +int __builtin_bcdsub_lt (vector unsigned char, vector unsigned char, const int);
>  int __builtin_bcdsub_eq (vector __int128, vector __int128, const int);
> +int __builtin_bcdsub_eq (vector unsigned char, vector unsigned char, const int);
>  int __builtin_bcdsub_gt (vector __int128, vector __int128, const int);
> +int __builtin_bcdsub_gt (vector unsigned char, vector unsigned char, const int);
>  int __builtin_bcdsub_ov (vector __int128, vector __int128, const int);
> +int __builtin_bcdsub_ov (vector unsigned char, vector unsigned char, const int);
>  @end smallexample
>
>  @node PowerPC AltiVec Built-in Functions Available on ISA 3.0
> diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-2.c b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
> index 2f51dee257f..95c3699a144 100644
> --- a/gcc/testsuite/gcc.target/powerpc/bcd-2.c
> +++ b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
> @@ -14,6 +14,8 @@
>  /* { dg-final { scan-assembler-not   "stxvw4x"               } } */
>  /* { dg-final { scan-assembler-not   "stxvd2x"               } } */
>
> +#include <altivec.h>
> +
>  typedef __int128_t __attribute__((__vector_size__(16)))        vector_128_t;
>  typedef __int128_t                                     scalar_128_t;
>  typedef        unsigned long long                              scalar_64_t;
> diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-3.c b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
> index 1b20841ae1c..7948a0c95e2 100644
> --- a/gcc/testsuite/gcc.target/powerpc/bcd-3.c
> +++ b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
> @@ -18,6 +18,8 @@ typedef __int128_t __attribute__((__vector_size__(16)))       vector_128_t;
>  typedef __int128_t                                     scalar_128_t;
>  typedef        unsigned long long                              scalar_64_t;
>
> +#include <altivec.h>
> +
>  /* Test whether the peephole works to allow folding a bcdadd, with a
>     bcdadd_<test> into a single instruction.  */
>
> diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-4.c b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
> new file mode 100644
> index 00000000000..708ad7b6b3f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
> @@ -0,0 +1,519 @@
> +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
> +/* { dg-require-effective-target power10_hw } */
> +/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
> +/* { dg-final { scan-assembler-times "\mbcdadd\M" 7 } } */
> +/* { dg-final { scan-assembler-times "\mbcdsub\M" 18 } } */
> +/* { dg-final { scan-assembler-times "\mbcds\M" 2 } } */
> +/* { dg-final { scan-assembler-times "\mdenbcdq\M" 1 } } */
> +
> +#include <altivec.h>
> +
> +#define DEBUG 0
> +
> +#if DEBUG
> +#include <stdio.h>
> +#endif
> +
> +
> +#define BCD_POS0  12    //  0xC
> +#define BCD_POS1  15    //  0xF
> +#define BCD_NEG   13    //  0xD
> +
> +void abort (void);
> +
> +  union conv_t
> +    {
> +      _Decimal128 d128;
> +      vector  unsigned char ch;
> +      vector  long long unsigned int vllui;
> +    } conv;
> +
> +_Decimal128 convert_vec_char (vector unsigned char a)
> +{
> +  union conv_t conv;
> +  _Decimal128 result;
> +
> +  conv.ch = a;
> +  result = conv.d128;
> +  return result;
> +}
> +
> +vector unsigned char maxbcd(unsigned int sign)
> +{
> +  vector unsigned char result;
> +  int i;
> +
> +  for (i = 15; i > 0; i--)
> +    result[i] = 0x99;
> +
> +  result[0] = sign << 4 | 0x9;
> +}
> +
> +vector unsigned char num2bcd(long int a, int encoding)
> +{
> +  int i;
> +  unsigned int hi, low, sign;
> +
> +  vector unsigned char result;
> +
> +  if (a > 0) {
> +    if (encoding == 0)
> +      sign = BCD_POS0;
> +    else
> +      sign = BCD_POS1;
> +
> +  } else {
> +    sign = BCD_NEG;
> +    a = -a;
> +  }
> +
> +  hi = a % 10;   // 1st digit
> +  a = a / 10;
> +  result[0] = hi << 4| sign;
> +
> +  for (i = 1; i < 16; i++)
> +    {
> +      low = a % 10;
> +      a = a / 10;
> +      hi = a % 10;
> +      a = a / 10;
> +      result[i] = hi << 4 | low;
> +    }
> +
> +
> +  return result;
> +}
> +
> +int main ()
> +{
> +  int i;
> +  long int value_a, value_b, value_result;
> +  vector unsigned char a, b, result, exp_result;
> +  _Decimal128 result_d128, exp_result_d128;
> +
> +  /* Make a and b positive BCD numbers */
> +  value_a = 1020304;
> +  a = num2bcd(value_a, 0);
> +
> +  value_b = 101010;
> +  b = num2bcd(value_b, 0);
> +
> +  value_result = value_a + value_b;
> +  exp_result = num2bcd(value_result, 0);
> +
> +  result = __builtin_bcdadd (a, b, 0);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i] != result[i]) {
> +
> +#if DEBUG
> +      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
> +            "expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* result should be positive */
> +  if ((result[0] & 0xF) != BCD_POS0)
> +#if DEBUG
> +      printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not match "
> +            "expected_result = %d\n",
> +            result[0] & 0xF, BCD_POS0);
> +#else
> +      abort();
> +#endif
> +
> +  /* Make a and b positive BCD numbers using alternate positive encoding.  */
> +  value_a = 1030507;
> +  a = num2bcd(value_a, 1);
> +
> +  value_b = 204060;
> +  b = num2bcd(value_b, 1);
> +
> +  value_result = value_a + value_b;
> +  exp_result = num2bcd(value_result, 1);
> +
> +  result = __builtin_bcdadd (a, b, 1);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i] != result[i]) {
> +#if DEBUG
> +      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
> +            "expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* Result should be positive, alternate encoding.  */
> +  if ((result[0] & 0xF) != BCD_POS1)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not "
> +          "match expected_result = %d\n",
> +            result[0] & 0xF, BCD_POS1);
> +#else
> +    abort();
> +#endif
> +
> +  /* Make a and b negative BCD numbers */
> +  value_a = -1030507;
> +  a = num2bcd(value_a, 0);
> +
> +  value_b = -1010101;
> +  b = num2bcd(value_b, 0);
> +
> +  value_result = value_a + value_b;
> +  exp_result = num2bcd(value_result, 0);
> +
> +  result = __builtin_bcdadd (a, b, 0);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i]  != result[i]) {
> +#if DEBUG
> +      printf("ERROR: __builtin_bcdadd, neg result[%d] = %d does not match "
> +            "expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* result should be negative */
> +  if ((result[0] & 0xF) != BCD_NEG)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdadd sign, neg of result is %d.  Does not "
> +          "match expected_result = %d\n",
> +            result[0] & 0xF, BCD_NEG);
> +#else
> +    abort();
> +#endif
> +
> +
> +  /* Make a negative, b positive BCD numbers */
> +  value_a = -1030507;
> +  a = num2bcd(value_a, 0);
> +
> +  value_b = 1010101;
> +  b = num2bcd(value_b, 0);
> +
> +  value_result = value_a - value_b;
> +  exp_result = num2bcd(value_result, 0);
> +
> +  result = __builtin_bcdsub (a, b, 0);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i] != result[i]) {
> +#if DEBUG
> +      printf("ERROR: __builtin_bcdsub, neg result[%d] = %d does not match "
> +            "expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* result should be positive, alt encoding */
> +  if ((result[0] & 0xF) != BCD_NEG)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdadd sign, of result is %d.  Does not match "
> +          "expected_result = %d\n",
> +            result[0] & 0xF, BCD_NEG);
> +#else
> +    abort();
> +#endif
> +
> +  /* Make a and b positive BCD numbers */
> +  value_a = 1030507;
> +  a = num2bcd(value_a, 1);
> +
> +  value_b = 1010101;
> +  b = num2bcd(value_b, 1);
> +
> +  value_result = value_a - value_b;
> +  exp_result = num2bcd(value_result, 1);
> +
> +  result = __builtin_bcdsub (a, b, 1);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i] != result[i]) {
> +#if DEBUG
> +      printf("ERROR:carll __builtin_bcdsub, pos result[%d] = %d does not "
> +            "match expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* result should be positive */
> +  if ((result[0] & 0xF) != BCD_POS1)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdsub sign, result is %d.  Does not match "
> +          "expected_result = %d\n",
> +            result[0] & 0xF, BCD_POS1);
> +#else
> +      abort();
> +#endif
> +
> +  /* Test overflow add and subtract.  */
> +  a = maxbcd(BCD_POS0);
> +  b = maxbcd(BCD_POS0);
> +
> +  if(__builtin_bcdadd_ofl (a, b, 0) == 0)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdadd did not overflow as expected\n");
> +#else
> +    abort();
> +#endif
> +
> +  value_a = 99999999;
> +  a = num2bcd(value_a, 0);
> +
> +  value_b = 999999999;
> +  b = num2bcd(value_b, 0);
> +
> +  if(__builtin_bcdadd_ofl (a, b, 0))
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdadd unexpectedly overflowed\n");
> +#else
> +    abort();
> +#endif
> +
> +  a = maxbcd(BCD_NEG);
> +  b = maxbcd(BCD_NEG);
> +
> +  if (__builtin_bcdsub_ofl (a, b, 0) == 0)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdsub did not overflow as expected\n");
> +#else
> +    abort();
> +#endif
> +
> +  value_a = -99999999;
> +  a = num2bcd(value_a, 0);
> +
> +  value_b = -999999999;
> +  b = num2bcd(value_b, 0);
> +
> +  if (__builtin_bcdsub_ofl (a, b, 0))
> +#if DEBUG
> +    printf("ERROR: __builtin_bcdsub unexpectedly overflowed\n");
> +#else
> +    abort();
> +#endif
> +
> +  /* Test arguments for valid/invalid */
> +  if (__builtin_bcdinvalid (a))
> +#if DEBUG
> +    printf("ERROR: __builtin_invalid input is unexpectedly invalid.\n");
> +#else
> +    abort();
> +#endif
> +
> +  a[3] = 0xBB;     /* an invalid BCD digit */
> +  if (!__builtin_bcdinvalid (a))
> +#if DEBUG
> +    printf("ERROR: __builtin_invalid input is unexpectedly valid.\n");
> +#else
> +    abort();
> +#endif
> +
> +  value_a = 1020304;
> +  a = num2bcd(value_a, 0);
> +
> +  value_b = 101010;
> +  b = num2bcd(value_b, 0);
> +
> +  /* Test equality */
> +  if (__builtin_bcdcmpeq (a, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 1.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (!__builtin_bcdcmpeq (a, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 0.\n");
> +#else
> +    abort();
> +#endif
> +
> +
> +  /* Test a greater then b, inputs already setup this way.  */
> +  if (!__builtin_bcdcmpgt (a, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 0.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (__builtin_bcdcmpgt (b, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 1.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (__builtin_bcdcmpgt (a, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpgt input equal, result is unexpectedly "
> +          "1.\n");
> +#else
> +    abort();
> +#endif
> +
> +
> +  if (!__builtin_bcdcmpge (a, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 0.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (__builtin_bcdcmpge (b, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 1.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (!__builtin_bcdcmpge (b, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmpge inputs equal result is unexpectedly "
> +          "0.\n");
> +#else
> +    abort();
> +#endif
> +
> +  /* Test a less then b.  */
> +  value_a = 101010;
> +  a = num2bcd(value_a, 0);
> +  value_b = 1020304;
> +  b = num2bcd(value_b, 0);
> +
> +  if (!__builtin_bcdcmplt (a, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 0.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (__builtin_bcdcmplt (b, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 1.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (__builtin_bcdcmplt (b, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmplt inputs equal result is unexpectedly "
> +          "1.\n");
> +#else
> +    abort();
> +#endif
> +
> +
> +  if (!__builtin_bcdcmple (a, b))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmple result is unexpectedly 0.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (__builtin_bcdcmple (b, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmple result is unexpectedly 1.\n");
> +#else
> +    abort();
> +#endif
> +
> +  if (!__builtin_bcdcmple (a, a))
> +#if DEBUG
> +    printf("ERROR: __builtin__bcdcmple inputs equal result is unexpectedly "
> +          "0.\n");
> +#else
> +    abort();
> +#endif
> +
> +  /* Test multipy 10 */
> +  value_a = 1020304;
> +  a = num2bcd(value_a, 0);
> +
> +  value_result = value_a * 10;
> +  exp_result = num2bcd(value_result, 0);
> +
> +  result = __builtin_bcdmul10 (a);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i] != result[i]) {
> +#if DEBUG
> +      printf("ERROR:carll __builtin_bcdmul10, pos result[%d] = %d does not "
> +            "match expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* result should be positive */
> +  if ((result[0] & 0xF) != BCD_POS0)
> +#if 0
> +    printf("ERROR: __builtin_bcdmul10 sign, result is %d.  Does not match "
> +          "expected_result = %d\n",
> +          result[0] & 0xF, BCD_POS1);
> +#else
> +    abort();
> +#endif
> +
> +  /* Test divide 10 */
> +  value_a = 1020304;
> +  a = num2bcd(value_a, 0);
> +
> +  value_result = value_a / 10;
> +  exp_result = num2bcd(value_result, 0);
> +
> +  result = __builtin_bcddiv10 (a);
> +
> +  for (i = 0; i < 16; i++)
> +    if (exp_result[i] != result[i]) {
> +#if DEBUG
> +      printf("ERROR:carll __builtin_bcddiv10, pos result[%d] = %d does not "
> +            "match expected_result[%d] = %d\n",
> +            i, result[i], i, exp_result[i]);
> +#else
> +      abort();
> +#endif
> +    }
> +
> +  /* result should be positive */
> +  if ((result[0] & 0xF) != BCD_POS0)
> +#if DEBUG
> +    printf("ERROR: __builtin_bcddiv10 sign, result is %d.  Does not match "
> +          "expected_result = %d\n",
> +            result[0] & 0xF, BCD_POS1);
> +#else
> +    abort();
> +#endif
> +
> +   value_a = 1020304;
> +   exp_result_d128 = 1020304;
> +   a = num2bcd(value_a, 0);
> +
> +   conv.ch = a;
> +   conv.d128 = __builtin_bcd2dfp (a);
> +   result_d128 = conv.d128;
> +
> +   if (result_d128 != exp_result_d128)
> +#if DEBUG
> +     printf("ERROR: __builtin_bcd2dfp, result does not match expected_result."
> +           "\n");
> +#else
> +     abort();
> +#endif
> +}
> +
> --
> 2.17.1
>
>
Carl Love Oct. 28, 2020, 11:21 p.m. UTC | #2
David:

On Sat, 2020-10-24 at 11:29 -0400, David Edelsohn wrote:
> Hi, Carl
> 
> Not commenting on the implementation.
> 
> Please stop using powerpc*-*-* in the test cases.  The test cases
> already are in the gcc.target/powerpc directory.
> 
> Do the test cases really need lp64, or should this require something
> like int128?
> 
> Thanks, David

OK, I looked at the test case and it really needs 128-bit integer
support.  I changed the test case header to:

+++ b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
@@ -0,0 +1,519 @@
+/* { dg-do compile { target int128  } } */
+/* { dg-require-effective-target power10_hw } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2" } */

I reran the regression test.  There were no regressions.  Does the
above look more reasonable?


                        Carl 
--------------------------------------------------------------------

Gcc maintainers:

The following patch adds support for the built-ins listed in Table B.1,
"Binary-Coded Decimal Built-In Functions" of the "64-Bit ELF V2 ABI
Specification", July 30, 2019.

The built-ins adds support the V16QI type for addition, subtraction and
comparison as sepcified in the Table B.1.  Note, the V1TI type was
previously supported for add, subtract and comparison.  The builtins
for test for valid value, multiply by 10, divide by 10 and conversion
to DFP value are also added for the V16QI type as specified in Table
B.1.

The patch includes adding the #include <altivec.h> to the existing bcd-
2.c and bcd-3.c tests so they will pass the regression tests as the
builtins names are now listed in altivec.h rather then just using
internal names.

The patch was compiled and tested on:

  powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions. 

Please let me know if this patch is acceptable for mainline.  Thanks.

                Carl Love

-----------------------------------------------------------------

2020-10-29  Carl Love  <cel@us.ibm.com>

gcc/
        PR target/93449
	* config/rs6000/altivec.h (__builtin_bcdadd, __builtin_bcdadd_lt,
	__builtin_bcdadd_eq, __builtin_bcdadd_gt, __builtin_bcdadd_ofl,
	__builtin_bcdadd_ov, __builtin_bcdsub, __builtin_bcdsub_lt,
	__builtin_bcdsub_eq, __builtin_bcdsub_gt, __builtin_bcdsub_ofl,
	__builtin_bcdsub_ov, __builtin_bcdinvalid, __builtin_bcdmul10,
	__builtin_bcddiv10, __builtin_bcd2dfp, __builtin_bcdcmpeq,
 	__builtin_bcdcmpgt, __builtin_bcdcmplt, __builtin_bcdcmpge,
	__builtin_bcdcmple): Add defines.
	* config/rs6000/altivec.md: Add UNSPEC_BCDSHIFT.
	(BCD_TEST): Add le, ge to code iterator.
	Add VBCD mode iterator.
	(bcd<bcd_add_sub>_test, *bcd<bcd_add_sub>_test2,
	bcd<bcd_add_sub>_<code>, bcd<bcd_add_sub>_<code>): Add mode to name.
	Change iterator from V1TI to VBCD.
	(*bcdinvalid_<mode>, bcdshift_v16qi): New define_insn.
	(bcdinvalid_<mode>, bcdmul10_v16qi, bcddiv10_v16qi): New define.
	config/rs6000/dfp.md (dfp_denbcd_v16qi_inst): New define_insn.
	(dfp_denbcd_v16qi): New define_expand.
	* confit/rs6000/rs6000-builtin.def (BU_P8V_MISC_1): New define.
	(BCDADD): Replaced with BCDADD_V1TI and BCDADD_V16QI.
	(BCDADD_LT): Replaced with BCDADD_LT_V1TI and BCDADD_LT_V16QI.
	(BCDADD_EQ): Replaced with BCDADD_EQ_V1TI and BCDADD_EQ_V16QI.
	(BCDADD_GT): Replaced with BCDADD_GT_V1TI and BCDADD_GT_V16QI.
	(BCDADD_OV): Replaced with BCDADD_OV_V1TI and BCDADD_OV_V16QI.
	(BCDSUB_V1TI, BCDSUB_V16QI, BCDSUB_LT_V1TI, BCDSUB_LT_V16QI,
	BCDSUB_LE_V1TI, BCDSUB_LE_V16QI, BCDSUB_EQ_V1TI, BCDSUB_EQ_V16QI,
	BCDSUB_GT_V1TI, BCDSUB_GT_V16QI, BCDSUB_GE_V1TI, BCDSUB_GE_V16QI,
	BCDSUB_OV_V1TI, BCDSUB_OV_V16QI, BCDINVALID_V1TI, BCDINVALID_V16QI,
	BCDMUL10_V16QI, BCDDIV10_V16QI, DENBCD_V16QI): New builtin definitions.
	(BCDADD, BCDADD_LT, BCDADD_EQ, BCDADD_GT, BCDADD_OV, BCDSUB, BCDSUB_LT,
	BCDSUB_LE, BCDSUB_EQ, BCDSUB_GT, BCDSUB_GE, BCDSUB_OV, BCDINVALID,
	BCDMUL10, BCDDIV10, DENBCD): New overload definitions.
	config/rs6000/rs6000-call.c (P8V_BUILTIN_VEC_BCDADD, P8V_BUILTIN_VEC_BCDADD_LT,
	P8V_BUILTIN_VEC_BCDADD_EQ, P8V_BUILTIN_VEC_BCDADD_GT, P8V_BUILTIN_VEC_BCDADD_OV,
	P8V_BUILTIN_VEC_BCDINVALID, P9V_BUILTIN_VEC_BCDMUL10, P8V_BUILTIN_VEC_DENBCD.
	P8V_BUILTIN_VEC_BCDSUB, P8V_BUILTIN_VEC_BCDSUB_LT, P8V_BUILTIN_VEC_BCDSUB_LE,
	P8V_BUILTIN_VEC_BCDSUB_EQ, P8V_BUILTIN_VEC_BCDSUB_GT, P8V_BUILTIN_VEC_BCDSUB_GE,
	P8V_BUILTIN_VEC_BCDSUB_OV): New overloaded specifications.
	(CODE_FOR_bcdadd): Replaced with CODE_FOR_bcdadd_v16qi and CODE_FOR_bcdadd_v1ti.
	(CODE_FOR_bcdadd_lt): Replaced with CODE_FOR_bcdadd_lt_v16qi and CODE_FOR_bcdadd_lt_v1ti.
	(CODE_FOR_bcdadd_eq): Replaced with CODE_FOR_bcdadd_eq_v16qi and CODE_FOR_bcdadd_eq_v1ti.
	(CODE_FOR_bcdadd_gt): Replaced with CODE_FOR_bcdadd_gt_v16qi and CODE_FOR_bcdadd_gt_v1ti.
	(CODE_FOR_bcdsub): Replaced with CODE_FOR_bcdsub_v16qi and CODE_FOR_bcdsub_v1ti.
	(CODE_FOR_bcdsub_lt): Replaced with CODE_FOR_bcdsub_lt_v16qi and CODE_FOR_bcdsub_lt_v1ti.
	(CODE_FOR_bcdsub_eq): Replaced with CODE_FOR_bcdsub_eq_v16qi and CODE_FOR_bcdsub_eq_v1ti.
	(CODE_FOR_bcdsub_gt): Replaced with CODE_FOR_bcdsub_gt_v16qi and CODE_FOR_bcdsub_gt_v1ti.
	(rs6000_expand_ternop_builtin):  Add CODE_FOR_dfp_denbcd_v16qi to else if.
	* doc/extend.texi: Add documentation for new builtins.

gcc/testsuite/
	* gcc.target/powerpc/bcd-3.c: Add include altivec.h.
	* gcc.target/powerpc/bcd-4.c: New test.
---
 gcc/config/rs6000/altivec.h              |  25 ++
 gcc/config/rs6000/altivec.md             | 104 ++++-
 gcc/config/rs6000/dfp.md                 |  22 +
 gcc/config/rs6000/rs6000-builtin.def     |  67 ++-
 gcc/config/rs6000/rs6000-call.c          | 103 ++++-
 gcc/doc/extend.texi                      |  13 +
 gcc/testsuite/gcc.target/powerpc/bcd-2.c |   2 +
 gcc/testsuite/gcc.target/powerpc/bcd-3.c |   2 +
 gcc/testsuite/gcc.target/powerpc/bcd-4.c | 519 +++++++++++++++++++++++
 9 files changed, 821 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/bcd-4.c

diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
index df10a8c498d..e1884f51bd8 100644
--- a/gcc/config/rs6000/altivec.h
+++ b/gcc/config/rs6000/altivec.h
@@ -497,8 +497,33 @@
 
 #define vec_xlx __builtin_vec_vextulx
 #define vec_xrx __builtin_vec_vexturx
+
 #endif
 
+/* BCD builtins, map ABI builtin name to existing builtin name.  */
+#define __builtin_bcdadd     __builtin_vec_bcdadd
+#define __builtin_bcdadd_lt  __builtin_vec_bcdadd_lt
+#define __builtin_bcdadd_eq  __builtin_vec_bcdadd_eq
+#define __builtin_bcdadd_gt  __builtin_vec_bcdadd_gt
+#define __builtin_bcdadd_ofl __builtin_vec_bcdadd_ov
+#define __builtin_bcdadd_ov  __builtin_vec_bcdadd_ov
+#define __builtin_bcdsub     __builtin_vec_bcdsub
+#define __builtin_bcdsub_lt  __builtin_vec_bcdsub_lt
+#define __builtin_bcdsub_eq  __builtin_vec_bcdsub_eq
+#define __builtin_bcdsub_gt  __builtin_vec_bcdsub_gt
+#define __builtin_bcdsub_ofl __builtin_vec_bcdsub_ov
+#define __builtin_bcdsub_ov  __builtin_vec_bcdsub_ov
+#define __builtin_bcdinvalid __builtin_vec_bcdinvalid
+#define __builtin_bcdmul10   __builtin_vec_bcdmul10
+#define __builtin_bcddiv10   __builtin_vec_bcddiv10
+#define __builtin_bcd2dfp    __builtin_vec_denb2dfp
+#define __builtin_bcdcmpeq(a,b)   __builtin_vec_bcdsub_eq(a,b,0)
+#define __builtin_bcdcmpgt(a,b)   __builtin_vec_bcdsub_gt(a,b,0)
+#define __builtin_bcdcmplt(a,b)   __builtin_vec_bcdsub_lt(a,b,0)
+#define __builtin_bcdcmpge(a,b)   __builtin_vec_bcdsub_ge(a,b,0)
+#define __builtin_bcdcmple(a,b)   __builtin_vec_bcdsub_le(a,b,0)
+
+
 /* Predicates.
    For C++, we use templates in order to allow non-parenthesized arguments.
    For C, instead, we use macros since non-parenthesized arguments were
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 0a2e634d6b0..6a6ce0f84ed 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -160,6 +160,7 @@
    UNSPEC_BCDADD
    UNSPEC_BCDSUB
    UNSPEC_BCD_OVERFLOW
+   UNSPEC_BCDSHIFT
    UNSPEC_VRLMI
    UNSPEC_VRLNM
    UNSPEC_VCFUGED
@@ -4410,12 +4411,13 @@
 (define_int_attr bcd_add_sub [(UNSPEC_BCDADD "add")
 			      (UNSPEC_BCDSUB "sub")])
 
-(define_code_iterator BCD_TEST [eq lt gt unordered])
+(define_code_iterator BCD_TEST [eq lt le gt ge unordered])
+(define_mode_iterator VBCD [V1TI V16QI])
 
-(define_insn "bcd<bcd_add_sub>"
-  [(set (match_operand:V1TI 0 "gpc_reg_operand" "=v")
-	(unspec:V1TI [(match_operand:V1TI 1 "gpc_reg_operand" "v")
-		      (match_operand:V1TI 2 "gpc_reg_operand" "v")
+(define_insn "bcd<bcd_add_sub>_<mode>"
+  [(set (match_operand:VBCD 0 "register_operand" "=v")
+	(unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
+		      (match_operand:VBCD 2 "register_operand" "v")
 		      (match_operand:QI 3 "const_0_to_1_operand" "n")]
 		     UNSPEC_BCD_ADD_SUB))
    (clobber (reg:CCFP CR6_REGNO))]
@@ -4428,23 +4430,23 @@
 ;; UNORDERED test on an integer type (like V1TImode) is not defined.  The type
 ;; probably should be one that can go in the VMX (Altivec) registers, so we
 ;; can't use DDmode or DFmode.
-(define_insn "*bcd<bcd_add_sub>_test"
+(define_insn "*bcd<bcd_add_sub>_test_<mode>"
   [(set (reg:CCFP CR6_REGNO)
 	(compare:CCFP
-	 (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "v")
-		       (match_operand:V1TI 2 "register_operand" "v")
+	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")
+		       (match_operand:VBCD 2 "register_operand" "v")
 		       (match_operand:QI 3 "const_0_to_1_operand" "i")]
 		      UNSPEC_BCD_ADD_SUB)
 	 (match_operand:V2DF 4 "zero_constant" "j")))
-   (clobber (match_scratch:V1TI 0 "=v"))]
+   (clobber (match_scratch:VBCD 0 "=v"))]
   "TARGET_P8_VECTOR"
   "bcd<bcd_add_sub>. %0,%1,%2,%3"
   [(set_attr "type" "vecsimple")])
 
-(define_insn "*bcd<bcd_add_sub>_test2"
-  [(set (match_operand:V1TI 0 "register_operand" "=v")
-	(unspec:V1TI [(match_operand:V1TI 1 "register_operand" "v")
-		      (match_operand:V1TI 2 "register_operand" "v")
+(define_insn "*bcd<bcd_add_sub>_test2_<mode>"
+  [(set (match_operand:VBCD 0 "register_operand" "=v")
+	(unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
+		      (match_operand:VBCD 2 "register_operand" "v")
 		      (match_operand:QI 3 "const_0_to_1_operand" "i")]
 		     UNSPEC_BCD_ADD_SUB))
    (set (reg:CCFP CR6_REGNO)
@@ -4540,15 +4542,15 @@
 }
    [(set_attr "type" "vecsimple")])
 
-(define_expand "bcd<bcd_add_sub>_<code>"
+(define_expand "bcd<bcd_add_sub>_<code>_<mode>"
   [(parallel [(set (reg:CCFP CR6_REGNO)
 		   (compare:CCFP
-		    (unspec:V2DF [(match_operand:V1TI 1 "register_operand")
-				  (match_operand:V1TI 2 "register_operand")
+		    (unspec:V2DF [(match_operand:VBCD 1 "register_operand")
+				  (match_operand:VBCD 2 "register_operand")
 				  (match_operand:QI 3 "const_0_to_1_operand")]
 				 UNSPEC_BCD_ADD_SUB)
 		    (match_dup 4)))
-	      (clobber (match_scratch:V1TI 5))])
+	      (clobber (match_scratch:VBCD 5))])
    (set (match_operand:SI 0 "register_operand")
 	(BCD_TEST:SI (reg:CCFP CR6_REGNO)
 		     (const_int 0)))]
@@ -4557,6 +4559,74 @@
   operands[4] = CONST0_RTX (V2DFmode);
 })
 
+(define_insn "*bcdinvalid_<mode>"
+  [(set (reg:CCFP CR6_REGNO)
+	(compare:CCFP
+	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")]
+		      UNSPEC_BCDADD)
+	 (match_operand:V2DF 2 "zero_constant" "j")))
+   (clobber (match_scratch:VBCD 0 "=v"))]
+  "TARGET_P8_VECTOR"
+  "bcdadd. %0,%1,%1,0"
+  [(set_attr "type" "vecsimple")])
+
+(define_expand "bcdinvalid_<mode>"
+  [(parallel [(set (reg:CCFP CR6_REGNO)
+		   (compare:CCFP
+		    (unspec:V2DF [(match_operand:VBCD 1 "register_operand")]
+				 UNSPEC_BCDADD)
+		    (match_dup 2)))
+	      (clobber (match_scratch:VBCD 3))])
+   (set (match_operand:SI 0 "register_operand")
+	(unordered:SI (reg:CCFP CR6_REGNO)
+		      (const_int 0)))]
+  "TARGET_P8_VECTOR"
+{
+  operands[2] = CONST0_RTX (V2DFmode);
+})
+
+(define_insn "bcdshift_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand" "=v")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
+		       (match_operand:V16QI 2 "register_operand" "v")
+		       (match_operand:QI 3 "const_0_to_1_operand" "n")]
+		     UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P8_VECTOR"
+  "bcds. %0,%1,%2,%3"
+  [(set_attr "type" "vecsimple")])
+
+(define_expand "bcdmul10_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
+		      UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P9_VECTOR"
+{
+  rtx one = gen_reg_rtx (V16QImode);
+
+  emit_insn (gen_altivec_vspltisb (one, const1_rtx));
+  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
+
+  DONE;
+})
+
+(define_expand "bcddiv10_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
+		      UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P9_VECTOR"
+{
+  rtx one = gen_reg_rtx (V16QImode);
+
+  emit_insn (gen_altivec_vspltisb (one, constm1_rtx));
+  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
+
+  DONE;
+})
+
+
 ;; Peephole2 pattern to combine a bcdadd/bcdsub that calculates the value and
 ;; the bcdadd/bcdsub that tests the value.  The combiner won't work since
 ;; CR6 is a hard coded register.  Unfortunately, all of the Altivec predicate
diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md
index 8f822732bac..9a952300cd6 100644
--- a/gcc/config/rs6000/dfp.md
+++ b/gcc/config/rs6000/dfp.md
@@ -273,6 +273,28 @@
   "denbcd<q> %1,%0,%2"
   [(set_attr "type" "dfp")])
 
+(define_insn "dfp_denbcd_v16qi_inst"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
+	(unspec:TD [(match_operand:QI 1 "const_0_to_1_operand" "i")
+		    (match_operand:V16QI 2 "register_operand" "d")]
+		   UNSPEC_DENBCD))]
+  "TARGET_DFP"
+  "denbcdq %1,%0,%2"
+  [(set_attr "type" "dfp")])
+
+(define_expand "dfp_denbcd_v16qi"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
+	(unspec:TD [(match_operand:V16QI 1 "register_operand" "v")]
+		   UNSPEC_DENBCD))]
+  "TARGET_DFP"
+ {
+   // Move vs128 upper 64-bits and lower 64-bits to fp register pair
+   convert_move (operands[0], operands[1], true);
+   emit_insn (gen_dfp_denbcd_v16qi_inst (operands[0], GEN_INT(1),
+					 operands[0]));
+   DONE;
+ })
+
 (define_insn "dfp_dxex_<mode>"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
 	(unspec:DI [(match_operand:DDTD 1 "gpc_reg_operand" "d")]
diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
index 5b05da87f4b..a58102c3785 100644
--- a/gcc/config/rs6000/rs6000-builtin.def
+++ b/gcc/config/rs6000/rs6000-builtin.def
@@ -696,6 +696,14 @@
 /* Miscellaneous builtins for instructions added in ISA 2.07.  These
    instructions do require the ISA 2.07 vector support, but they aren't vector
    instructions.  */
+#define BU_P8V_MISC_1(ENUM, NAME, ATTR, ICODE)				\
+  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
+		    "__builtin_" NAME,			/* NAME */	\
+		    RS6000_BTM_P8_VECTOR,		/* MASK */	\
+		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
+		     | RS6000_BTC_UNARY),				\
+		    CODE_FOR_ ## ICODE)			/* ICODE */
+
 #define BU_P8V_MISC_3(ENUM, NAME, ATTR, ICODE)				\
   RS6000_BUILTIN_3 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
 		    "__builtin_" NAME,			/* NAME */	\
@@ -2668,16 +2676,55 @@ BU_P7_MISC_1 (CBCDTD,		"cbcdtd",	CONST,	cbcdtd)
 BU_P7_MISC_2 (ADDG6S,		"addg6s",	CONST,	addg6s)
 
 /* 3 argument BCD functions added in ISA 2.07.  */
-BU_P8V_MISC_3 (BCDADD,		"bcdadd",	CONST,	bcdadd)
-BU_P8V_MISC_3 (BCDADD_LT,	"bcdadd_lt",	CONST,	bcdadd_lt)
-BU_P8V_MISC_3 (BCDADD_EQ,	"bcdadd_eq",	CONST,	bcdadd_eq)
-BU_P8V_MISC_3 (BCDADD_GT,	"bcdadd_gt",	CONST,	bcdadd_gt)
-BU_P8V_MISC_3 (BCDADD_OV,	"bcdadd_ov",	CONST,	bcdadd_unordered)
-BU_P8V_MISC_3 (BCDSUB,		"bcdsub",	CONST,	bcdsub)
-BU_P8V_MISC_3 (BCDSUB_LT,	"bcdsub_lt",	CONST,	bcdsub_lt)
-BU_P8V_MISC_3 (BCDSUB_EQ,	"bcdsub_eq",	CONST,	bcdsub_eq)
-BU_P8V_MISC_3 (BCDSUB_GT,	"bcdsub_gt",	CONST,	bcdsub_gt)
-BU_P8V_MISC_3 (BCDSUB_OV,	"bcdsub_ov",	CONST,	bcdsub_unordered)
+BU_P8V_MISC_3 (BCDADD_V1TI,	"bcdadd_v1ti",	CONST,	bcdadd_v1ti)
+BU_P8V_MISC_3 (BCDADD_V16QI,	"bcdadd_v16qi",	CONST,	bcdadd_v16qi)
+BU_P8V_MISC_3 (BCDADD_LT_V1TI,	"bcdadd_lt_v1ti",  CONST, bcdadd_lt_v1ti)
+BU_P8V_MISC_3 (BCDADD_LT_V16QI,	"bcdadd_lt_v16qi", CONST, bcdadd_lt_v16qi)
+BU_P8V_MISC_3 (BCDADD_EQ_V1TI,	"bcdadd_eq_v1ti",  CONST, bcdadd_eq_v1ti)
+BU_P8V_MISC_3 (BCDADD_EQ_V16QI,	"bcdadd_eq_v16qi", CONST, bcdadd_eq_v16qi)
+BU_P8V_MISC_3 (BCDADD_GT_V1TI,	"bcdadd_gt_v1ti",  CONST, bcdadd_gt_v1ti)
+BU_P8V_MISC_3 (BCDADD_GT_V16QI,	"bcdadd_gt_v16qi", CONST, bcdadd_gt_v16qi)
+BU_P8V_MISC_3 (BCDADD_OV_V1TI,	"bcdadd_ov_v1ti",  CONST, bcdadd_unordered_v1ti)
+BU_P8V_MISC_3 (BCDADD_OV_V16QI,	"bcdadd_ov_v16qi", CONST, bcdadd_unordered_v16qi)
+
+BU_P8V_MISC_3 (BCDSUB_V1TI,	"bcdsub_v1ti",	CONST,	bcdsub_v1ti)
+BU_P8V_MISC_3 (BCDSUB_V16QI,	"bcdsub_v16qi",	CONST,	bcdsub_v16qi)
+BU_P8V_MISC_3 (BCDSUB_LT_V1TI,	"bcdsub_lt_v1ti",  CONST, bcdsub_lt_v1ti)
+BU_P8V_MISC_3 (BCDSUB_LT_V16QI,	"bcdsub_lt_v16qi", CONST, bcdsub_lt_v16qi)
+BU_P8V_MISC_3 (BCDSUB_LE_V1TI,	"bcdsub_le_v1ti",  CONST, bcdsub_le_v1ti)
+BU_P8V_MISC_3 (BCDSUB_LE_V16QI,	"bcdsub_le_v16qi", CONST, bcdsub_le_v16qi)
+BU_P8V_MISC_3 (BCDSUB_EQ_V1TI,	"bcdsub_eq_v1ti",  CONST, bcdsub_eq_v1ti)
+BU_P8V_MISC_3 (BCDSUB_EQ_V16QI,	"bcdsub_eq_v16qi", CONST, bcdsub_eq_v16qi)
+BU_P8V_MISC_3 (BCDSUB_GT_V1TI,	"bcdsub_gt_v1ti",  CONST, bcdsub_gt_v1ti)
+BU_P8V_MISC_3 (BCDSUB_GT_V16QI,	"bcdsub_gt_v16qi", CONST, bcdsub_gt_v16qi)
+BU_P8V_MISC_3 (BCDSUB_GE_V1TI,	"bcdsub_ge_v1ti",  CONST, bcdsub_ge_v1ti)
+BU_P8V_MISC_3 (BCDSUB_GE_V16QI,	"bcdsub_ge_v16qi", CONST, bcdsub_ge_v16qi)
+BU_P8V_MISC_3 (BCDSUB_OV_V1TI,	"bcdsub_ov_v1ti",  CONST, bcdsub_unordered_v1ti)
+BU_P8V_MISC_3 (BCDSUB_OV_V16QI,	"bcdsub_ov_v16qi", CONST, bcdsub_unordered_v16qi)
+
+BU_P8V_MISC_1 (BCDINVALID_V1TI,	"bcdinvalid_v1ti",  CONST, bcdinvalid_v1ti)
+BU_P8V_MISC_1 (BCDINVALID_V16QI, "bcdinvalid_v16qi", CONST, bcdinvalid_v16qi)
+
+BU_P9V_AV_1 (BCDMUL10_V16QI, "bcdmul10_v16qi", CONST, bcdmul10_v16qi)
+BU_P9V_AV_1 (BCDDIV10_V16QI, "bcddiv10_v16qi", CONST, bcddiv10_v16qi)
+BU_P8V_MISC_1 (DENBCD_V16QI,	"denb2dfp_v16qi", CONST, dfp_denbcd_v16qi)
+
+BU_P8V_OVERLOAD_3 (BCDADD,	"bcdadd")
+BU_P8V_OVERLOAD_3 (BCDADD_LT,	"bcdadd_lt")
+BU_P8V_OVERLOAD_3 (BCDADD_EQ,	"bcdadd_eq")
+BU_P8V_OVERLOAD_3 (BCDADD_GT,	"bcdadd_gt")
+BU_P8V_OVERLOAD_3 (BCDADD_OV,	"bcdadd_ov")
+BU_P8V_OVERLOAD_3 (BCDSUB,	"bcdsub")
+BU_P8V_OVERLOAD_3 (BCDSUB_LT,	"bcdsub_lt")
+BU_P8V_OVERLOAD_3 (BCDSUB_LE,	"bcdsub_le")
+BU_P8V_OVERLOAD_3 (BCDSUB_EQ,	"bcdsub_eq")
+BU_P8V_OVERLOAD_3 (BCDSUB_GT,	"bcdsub_gt")
+BU_P8V_OVERLOAD_3 (BCDSUB_GE,	"bcdsub_ge")
+BU_P8V_OVERLOAD_3 (BCDSUB_OV,	"bcdsub_ov")
+BU_P8V_OVERLOAD_1 (BCDINVALID,	"bcdinvalid")
+BU_P9V_OVERLOAD_1 (BCDMUL10,	"bcdmul10")
+BU_P9V_OVERLOAD_1 (BCDDIV10,	"bcddiv10")
+BU_P8V_OVERLOAD_1 (DENBCD,	"denb2dfp")
 
 /* 2 argument pack/unpack 128-bit floating point types.  */
 BU_DFP_MISC_2 (PACK_TD,		"pack_dec128",		CONST,	packtd)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index b044778a7ae..92378e958a9 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -985,6 +985,82 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = {
     RS6000_BTI_unsigned_V4SI, RS6000_BTI_V4SF, RS6000_BTI_INTSI, 0 },
   { ALTIVEC_BUILTIN_VEC_CTU, VSX_BUILTIN_XVCVDPUXDS_SCALE,
     RS6000_BTI_unsigned_V2DI, RS6000_BTI_V2DF, RS6000_BTI_INTSI, 0 },
+
+  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V1TI,
+    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, 0, 0 },
+  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P9V_BUILTIN_VEC_BCDMUL10, P9V_BUILTIN_BCDMUL10_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+  { P9V_BUILTIN_VEC_BCDDIV10, P9V_BUILTIN_BCDDIV10_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P8V_BUILTIN_VEC_DENBCD, MISC_BUILTIN_DENBCD_V16QI,
+    RS6000_BTI_dfloat128, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V1TI,
+    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+
+
   { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVSP,
     RS6000_BTI_V4SF, RS6000_BTI_V4SF, RS6000_BTI_V4SF, 0 },
   { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVDP,
@@ -10570,14 +10646,22 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
     }
   else if (icode == CODE_FOR_vsx_set_v2df
            || icode == CODE_FOR_vsx_set_v2di
-	   || icode == CODE_FOR_bcdadd
-	   || icode == CODE_FOR_bcdadd_lt
-	   || icode == CODE_FOR_bcdadd_eq
-	   || icode == CODE_FOR_bcdadd_gt
-	   || icode == CODE_FOR_bcdsub
-	   || icode == CODE_FOR_bcdsub_lt
-	   || icode == CODE_FOR_bcdsub_eq
-	   || icode == CODE_FOR_bcdsub_gt)
+	   || icode == CODE_FOR_bcdadd_v16qi
+	   || icode == CODE_FOR_bcdadd_v1ti
+	   || icode == CODE_FOR_bcdadd_lt_v16qi
+	   || icode == CODE_FOR_bcdadd_lt_v1ti
+	   || icode == CODE_FOR_bcdadd_eq_v16qi
+	   || icode == CODE_FOR_bcdadd_eq_v1ti
+	   || icode == CODE_FOR_bcdadd_gt_v16qi
+	   || icode == CODE_FOR_bcdadd_gt_v1ti
+	   || icode == CODE_FOR_bcdsub_v16qi
+	   || icode == CODE_FOR_bcdsub_v1ti
+	   || icode == CODE_FOR_bcdsub_lt_v16qi
+	   || icode == CODE_FOR_bcdsub_lt_v1ti
+	   || icode == CODE_FOR_bcdsub_eq_v16qi
+	   || icode == CODE_FOR_bcdsub_eq_v1ti
+	   || icode == CODE_FOR_bcdsub_gt_v16qi
+	   || icode == CODE_FOR_bcdsub_gt_v1ti)
     {
       /* Only allow 1-bit unsigned literals.  */
       STRIP_NOPS (arg2);
@@ -10601,7 +10685,8 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
 	}
     }
   else if (icode == CODE_FOR_dfp_denbcd_dd
-	   || icode == CODE_FOR_dfp_denbcd_td)
+	   || icode == CODE_FOR_dfp_denbcd_td
+	   || icode == CODE_FOR_dfp_denbcd_v16qi)
     {
       /* Only allow 1-bit unsigned literals.  */
       STRIP_NOPS (arg0);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 5be1cbecf60..0b701ee506f 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -20161,15 +20161,28 @@ __int128 vec_vsubuqm (__int128, __int128);
 __uint128 vec_vsubuqm (__uint128, __uint128);
 
 vector __int128 __builtin_bcdadd (vector __int128, vector __int128, const int);
+vector unsigned char __builtin_bcdadd (vector unsigned char, vector unsigned char,
+                                       const int);
 int __builtin_bcdadd_lt (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_lt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_eq (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_eq (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_gt (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_gt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_ov (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_ov (vector unsigned char, vector unsigned char, const int);
+
 vector __int128 __builtin_bcdsub (vector __int128, vector __int128, const int);
+vector unsigned char __builtin_bcdsub (vector unsigned char, vector unsigned char,
+                                       const int);
 int __builtin_bcdsub_lt (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_lt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_eq (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_eq (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_gt (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_gt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_ov (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_ov (vector unsigned char, vector unsigned char, const int);
 @end smallexample
 
 @node PowerPC AltiVec Built-in Functions Available on ISA 3.0
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-2.c b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
index 2f51dee257f..95c3699a144 100644
--- a/gcc/testsuite/gcc.target/powerpc/bcd-2.c
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
@@ -14,6 +14,8 @@
 /* { dg-final { scan-assembler-not   "stxvw4x" 	      } } */
 /* { dg-final { scan-assembler-not   "stxvd2x" 	      } } */
 
+#include <altivec.h>
+
 typedef __int128_t __attribute__((__vector_size__(16)))	vector_128_t;
 typedef __int128_t					scalar_128_t;
 typedef	unsigned long long				scalar_64_t;
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-3.c b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
index 1b20841ae1c..7948a0c95e2 100644
--- a/gcc/testsuite/gcc.target/powerpc/bcd-3.c
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
@@ -18,6 +18,8 @@ typedef __int128_t __attribute__((__vector_size__(16)))	vector_128_t;
 typedef __int128_t					scalar_128_t;
 typedef	unsigned long long				scalar_64_t;
 
+#include <altivec.h>
+
 /* Test whether the peephole works to allow folding a bcdadd, with a
    bcdadd_<test> into a single instruction.  */
 
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-4.c b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
new file mode 100644
index 00000000000..6d30e49126c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
@@ -0,0 +1,519 @@
+/* { dg-do compile { target int128  } } */
+/* { dg-require-effective-target power10_hw } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
+/* { dg-final { scan-assembler-times "\mbcdadd\M" 7 } } */
+/* { dg-final { scan-assembler-times "\mbcdsub\M" 18 } } */
+/* { dg-final { scan-assembler-times "\mbcds\M" 2 } } */
+/* { dg-final { scan-assembler-times "\mdenbcdq\M" 1 } } */
+
+#include <altivec.h>
+
+#define DEBUG 0
+
+#if DEBUG
+#include <stdio.h>
+#endif
+
+
+#define BCD_POS0  12    //  0xC
+#define BCD_POS1  15    //  0xF
+#define BCD_NEG   13    //  0xD
+
+void abort (void);
+
+  union conv_t
+    {
+      _Decimal128 d128;
+      vector  unsigned char ch;
+      vector  long long unsigned int vllui;
+    } conv;
+  
+_Decimal128 convert_vec_char (vector unsigned char a)
+{
+  union conv_t conv;
+  _Decimal128 result;
+  
+  conv.ch = a;
+  result = conv.d128;
+  return result;
+}
+			      
+vector unsigned char maxbcd(unsigned int sign)
+{
+  vector unsigned char result;
+  int i;
+
+  for (i = 15; i > 0; i--)
+    result[i] = 0x99;
+
+  result[0] = sign << 4 | 0x9;
+}
+
+vector unsigned char num2bcd(long int a, int encoding)
+{
+  int i;
+  unsigned int hi, low, sign;
+  
+  vector unsigned char result;
+
+  if (a > 0) {
+    if (encoding == 0)
+      sign = BCD_POS0;
+    else
+      sign = BCD_POS1;
+
+  } else {
+    sign = BCD_NEG;
+    a = -a;
+  }
+
+  hi = a % 10;   // 1st digit
+  a = a / 10;
+  result[0] = hi << 4| sign;
+
+  for (i = 1; i < 16; i++)
+    {
+      low = a % 10;
+      a = a / 10;
+      hi = a % 10;
+      a = a / 10;
+      result[i] = hi << 4 | low;
+    }
+
+
+  return result;
+}
+
+int main ()
+{
+  int i;
+  long int value_a, value_b, value_result;
+  vector unsigned char a, b, result, exp_result;
+  _Decimal128 result_d128, exp_result_d128;
+
+  /* Make a and b positive BCD numbers */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_b = 101010;
+  b = num2bcd(value_b, 0);
+ 
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdadd (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not match "
+	     "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS0);
+#else
+      abort();
+#endif
+
+  /* Make a and b positive BCD numbers using alternate positive encoding.  */
+  value_a = 1030507;
+  a = num2bcd(value_a, 1);
+
+  value_b = 204060;
+  b = num2bcd(value_b, 1);
+
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 1);
+  
+  result = __builtin_bcdadd (a, b, 1);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* Result should be positive, alternate encoding.  */
+  if ((result[0] & 0xF) != BCD_POS1)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not "
+	   "match expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+  /* Make a and b negative BCD numbers */
+  value_a = -1030507;
+  a = num2bcd(value_a, 0);
+
+  value_b = -1010101;
+  b = num2bcd(value_b, 0);
+
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdadd (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i]  != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd, neg result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be negative */
+  if ((result[0] & 0xF) != BCD_NEG)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign, neg of result is %d.  Does not "
+	   "match expected_result = %d\n",
+	     result[0] & 0xF, BCD_NEG);
+#else
+    abort();
+#endif
+
+ 
+  /* Make a negative, b positive BCD numbers */
+  value_a = -1030507;
+  a = num2bcd(value_a, 0);
+
+  value_b = 1010101;
+  b = num2bcd(value_b, 0);
+
+  value_result = value_a - value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdsub (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdsub, neg result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive, alt encoding */
+  if ((result[0] & 0xF) != BCD_NEG)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign, of result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_NEG);
+#else
+    abort();
+#endif
+
+  /* Make a and b positive BCD numbers */
+  value_a = 1030507;
+  a = num2bcd(value_a, 1);
+
+  value_b = 1010101;
+  b = num2bcd(value_b, 1);
+
+  value_result = value_a - value_b;
+  exp_result = num2bcd(value_result, 1);
+  
+  result = __builtin_bcdsub (a, b, 1);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcdsub, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS1)
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+      abort();
+#endif
+
+  /* Test overflow add and subtract.  */
+  a = maxbcd(BCD_POS0);
+  b = maxbcd(BCD_POS0);
+
+  if(__builtin_bcdadd_ofl (a, b, 0) == 0)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd did not overflow as expected\n");
+#else
+    abort();
+#endif
+
+  value_a = 99999999;
+  a = num2bcd(value_a, 0);
+
+  value_b = 999999999;
+  b = num2bcd(value_b, 0);
+
+  if(__builtin_bcdadd_ofl (a, b, 0))
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd unexpectedly overflowed\n");
+#else
+    abort();
+#endif
+
+  a = maxbcd(BCD_NEG);
+  b = maxbcd(BCD_NEG);
+
+  if (__builtin_bcdsub_ofl (a, b, 0) == 0)
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub did not overflow as expected\n");
+#else
+    abort();
+#endif
+
+  value_a = -99999999;
+  a = num2bcd(value_a, 0);
+
+  value_b = -999999999;
+  b = num2bcd(value_b, 0);
+
+  if (__builtin_bcdsub_ofl (a, b, 0))
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub unexpectedly overflowed\n");
+#else
+    abort();
+#endif
+
+  /* Test arguments for valid/invalid */
+  if (__builtin_bcdinvalid (a))
+#if DEBUG
+    printf("ERROR: __builtin_invalid input is unexpectedly invalid.\n");
+#else
+    abort();
+#endif
+
+  a[3] = 0xBB;     /* an invalid BCD digit */
+  if (!__builtin_bcdinvalid (a))
+#if DEBUG
+    printf("ERROR: __builtin_invalid input is unexpectedly valid.\n");
+#else
+    abort();
+#endif
+
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_b = 101010;
+  b = num2bcd(value_b, 0);
+
+  /* Test equality */
+  if (__builtin_bcdcmpeq (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmpeq (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+
+  /* Test a greater then b, inputs already setup this way.  */
+  if (!__builtin_bcdcmpgt (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpgt (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpgt (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt input equal, result is unexpectedly "
+	   "1.\n");
+#else
+    abort();
+#endif
+
+
+  if (!__builtin_bcdcmpge (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpge (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmpge (b, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge inputs equal result is unexpectedly "
+	   "0.\n");
+#else
+    abort();
+#endif
+
+  /* Test a less then b.  */
+  value_a = 101010;
+  a = num2bcd(value_a, 0);
+  value_b = 1020304;
+  b = num2bcd(value_b, 0);
+
+  if (!__builtin_bcdcmplt (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmplt (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmplt (b, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt inputs equal result is unexpectedly "
+	   "1.\n");
+#else
+    abort();
+#endif
+
+
+  if (!__builtin_bcdcmple (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmple (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmple (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple inputs equal result is unexpectedly "
+	   "0.\n");
+#else
+    abort();
+#endif
+
+  /* Test multipy 10 */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_result = value_a * 10;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdmul10 (a);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcdmul10, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if 0
+    printf("ERROR: __builtin_bcdmul10 sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	   result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+  /* Test divide 10 */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_result = value_a / 10;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcddiv10 (a);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcddiv10, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if DEBUG
+    printf("ERROR: __builtin_bcddiv10 sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+   value_a = 1020304;
+   exp_result_d128 = 1020304;
+   a = num2bcd(value_a, 0);
+
+   conv.ch = a;
+   conv.d128 = __builtin_bcd2dfp (a);
+   result_d128 = conv.d128;
+   
+   if (result_d128 != exp_result_d128)
+#if DEBUG
+     printf("ERROR: __builtin_bcd2dfp, result does not match expected_result."
+	    "\n");
+#else
+     abort();
+#endif
+}
+
David Edelsohn Oct. 29, 2020, 12:43 a.m. UTC | #3
On Wed, Oct 28, 2020 at 7:21 PM Carl Love <cel@us.ibm.com> wrote:
>
> David:
>
> On Sat, 2020-10-24 at 11:29 -0400, David Edelsohn wrote:
> > Hi, Carl
> >
> > Not commenting on the implementation.
> >
> > Please stop using powerpc*-*-* in the test cases.  The test cases
> > already are in the gcc.target/powerpc directory.
> >
> > Do the test cases really need lp64, or should this require something
> > like int128?
> >
> > Thanks, David
>
> OK, I looked at the test case and it really needs 128-bit integer
> support.  I changed the test case header to:
>
> +++ b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
> @@ -0,0 +1,519 @@
> +/* { dg-do compile { target int128  } } */
> +/* { dg-require-effective-target power10_hw } */
> +/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
>
> I reran the regression test.  There were no regressions.  Does the
> above look more reasonable?

Better, but please use

/* { dg-require-effective-target int128 } */

not "target int128" in the selector.  Segher and I both agree that
it's cleaner and more readable.  The selector (the target part on the
dg-do line) should not be used for this type of requirement.

Thanks David
Carl Love Oct. 30, 2020, 4:36 p.m. UTC | #4
David:

On Wed, 2020-10-28 at 20:43 -0400, David Edelsohn wrote:
> Better, but please use
> 
> /* { dg-require-effective-target int128 } */
> 
> not "target int128" in the selector.  Segher and I both agree that
> it's cleaner and more readable.  The selector (the target part on the
> dg-do line) should not be used for this type of requirement.

OK, redid the test case.  It now reads:

+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/
* { dg-require-effective-target power10_hw } */
+/* { dg-options "-
mdejagnu-cpu=power10 -O2" } */
+/* { dg-final { scan-assembler-times
"\mbcdadd\M" 7 } } */
+/* { dg-final { scan-assembler-times "\mbcdsub\M"
18 } } */
+/* { dg-final { scan-assembler-times "\mbcds\M" 2 } } */
+/* {
dg-final { scan-assembler-times "\mdenbcdq\M" 1 } } */
+

Reran the regresion, no new failures were reported.

Please let me know if that looks OK.  Thanks.

                           Carl 
------------------------------------

Gcc maintainers:

The following patch adds support for the built-ins listed in Table B.1,
"Binary-Coded Decimal Built-In Functions" of the "64-Bit ELF V2 ABI
Specification", July 30, 2019.

The built-ins adds support the V16QI type for addition, subtraction and
comparison as sepcified in the Table B.1.  Note, the V1TI type was
previously supported for add, subtract and comparison.  The builtins
for test for valid value, multiply by 10, divide by 10 and conversion
to DFP value are also added for the V16QI type as specified in Table
B.1.

The patch includes adding the #include <altivec.h> to the existing bcd-
2.c and bcd-3.c tests so they will pass the regression tests as the
builtins names are now listed in altivec.h rather then just using
internal names.

The patch was compiled and tested on:

  powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions. 

Please let me know if this patch is acceptable for mainline.  Thanks.

                Carl Love

-------------------------------------------------------------


2020-10-29  Carl Love  <cel@us.ibm.com>

gcc/
        PR target/93449
	* config/rs6000/altivec.h (__builtin_bcdadd, __builtin_bcdadd_lt,
	__builtin_bcdadd_eq, __builtin_bcdadd_gt, __builtin_bcdadd_ofl,
	__builtin_bcdadd_ov, __builtin_bcdsub, __builtin_bcdsub_lt,
	__builtin_bcdsub_eq, __builtin_bcdsub_gt, __builtin_bcdsub_ofl,
	__builtin_bcdsub_ov, __builtin_bcdinvalid, __builtin_bcdmul10,
	__builtin_bcddiv10, __builtin_bcd2dfp, __builtin_bcdcmpeq,
 	__builtin_bcdcmpgt, __builtin_bcdcmplt, __builtin_bcdcmpge,
	__builtin_bcdcmple): Add defines.
	* config/rs6000/altivec.md: Add UNSPEC_BCDSHIFT.
	(BCD_TEST): Add le, ge to code iterator.
	Add VBCD mode iterator.
	(bcd<bcd_add_sub>_test, *bcd<bcd_add_sub>_test2,
	bcd<bcd_add_sub>_<code>, bcd<bcd_add_sub>_<code>): Add mode to name.
	Change iterator from V1TI to VBCD.
	(*bcdinvalid_<mode>, bcdshift_v16qi): New define_insn.
	(bcdinvalid_<mode>, bcdmul10_v16qi, bcddiv10_v16qi): New define.
	config/rs6000/dfp.md (dfp_denbcd_v16qi_inst): New define_insn.
	(dfp_denbcd_v16qi): New define_expand.
	* confit/rs6000/rs6000-builtin.def (BU_P8V_MISC_1): New define.
	(BCDADD): Replaced with BCDADD_V1TI and BCDADD_V16QI.
	(BCDADD_LT): Replaced with BCDADD_LT_V1TI and BCDADD_LT_V16QI.
	(BCDADD_EQ): Replaced with BCDADD_EQ_V1TI and BCDADD_EQ_V16QI.
	(BCDADD_GT): Replaced with BCDADD_GT_V1TI and BCDADD_GT_V16QI.
	(BCDADD_OV): Replaced with BCDADD_OV_V1TI and BCDADD_OV_V16QI.
	(BCDSUB_V1TI, BCDSUB_V16QI, BCDSUB_LT_V1TI, BCDSUB_LT_V16QI,
	BCDSUB_LE_V1TI, BCDSUB_LE_V16QI, BCDSUB_EQ_V1TI, BCDSUB_EQ_V16QI,
	BCDSUB_GT_V1TI, BCDSUB_GT_V16QI, BCDSUB_GE_V1TI, BCDSUB_GE_V16QI,
	BCDSUB_OV_V1TI, BCDSUB_OV_V16QI, BCDINVALID_V1TI, BCDINVALID_V16QI,
	BCDMUL10_V16QI, BCDDIV10_V16QI, DENBCD_V16QI): New builtin definitions.
	(BCDADD, BCDADD_LT, BCDADD_EQ, BCDADD_GT, BCDADD_OV, BCDSUB, BCDSUB_LT,
	BCDSUB_LE, BCDSUB_EQ, BCDSUB_GT, BCDSUB_GE, BCDSUB_OV, BCDINVALID,
	BCDMUL10, BCDDIV10, DENBCD): New overload definitions.
	config/rs6000/rs6000-call.c (P8V_BUILTIN_VEC_BCDADD, P8V_BUILTIN_VEC_BCDADD_LT,
	P8V_BUILTIN_VEC_BCDADD_EQ, P8V_BUILTIN_VEC_BCDADD_GT, P8V_BUILTIN_VEC_BCDADD_OV,
	P8V_BUILTIN_VEC_BCDINVALID, P9V_BUILTIN_VEC_BCDMUL10, P8V_BUILTIN_VEC_DENBCD.
	P8V_BUILTIN_VEC_BCDSUB, P8V_BUILTIN_VEC_BCDSUB_LT, P8V_BUILTIN_VEC_BCDSUB_LE,
	P8V_BUILTIN_VEC_BCDSUB_EQ, P8V_BUILTIN_VEC_BCDSUB_GT, P8V_BUILTIN_VEC_BCDSUB_GE,
	P8V_BUILTIN_VEC_BCDSUB_OV): New overloaded specifications.
	(CODE_FOR_bcdadd): Replaced with CODE_FOR_bcdadd_v16qi and CODE_FOR_bcdadd_v1ti.
	(CODE_FOR_bcdadd_lt): Replaced with CODE_FOR_bcdadd_lt_v16qi and CODE_FOR_bcdadd_lt_v1ti.
	(CODE_FOR_bcdadd_eq): Replaced with CODE_FOR_bcdadd_eq_v16qi and CODE_FOR_bcdadd_eq_v1ti.
	(CODE_FOR_bcdadd_gt): Replaced with CODE_FOR_bcdadd_gt_v16qi and CODE_FOR_bcdadd_gt_v1ti.
	(CODE_FOR_bcdsub): Replaced with CODE_FOR_bcdsub_v16qi and CODE_FOR_bcdsub_v1ti.
	(CODE_FOR_bcdsub_lt): Replaced with CODE_FOR_bcdsub_lt_v16qi and CODE_FOR_bcdsub_lt_v1ti.
	(CODE_FOR_bcdsub_eq): Replaced with CODE_FOR_bcdsub_eq_v16qi and CODE_FOR_bcdsub_eq_v1ti.
	(CODE_FOR_bcdsub_gt): Replaced with CODE_FOR_bcdsub_gt_v16qi and CODE_FOR_bcdsub_gt_v1ti.
	(rs6000_expand_ternop_builtin):  Add CODE_FOR_dfp_denbcd_v16qi to else if.
	* doc/extend.texi: Add documentation for new builtins.

gcc/testsuite/
	* gcc.target/powerpc/bcd-3.c: Add include altivec.h.
	* gcc.target/powerpc/bcd-4.c: New test.
---
 gcc/config/rs6000/altivec.h              |  25 ++
 gcc/config/rs6000/altivec.md             | 104 ++++-
 gcc/config/rs6000/dfp.md                 |  22 +
 gcc/config/rs6000/rs6000-builtin.def     |  67 ++-
 gcc/config/rs6000/rs6000-call.c          | 103 ++++-
 gcc/doc/extend.texi                      |  13 +
 gcc/testsuite/gcc.target/powerpc/bcd-2.c |   2 +
 gcc/testsuite/gcc.target/powerpc/bcd-3.c |   2 +
 gcc/testsuite/gcc.target/powerpc/bcd-4.c | 520 +++++++++++++++++++++++
 9 files changed, 822 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/bcd-4.c

diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
index df10a8c498d..e1884f51bd8 100644
--- a/gcc/config/rs6000/altivec.h
+++ b/gcc/config/rs6000/altivec.h
@@ -497,8 +497,33 @@
 
 #define vec_xlx __builtin_vec_vextulx
 #define vec_xrx __builtin_vec_vexturx
+
 #endif
 
+/* BCD builtins, map ABI builtin name to existing builtin name.  */
+#define __builtin_bcdadd     __builtin_vec_bcdadd
+#define __builtin_bcdadd_lt  __builtin_vec_bcdadd_lt
+#define __builtin_bcdadd_eq  __builtin_vec_bcdadd_eq
+#define __builtin_bcdadd_gt  __builtin_vec_bcdadd_gt
+#define __builtin_bcdadd_ofl __builtin_vec_bcdadd_ov
+#define __builtin_bcdadd_ov  __builtin_vec_bcdadd_ov
+#define __builtin_bcdsub     __builtin_vec_bcdsub
+#define __builtin_bcdsub_lt  __builtin_vec_bcdsub_lt
+#define __builtin_bcdsub_eq  __builtin_vec_bcdsub_eq
+#define __builtin_bcdsub_gt  __builtin_vec_bcdsub_gt
+#define __builtin_bcdsub_ofl __builtin_vec_bcdsub_ov
+#define __builtin_bcdsub_ov  __builtin_vec_bcdsub_ov
+#define __builtin_bcdinvalid __builtin_vec_bcdinvalid
+#define __builtin_bcdmul10   __builtin_vec_bcdmul10
+#define __builtin_bcddiv10   __builtin_vec_bcddiv10
+#define __builtin_bcd2dfp    __builtin_vec_denb2dfp
+#define __builtin_bcdcmpeq(a,b)   __builtin_vec_bcdsub_eq(a,b,0)
+#define __builtin_bcdcmpgt(a,b)   __builtin_vec_bcdsub_gt(a,b,0)
+#define __builtin_bcdcmplt(a,b)   __builtin_vec_bcdsub_lt(a,b,0)
+#define __builtin_bcdcmpge(a,b)   __builtin_vec_bcdsub_ge(a,b,0)
+#define __builtin_bcdcmple(a,b)   __builtin_vec_bcdsub_le(a,b,0)
+
+
 /* Predicates.
    For C++, we use templates in order to allow non-parenthesized arguments.
    For C, instead, we use macros since non-parenthesized arguments were
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 0a2e634d6b0..6a6ce0f84ed 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -160,6 +160,7 @@
    UNSPEC_BCDADD
    UNSPEC_BCDSUB
    UNSPEC_BCD_OVERFLOW
+   UNSPEC_BCDSHIFT
    UNSPEC_VRLMI
    UNSPEC_VRLNM
    UNSPEC_VCFUGED
@@ -4410,12 +4411,13 @@
 (define_int_attr bcd_add_sub [(UNSPEC_BCDADD "add")
 			      (UNSPEC_BCDSUB "sub")])
 
-(define_code_iterator BCD_TEST [eq lt gt unordered])
+(define_code_iterator BCD_TEST [eq lt le gt ge unordered])
+(define_mode_iterator VBCD [V1TI V16QI])
 
-(define_insn "bcd<bcd_add_sub>"
-  [(set (match_operand:V1TI 0 "gpc_reg_operand" "=v")
-	(unspec:V1TI [(match_operand:V1TI 1 "gpc_reg_operand" "v")
-		      (match_operand:V1TI 2 "gpc_reg_operand" "v")
+(define_insn "bcd<bcd_add_sub>_<mode>"
+  [(set (match_operand:VBCD 0 "register_operand" "=v")
+	(unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
+		      (match_operand:VBCD 2 "register_operand" "v")
 		      (match_operand:QI 3 "const_0_to_1_operand" "n")]
 		     UNSPEC_BCD_ADD_SUB))
    (clobber (reg:CCFP CR6_REGNO))]
@@ -4428,23 +4430,23 @@
 ;; UNORDERED test on an integer type (like V1TImode) is not defined.  The type
 ;; probably should be one that can go in the VMX (Altivec) registers, so we
 ;; can't use DDmode or DFmode.
-(define_insn "*bcd<bcd_add_sub>_test"
+(define_insn "*bcd<bcd_add_sub>_test_<mode>"
   [(set (reg:CCFP CR6_REGNO)
 	(compare:CCFP
-	 (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "v")
-		       (match_operand:V1TI 2 "register_operand" "v")
+	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")
+		       (match_operand:VBCD 2 "register_operand" "v")
 		       (match_operand:QI 3 "const_0_to_1_operand" "i")]
 		      UNSPEC_BCD_ADD_SUB)
 	 (match_operand:V2DF 4 "zero_constant" "j")))
-   (clobber (match_scratch:V1TI 0 "=v"))]
+   (clobber (match_scratch:VBCD 0 "=v"))]
   "TARGET_P8_VECTOR"
   "bcd<bcd_add_sub>. %0,%1,%2,%3"
   [(set_attr "type" "vecsimple")])
 
-(define_insn "*bcd<bcd_add_sub>_test2"
-  [(set (match_operand:V1TI 0 "register_operand" "=v")
-	(unspec:V1TI [(match_operand:V1TI 1 "register_operand" "v")
-		      (match_operand:V1TI 2 "register_operand" "v")
+(define_insn "*bcd<bcd_add_sub>_test2_<mode>"
+  [(set (match_operand:VBCD 0 "register_operand" "=v")
+	(unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
+		      (match_operand:VBCD 2 "register_operand" "v")
 		      (match_operand:QI 3 "const_0_to_1_operand" "i")]
 		     UNSPEC_BCD_ADD_SUB))
    (set (reg:CCFP CR6_REGNO)
@@ -4540,15 +4542,15 @@
 }
    [(set_attr "type" "vecsimple")])
 
-(define_expand "bcd<bcd_add_sub>_<code>"
+(define_expand "bcd<bcd_add_sub>_<code>_<mode>"
   [(parallel [(set (reg:CCFP CR6_REGNO)
 		   (compare:CCFP
-		    (unspec:V2DF [(match_operand:V1TI 1 "register_operand")
-				  (match_operand:V1TI 2 "register_operand")
+		    (unspec:V2DF [(match_operand:VBCD 1 "register_operand")
+				  (match_operand:VBCD 2 "register_operand")
 				  (match_operand:QI 3 "const_0_to_1_operand")]
 				 UNSPEC_BCD_ADD_SUB)
 		    (match_dup 4)))
-	      (clobber (match_scratch:V1TI 5))])
+	      (clobber (match_scratch:VBCD 5))])
    (set (match_operand:SI 0 "register_operand")
 	(BCD_TEST:SI (reg:CCFP CR6_REGNO)
 		     (const_int 0)))]
@@ -4557,6 +4559,74 @@
   operands[4] = CONST0_RTX (V2DFmode);
 })
 
+(define_insn "*bcdinvalid_<mode>"
+  [(set (reg:CCFP CR6_REGNO)
+	(compare:CCFP
+	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")]
+		      UNSPEC_BCDADD)
+	 (match_operand:V2DF 2 "zero_constant" "j")))
+   (clobber (match_scratch:VBCD 0 "=v"))]
+  "TARGET_P8_VECTOR"
+  "bcdadd. %0,%1,%1,0"
+  [(set_attr "type" "vecsimple")])
+
+(define_expand "bcdinvalid_<mode>"
+  [(parallel [(set (reg:CCFP CR6_REGNO)
+		   (compare:CCFP
+		    (unspec:V2DF [(match_operand:VBCD 1 "register_operand")]
+				 UNSPEC_BCDADD)
+		    (match_dup 2)))
+	      (clobber (match_scratch:VBCD 3))])
+   (set (match_operand:SI 0 "register_operand")
+	(unordered:SI (reg:CCFP CR6_REGNO)
+		      (const_int 0)))]
+  "TARGET_P8_VECTOR"
+{
+  operands[2] = CONST0_RTX (V2DFmode);
+})
+
+(define_insn "bcdshift_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand" "=v")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
+		       (match_operand:V16QI 2 "register_operand" "v")
+		       (match_operand:QI 3 "const_0_to_1_operand" "n")]
+		     UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P8_VECTOR"
+  "bcds. %0,%1,%2,%3"
+  [(set_attr "type" "vecsimple")])
+
+(define_expand "bcdmul10_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
+		      UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P9_VECTOR"
+{
+  rtx one = gen_reg_rtx (V16QImode);
+
+  emit_insn (gen_altivec_vspltisb (one, const1_rtx));
+  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
+
+  DONE;
+})
+
+(define_expand "bcddiv10_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
+		      UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P9_VECTOR"
+{
+  rtx one = gen_reg_rtx (V16QImode);
+
+  emit_insn (gen_altivec_vspltisb (one, constm1_rtx));
+  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
+
+  DONE;
+})
+
+
 ;; Peephole2 pattern to combine a bcdadd/bcdsub that calculates the value and
 ;; the bcdadd/bcdsub that tests the value.  The combiner won't work since
 ;; CR6 is a hard coded register.  Unfortunately, all of the Altivec predicate
diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md
index 8f822732bac..9a952300cd6 100644
--- a/gcc/config/rs6000/dfp.md
+++ b/gcc/config/rs6000/dfp.md
@@ -273,6 +273,28 @@
   "denbcd<q> %1,%0,%2"
   [(set_attr "type" "dfp")])
 
+(define_insn "dfp_denbcd_v16qi_inst"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
+	(unspec:TD [(match_operand:QI 1 "const_0_to_1_operand" "i")
+		    (match_operand:V16QI 2 "register_operand" "d")]
+		   UNSPEC_DENBCD))]
+  "TARGET_DFP"
+  "denbcdq %1,%0,%2"
+  [(set_attr "type" "dfp")])
+
+(define_expand "dfp_denbcd_v16qi"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
+	(unspec:TD [(match_operand:V16QI 1 "register_operand" "v")]
+		   UNSPEC_DENBCD))]
+  "TARGET_DFP"
+ {
+   // Move vs128 upper 64-bits and lower 64-bits to fp register pair
+   convert_move (operands[0], operands[1], true);
+   emit_insn (gen_dfp_denbcd_v16qi_inst (operands[0], GEN_INT(1),
+					 operands[0]));
+   DONE;
+ })
+
 (define_insn "dfp_dxex_<mode>"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
 	(unspec:DI [(match_operand:DDTD 1 "gpc_reg_operand" "d")]
diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
index 5b05da87f4b..a58102c3785 100644
--- a/gcc/config/rs6000/rs6000-builtin.def
+++ b/gcc/config/rs6000/rs6000-builtin.def
@@ -696,6 +696,14 @@
 /* Miscellaneous builtins for instructions added in ISA 2.07.  These
    instructions do require the ISA 2.07 vector support, but they aren't vector
    instructions.  */
+#define BU_P8V_MISC_1(ENUM, NAME, ATTR, ICODE)				\
+  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
+		    "__builtin_" NAME,			/* NAME */	\
+		    RS6000_BTM_P8_VECTOR,		/* MASK */	\
+		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
+		     | RS6000_BTC_UNARY),				\
+		    CODE_FOR_ ## ICODE)			/* ICODE */
+
 #define BU_P8V_MISC_3(ENUM, NAME, ATTR, ICODE)				\
   RS6000_BUILTIN_3 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
 		    "__builtin_" NAME,			/* NAME */	\
@@ -2668,16 +2676,55 @@ BU_P7_MISC_1 (CBCDTD,		"cbcdtd",	CONST,	cbcdtd)
 BU_P7_MISC_2 (ADDG6S,		"addg6s",	CONST,	addg6s)
 
 /* 3 argument BCD functions added in ISA 2.07.  */
-BU_P8V_MISC_3 (BCDADD,		"bcdadd",	CONST,	bcdadd)
-BU_P8V_MISC_3 (BCDADD_LT,	"bcdadd_lt",	CONST,	bcdadd_lt)
-BU_P8V_MISC_3 (BCDADD_EQ,	"bcdadd_eq",	CONST,	bcdadd_eq)
-BU_P8V_MISC_3 (BCDADD_GT,	"bcdadd_gt",	CONST,	bcdadd_gt)
-BU_P8V_MISC_3 (BCDADD_OV,	"bcdadd_ov",	CONST,	bcdadd_unordered)
-BU_P8V_MISC_3 (BCDSUB,		"bcdsub",	CONST,	bcdsub)
-BU_P8V_MISC_3 (BCDSUB_LT,	"bcdsub_lt",	CONST,	bcdsub_lt)
-BU_P8V_MISC_3 (BCDSUB_EQ,	"bcdsub_eq",	CONST,	bcdsub_eq)
-BU_P8V_MISC_3 (BCDSUB_GT,	"bcdsub_gt",	CONST,	bcdsub_gt)
-BU_P8V_MISC_3 (BCDSUB_OV,	"bcdsub_ov",	CONST,	bcdsub_unordered)
+BU_P8V_MISC_3 (BCDADD_V1TI,	"bcdadd_v1ti",	CONST,	bcdadd_v1ti)
+BU_P8V_MISC_3 (BCDADD_V16QI,	"bcdadd_v16qi",	CONST,	bcdadd_v16qi)
+BU_P8V_MISC_3 (BCDADD_LT_V1TI,	"bcdadd_lt_v1ti",  CONST, bcdadd_lt_v1ti)
+BU_P8V_MISC_3 (BCDADD_LT_V16QI,	"bcdadd_lt_v16qi", CONST, bcdadd_lt_v16qi)
+BU_P8V_MISC_3 (BCDADD_EQ_V1TI,	"bcdadd_eq_v1ti",  CONST, bcdadd_eq_v1ti)
+BU_P8V_MISC_3 (BCDADD_EQ_V16QI,	"bcdadd_eq_v16qi", CONST, bcdadd_eq_v16qi)
+BU_P8V_MISC_3 (BCDADD_GT_V1TI,	"bcdadd_gt_v1ti",  CONST, bcdadd_gt_v1ti)
+BU_P8V_MISC_3 (BCDADD_GT_V16QI,	"bcdadd_gt_v16qi", CONST, bcdadd_gt_v16qi)
+BU_P8V_MISC_3 (BCDADD_OV_V1TI,	"bcdadd_ov_v1ti",  CONST, bcdadd_unordered_v1ti)
+BU_P8V_MISC_3 (BCDADD_OV_V16QI,	"bcdadd_ov_v16qi", CONST, bcdadd_unordered_v16qi)
+
+BU_P8V_MISC_3 (BCDSUB_V1TI,	"bcdsub_v1ti",	CONST,	bcdsub_v1ti)
+BU_P8V_MISC_3 (BCDSUB_V16QI,	"bcdsub_v16qi",	CONST,	bcdsub_v16qi)
+BU_P8V_MISC_3 (BCDSUB_LT_V1TI,	"bcdsub_lt_v1ti",  CONST, bcdsub_lt_v1ti)
+BU_P8V_MISC_3 (BCDSUB_LT_V16QI,	"bcdsub_lt_v16qi", CONST, bcdsub_lt_v16qi)
+BU_P8V_MISC_3 (BCDSUB_LE_V1TI,	"bcdsub_le_v1ti",  CONST, bcdsub_le_v1ti)
+BU_P8V_MISC_3 (BCDSUB_LE_V16QI,	"bcdsub_le_v16qi", CONST, bcdsub_le_v16qi)
+BU_P8V_MISC_3 (BCDSUB_EQ_V1TI,	"bcdsub_eq_v1ti",  CONST, bcdsub_eq_v1ti)
+BU_P8V_MISC_3 (BCDSUB_EQ_V16QI,	"bcdsub_eq_v16qi", CONST, bcdsub_eq_v16qi)
+BU_P8V_MISC_3 (BCDSUB_GT_V1TI,	"bcdsub_gt_v1ti",  CONST, bcdsub_gt_v1ti)
+BU_P8V_MISC_3 (BCDSUB_GT_V16QI,	"bcdsub_gt_v16qi", CONST, bcdsub_gt_v16qi)
+BU_P8V_MISC_3 (BCDSUB_GE_V1TI,	"bcdsub_ge_v1ti",  CONST, bcdsub_ge_v1ti)
+BU_P8V_MISC_3 (BCDSUB_GE_V16QI,	"bcdsub_ge_v16qi", CONST, bcdsub_ge_v16qi)
+BU_P8V_MISC_3 (BCDSUB_OV_V1TI,	"bcdsub_ov_v1ti",  CONST, bcdsub_unordered_v1ti)
+BU_P8V_MISC_3 (BCDSUB_OV_V16QI,	"bcdsub_ov_v16qi", CONST, bcdsub_unordered_v16qi)
+
+BU_P8V_MISC_1 (BCDINVALID_V1TI,	"bcdinvalid_v1ti",  CONST, bcdinvalid_v1ti)
+BU_P8V_MISC_1 (BCDINVALID_V16QI, "bcdinvalid_v16qi", CONST, bcdinvalid_v16qi)
+
+BU_P9V_AV_1 (BCDMUL10_V16QI, "bcdmul10_v16qi", CONST, bcdmul10_v16qi)
+BU_P9V_AV_1 (BCDDIV10_V16QI, "bcddiv10_v16qi", CONST, bcddiv10_v16qi)
+BU_P8V_MISC_1 (DENBCD_V16QI,	"denb2dfp_v16qi", CONST, dfp_denbcd_v16qi)
+
+BU_P8V_OVERLOAD_3 (BCDADD,	"bcdadd")
+BU_P8V_OVERLOAD_3 (BCDADD_LT,	"bcdadd_lt")
+BU_P8V_OVERLOAD_3 (BCDADD_EQ,	"bcdadd_eq")
+BU_P8V_OVERLOAD_3 (BCDADD_GT,	"bcdadd_gt")
+BU_P8V_OVERLOAD_3 (BCDADD_OV,	"bcdadd_ov")
+BU_P8V_OVERLOAD_3 (BCDSUB,	"bcdsub")
+BU_P8V_OVERLOAD_3 (BCDSUB_LT,	"bcdsub_lt")
+BU_P8V_OVERLOAD_3 (BCDSUB_LE,	"bcdsub_le")
+BU_P8V_OVERLOAD_3 (BCDSUB_EQ,	"bcdsub_eq")
+BU_P8V_OVERLOAD_3 (BCDSUB_GT,	"bcdsub_gt")
+BU_P8V_OVERLOAD_3 (BCDSUB_GE,	"bcdsub_ge")
+BU_P8V_OVERLOAD_3 (BCDSUB_OV,	"bcdsub_ov")
+BU_P8V_OVERLOAD_1 (BCDINVALID,	"bcdinvalid")
+BU_P9V_OVERLOAD_1 (BCDMUL10,	"bcdmul10")
+BU_P9V_OVERLOAD_1 (BCDDIV10,	"bcddiv10")
+BU_P8V_OVERLOAD_1 (DENBCD,	"denb2dfp")
 
 /* 2 argument pack/unpack 128-bit floating point types.  */
 BU_DFP_MISC_2 (PACK_TD,		"pack_dec128",		CONST,	packtd)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index b044778a7ae..92378e958a9 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -985,6 +985,82 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = {
     RS6000_BTI_unsigned_V4SI, RS6000_BTI_V4SF, RS6000_BTI_INTSI, 0 },
   { ALTIVEC_BUILTIN_VEC_CTU, VSX_BUILTIN_XVCVDPUXDS_SCALE,
     RS6000_BTI_unsigned_V2DI, RS6000_BTI_V2DF, RS6000_BTI_INTSI, 0 },
+
+  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V1TI,
+    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, 0, 0 },
+  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P9V_BUILTIN_VEC_BCDMUL10, P9V_BUILTIN_BCDMUL10_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+  { P9V_BUILTIN_VEC_BCDDIV10, P9V_BUILTIN_BCDDIV10_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P8V_BUILTIN_VEC_DENBCD, MISC_BUILTIN_DENBCD_V16QI,
+    RS6000_BTI_dfloat128, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V1TI,
+    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+
+
   { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVSP,
     RS6000_BTI_V4SF, RS6000_BTI_V4SF, RS6000_BTI_V4SF, 0 },
   { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVDP,
@@ -10570,14 +10646,22 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
     }
   else if (icode == CODE_FOR_vsx_set_v2df
            || icode == CODE_FOR_vsx_set_v2di
-	   || icode == CODE_FOR_bcdadd
-	   || icode == CODE_FOR_bcdadd_lt
-	   || icode == CODE_FOR_bcdadd_eq
-	   || icode == CODE_FOR_bcdadd_gt
-	   || icode == CODE_FOR_bcdsub
-	   || icode == CODE_FOR_bcdsub_lt
-	   || icode == CODE_FOR_bcdsub_eq
-	   || icode == CODE_FOR_bcdsub_gt)
+	   || icode == CODE_FOR_bcdadd_v16qi
+	   || icode == CODE_FOR_bcdadd_v1ti
+	   || icode == CODE_FOR_bcdadd_lt_v16qi
+	   || icode == CODE_FOR_bcdadd_lt_v1ti
+	   || icode == CODE_FOR_bcdadd_eq_v16qi
+	   || icode == CODE_FOR_bcdadd_eq_v1ti
+	   || icode == CODE_FOR_bcdadd_gt_v16qi
+	   || icode == CODE_FOR_bcdadd_gt_v1ti
+	   || icode == CODE_FOR_bcdsub_v16qi
+	   || icode == CODE_FOR_bcdsub_v1ti
+	   || icode == CODE_FOR_bcdsub_lt_v16qi
+	   || icode == CODE_FOR_bcdsub_lt_v1ti
+	   || icode == CODE_FOR_bcdsub_eq_v16qi
+	   || icode == CODE_FOR_bcdsub_eq_v1ti
+	   || icode == CODE_FOR_bcdsub_gt_v16qi
+	   || icode == CODE_FOR_bcdsub_gt_v1ti)
     {
       /* Only allow 1-bit unsigned literals.  */
       STRIP_NOPS (arg2);
@@ -10601,7 +10685,8 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
 	}
     }
   else if (icode == CODE_FOR_dfp_denbcd_dd
-	   || icode == CODE_FOR_dfp_denbcd_td)
+	   || icode == CODE_FOR_dfp_denbcd_td
+	   || icode == CODE_FOR_dfp_denbcd_v16qi)
     {
       /* Only allow 1-bit unsigned literals.  */
       STRIP_NOPS (arg0);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 5be1cbecf60..0b701ee506f 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -20161,15 +20161,28 @@ __int128 vec_vsubuqm (__int128, __int128);
 __uint128 vec_vsubuqm (__uint128, __uint128);
 
 vector __int128 __builtin_bcdadd (vector __int128, vector __int128, const int);
+vector unsigned char __builtin_bcdadd (vector unsigned char, vector unsigned char,
+                                       const int);
 int __builtin_bcdadd_lt (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_lt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_eq (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_eq (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_gt (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_gt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_ov (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_ov (vector unsigned char, vector unsigned char, const int);
+
 vector __int128 __builtin_bcdsub (vector __int128, vector __int128, const int);
+vector unsigned char __builtin_bcdsub (vector unsigned char, vector unsigned char,
+                                       const int);
 int __builtin_bcdsub_lt (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_lt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_eq (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_eq (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_gt (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_gt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_ov (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_ov (vector unsigned char, vector unsigned char, const int);
 @end smallexample
 
 @node PowerPC AltiVec Built-in Functions Available on ISA 3.0
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-2.c b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
index 2f51dee257f..95c3699a144 100644
--- a/gcc/testsuite/gcc.target/powerpc/bcd-2.c
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
@@ -14,6 +14,8 @@
 /* { dg-final { scan-assembler-not   "stxvw4x" 	      } } */
 /* { dg-final { scan-assembler-not   "stxvd2x" 	      } } */
 
+#include <altivec.h>
+
 typedef __int128_t __attribute__((__vector_size__(16)))	vector_128_t;
 typedef __int128_t					scalar_128_t;
 typedef	unsigned long long				scalar_64_t;
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-3.c b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
index 1b20841ae1c..7948a0c95e2 100644
--- a/gcc/testsuite/gcc.target/powerpc/bcd-3.c
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
@@ -18,6 +18,8 @@ typedef __int128_t __attribute__((__vector_size__(16)))	vector_128_t;
 typedef __int128_t					scalar_128_t;
 typedef	unsigned long long				scalar_64_t;
 
+#include <altivec.h>
+
 /* Test whether the peephole works to allow folding a bcdadd, with a
    bcdadd_<test> into a single instruction.  */
 
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-4.c b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
new file mode 100644
index 00000000000..5254c68d09e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
@@ -0,0 +1,520 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-require-effective-target power10_hw } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
+/* { dg-final { scan-assembler-times "\mbcdadd\M" 7 } } */
+/* { dg-final { scan-assembler-times "\mbcdsub\M" 18 } } */
+/* { dg-final { scan-assembler-times "\mbcds\M" 2 } } */
+/* { dg-final { scan-assembler-times "\mdenbcdq\M" 1 } } */
+
+#include <altivec.h>
+
+#define DEBUG 0
+
+#if DEBUG
+#include <stdio.h>
+#endif
+
+
+#define BCD_POS0  12    //  0xC
+#define BCD_POS1  15    //  0xF
+#define BCD_NEG   13    //  0xD
+
+void abort (void);
+
+  union conv_t
+    {
+      _Decimal128 d128;
+      vector  unsigned char ch;
+      vector  long long unsigned int vllui;
+    } conv;
+  
+_Decimal128 convert_vec_char (vector unsigned char a)
+{
+  union conv_t conv;
+  _Decimal128 result;
+  
+  conv.ch = a;
+  result = conv.d128;
+  return result;
+}
+			      
+vector unsigned char maxbcd(unsigned int sign)
+{
+  vector unsigned char result;
+  int i;
+
+  for (i = 15; i > 0; i--)
+    result[i] = 0x99;
+
+  result[0] = sign << 4 | 0x9;
+}
+
+vector unsigned char num2bcd(long int a, int encoding)
+{
+  int i;
+  unsigned int hi, low, sign;
+  
+  vector unsigned char result;
+
+  if (a > 0) {
+    if (encoding == 0)
+      sign = BCD_POS0;
+    else
+      sign = BCD_POS1;
+
+  } else {
+    sign = BCD_NEG;
+    a = -a;
+  }
+
+  hi = a % 10;   // 1st digit
+  a = a / 10;
+  result[0] = hi << 4| sign;
+
+  for (i = 1; i < 16; i++)
+    {
+      low = a % 10;
+      a = a / 10;
+      hi = a % 10;
+      a = a / 10;
+      result[i] = hi << 4 | low;
+    }
+
+
+  return result;
+}
+
+int main ()
+{
+  int i;
+  long int value_a, value_b, value_result;
+  vector unsigned char a, b, result, exp_result;
+  _Decimal128 result_d128, exp_result_d128;
+
+  /* Make a and b positive BCD numbers */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_b = 101010;
+  b = num2bcd(value_b, 0);
+ 
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdadd (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not match "
+	     "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS0);
+#else
+      abort();
+#endif
+
+  /* Make a and b positive BCD numbers using alternate positive encoding.  */
+  value_a = 1030507;
+  a = num2bcd(value_a, 1);
+
+  value_b = 204060;
+  b = num2bcd(value_b, 1);
+
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 1);
+  
+  result = __builtin_bcdadd (a, b, 1);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* Result should be positive, alternate encoding.  */
+  if ((result[0] & 0xF) != BCD_POS1)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not "
+	   "match expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+  /* Make a and b negative BCD numbers */
+  value_a = -1030507;
+  a = num2bcd(value_a, 0);
+
+  value_b = -1010101;
+  b = num2bcd(value_b, 0);
+
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdadd (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i]  != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd, neg result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be negative */
+  if ((result[0] & 0xF) != BCD_NEG)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign, neg of result is %d.  Does not "
+	   "match expected_result = %d\n",
+	     result[0] & 0xF, BCD_NEG);
+#else
+    abort();
+#endif
+
+ 
+  /* Make a negative, b positive BCD numbers */
+  value_a = -1030507;
+  a = num2bcd(value_a, 0);
+
+  value_b = 1010101;
+  b = num2bcd(value_b, 0);
+
+  value_result = value_a - value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdsub (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdsub, neg result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive, alt encoding */
+  if ((result[0] & 0xF) != BCD_NEG)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign, of result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_NEG);
+#else
+    abort();
+#endif
+
+  /* Make a and b positive BCD numbers */
+  value_a = 1030507;
+  a = num2bcd(value_a, 1);
+
+  value_b = 1010101;
+  b = num2bcd(value_b, 1);
+
+  value_result = value_a - value_b;
+  exp_result = num2bcd(value_result, 1);
+  
+  result = __builtin_bcdsub (a, b, 1);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcdsub, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS1)
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+      abort();
+#endif
+
+  /* Test overflow add and subtract.  */
+  a = maxbcd(BCD_POS0);
+  b = maxbcd(BCD_POS0);
+
+  if(__builtin_bcdadd_ofl (a, b, 0) == 0)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd did not overflow as expected\n");
+#else
+    abort();
+#endif
+
+  value_a = 99999999;
+  a = num2bcd(value_a, 0);
+
+  value_b = 999999999;
+  b = num2bcd(value_b, 0);
+
+  if(__builtin_bcdadd_ofl (a, b, 0))
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd unexpectedly overflowed\n");
+#else
+    abort();
+#endif
+
+  a = maxbcd(BCD_NEG);
+  b = maxbcd(BCD_NEG);
+
+  if (__builtin_bcdsub_ofl (a, b, 0) == 0)
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub did not overflow as expected\n");
+#else
+    abort();
+#endif
+
+  value_a = -99999999;
+  a = num2bcd(value_a, 0);
+
+  value_b = -999999999;
+  b = num2bcd(value_b, 0);
+
+  if (__builtin_bcdsub_ofl (a, b, 0))
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub unexpectedly overflowed\n");
+#else
+    abort();
+#endif
+
+  /* Test arguments for valid/invalid */
+  if (__builtin_bcdinvalid (a))
+#if DEBUG
+    printf("ERROR: __builtin_invalid input is unexpectedly invalid.\n");
+#else
+    abort();
+#endif
+
+  a[3] = 0xBB;     /* an invalid BCD digit */
+  if (!__builtin_bcdinvalid (a))
+#if DEBUG
+    printf("ERROR: __builtin_invalid input is unexpectedly valid.\n");
+#else
+    abort();
+#endif
+
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_b = 101010;
+  b = num2bcd(value_b, 0);
+
+  /* Test equality */
+  if (__builtin_bcdcmpeq (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmpeq (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+
+  /* Test a greater then b, inputs already setup this way.  */
+  if (!__builtin_bcdcmpgt (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpgt (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpgt (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt input equal, result is unexpectedly "
+	   "1.\n");
+#else
+    abort();
+#endif
+
+
+  if (!__builtin_bcdcmpge (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpge (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmpge (b, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge inputs equal result is unexpectedly "
+	   "0.\n");
+#else
+    abort();
+#endif
+
+  /* Test a less then b.  */
+  value_a = 101010;
+  a = num2bcd(value_a, 0);
+  value_b = 1020304;
+  b = num2bcd(value_b, 0);
+
+  if (!__builtin_bcdcmplt (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmplt (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmplt (b, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt inputs equal result is unexpectedly "
+	   "1.\n");
+#else
+    abort();
+#endif
+
+
+  if (!__builtin_bcdcmple (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmple (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmple (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple inputs equal result is unexpectedly "
+	   "0.\n");
+#else
+    abort();
+#endif
+
+  /* Test multipy 10 */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_result = value_a * 10;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdmul10 (a);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcdmul10, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if 0
+    printf("ERROR: __builtin_bcdmul10 sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	   result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+  /* Test divide 10 */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_result = value_a / 10;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcddiv10 (a);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcddiv10, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if DEBUG
+    printf("ERROR: __builtin_bcddiv10 sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+   value_a = 1020304;
+   exp_result_d128 = 1020304;
+   a = num2bcd(value_a, 0);
+
+   conv.ch = a;
+   conv.d128 = __builtin_bcd2dfp (a);
+   result_d128 = conv.d128;
+   
+   if (result_d128 != exp_result_d128)
+#if DEBUG
+     printf("ERROR: __builtin_bcd2dfp, result does not match expected_result."
+	    "\n");
+#else
+     abort();
+#endif
+}
+
David Edelsohn Oct. 30, 2020, 5:34 p.m. UTC | #5
On Fri, Oct 30, 2020 at 12:36 PM Carl Love <cel@us.ibm.com> wrote:
>
> David:
>
> On Wed, 2020-10-28 at 20:43 -0400, David Edelsohn wrote:
> > Better, but please use
> >
> > /* { dg-require-effective-target int128 } */
> >
> > not "target int128" in the selector.  Segher and I both agree that
> > it's cleaner and more readable.  The selector (the target part on the
> > dg-do line) should not be used for this type of requirement.
>
> OK, redid the test case.  It now reads:
>
> +/* { dg-do compile } */
> +/* { dg-require-effective-target int128 } */
> +/
> * { dg-require-effective-target power10_hw } */
> +/* { dg-options "-
> mdejagnu-cpu=power10 -O2" } */
> +/* { dg-final { scan-assembler-times
> "\mbcdadd\M" 7 } } */
> +/* { dg-final { scan-assembler-times "\mbcdsub\M"
> 18 } } */
> +/* { dg-final { scan-assembler-times "\mbcds\M" 2 } } */
> +/* {
> dg-final { scan-assembler-times "\mdenbcdq\M" 1 } } */
> +
>
> Reran the regresion, no new failures were reported.
>
> Please let me know if that looks OK.  Thanks.

Hi, Carl

The revised dg-require for the testcases look fine to me.

Thanks for implementing this next set of builtins.  The patch looks
good to me, modulo any comments from Segher.

20+ more builtins for Bill's rewrite.  You owe him a beer.

Thanks, David
Segher Boessenkool Oct. 30, 2020, 6:26 p.m. UTC | #6
Hi!

On Fri, Oct 30, 2020 at 09:36:13AM -0700, Carl Love wrote:
> On Wed, 2020-10-28 at 20:43 -0400, David Edelsohn wrote:
> > Better, but please use
> > 
> > /* { dg-require-effective-target int128 } */
> > 
> > not "target int128" in the selector.  Segher and I both agree that
> > it's cleaner and more readable.  The selector (the target part on the
> > dg-do line) should not be used for this type of requirement.

Yes.

> +(define_insn "*bcd<bcd_add_sub>_test_<mode>"
>    [(set (reg:CCFP CR6_REGNO)
>  	(compare:CCFP
> -	 (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "v")
> -		       (match_operand:V1TI 2 "register_operand" "v")
> +	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")
> +		       (match_operand:VBCD 2 "register_operand" "v")
>  		       (match_operand:QI 3 "const_0_to_1_operand" "i")]

This should be "n" instead of "i".  This is existing code of course, but
please do that in the new code at least?  (And changing "i" to "n" in
existing code wherever an assembly-time literal constant is needed is
pre-approved -- "i" allows relocations, "n" does not, essentially.)

> +(define_insn "dfp_denbcd_v16qi_inst"
> +  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
> +	(unspec:TD [(match_operand:QI 1 "const_0_to_1_operand" "i")

(like here)

Because the predicate here only allows actual numbers (const_ints), it
is quite hard to ever make the "i" go wrong, but it isn't impossible in
principle.

Other than that nit, yes this looks good.  So okay for trunk, thanks!


Segher
diff mbox series

Patch

diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
index df10a8c498d..e1884f51bd8 100644
--- a/gcc/config/rs6000/altivec.h
+++ b/gcc/config/rs6000/altivec.h
@@ -497,8 +497,33 @@ 
 
 #define vec_xlx __builtin_vec_vextulx
 #define vec_xrx __builtin_vec_vexturx
+
 #endif
 
+/* BCD builtins, map ABI builtin name to existing builtin name.  */
+#define __builtin_bcdadd     __builtin_vec_bcdadd
+#define __builtin_bcdadd_lt  __builtin_vec_bcdadd_lt
+#define __builtin_bcdadd_eq  __builtin_vec_bcdadd_eq
+#define __builtin_bcdadd_gt  __builtin_vec_bcdadd_gt
+#define __builtin_bcdadd_ofl __builtin_vec_bcdadd_ov
+#define __builtin_bcdadd_ov  __builtin_vec_bcdadd_ov
+#define __builtin_bcdsub     __builtin_vec_bcdsub
+#define __builtin_bcdsub_lt  __builtin_vec_bcdsub_lt
+#define __builtin_bcdsub_eq  __builtin_vec_bcdsub_eq
+#define __builtin_bcdsub_gt  __builtin_vec_bcdsub_gt
+#define __builtin_bcdsub_ofl __builtin_vec_bcdsub_ov
+#define __builtin_bcdsub_ov  __builtin_vec_bcdsub_ov
+#define __builtin_bcdinvalid __builtin_vec_bcdinvalid
+#define __builtin_bcdmul10   __builtin_vec_bcdmul10
+#define __builtin_bcddiv10   __builtin_vec_bcddiv10
+#define __builtin_bcd2dfp    __builtin_vec_denb2dfp
+#define __builtin_bcdcmpeq(a,b)   __builtin_vec_bcdsub_eq(a,b,0)
+#define __builtin_bcdcmpgt(a,b)   __builtin_vec_bcdsub_gt(a,b,0)
+#define __builtin_bcdcmplt(a,b)   __builtin_vec_bcdsub_lt(a,b,0)
+#define __builtin_bcdcmpge(a,b)   __builtin_vec_bcdsub_ge(a,b,0)
+#define __builtin_bcdcmple(a,b)   __builtin_vec_bcdsub_le(a,b,0)
+
+
 /* Predicates.
    For C++, we use templates in order to allow non-parenthesized arguments.
    For C, instead, we use macros since non-parenthesized arguments were
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 0a2e634d6b0..6a6ce0f84ed 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -160,6 +160,7 @@ 
    UNSPEC_BCDADD
    UNSPEC_BCDSUB
    UNSPEC_BCD_OVERFLOW
+   UNSPEC_BCDSHIFT
    UNSPEC_VRLMI
    UNSPEC_VRLNM
    UNSPEC_VCFUGED
@@ -4410,12 +4411,13 @@ 
 (define_int_attr bcd_add_sub [(UNSPEC_BCDADD "add")
 			      (UNSPEC_BCDSUB "sub")])
 
-(define_code_iterator BCD_TEST [eq lt gt unordered])
+(define_code_iterator BCD_TEST [eq lt le gt ge unordered])
+(define_mode_iterator VBCD [V1TI V16QI])
 
-(define_insn "bcd<bcd_add_sub>"
-  [(set (match_operand:V1TI 0 "gpc_reg_operand" "=v")
-	(unspec:V1TI [(match_operand:V1TI 1 "gpc_reg_operand" "v")
-		      (match_operand:V1TI 2 "gpc_reg_operand" "v")
+(define_insn "bcd<bcd_add_sub>_<mode>"
+  [(set (match_operand:VBCD 0 "register_operand" "=v")
+	(unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
+		      (match_operand:VBCD 2 "register_operand" "v")
 		      (match_operand:QI 3 "const_0_to_1_operand" "n")]
 		     UNSPEC_BCD_ADD_SUB))
    (clobber (reg:CCFP CR6_REGNO))]
@@ -4428,23 +4430,23 @@ 
 ;; UNORDERED test on an integer type (like V1TImode) is not defined.  The type
 ;; probably should be one that can go in the VMX (Altivec) registers, so we
 ;; can't use DDmode or DFmode.
-(define_insn "*bcd<bcd_add_sub>_test"
+(define_insn "*bcd<bcd_add_sub>_test_<mode>"
   [(set (reg:CCFP CR6_REGNO)
 	(compare:CCFP
-	 (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "v")
-		       (match_operand:V1TI 2 "register_operand" "v")
+	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")
+		       (match_operand:VBCD 2 "register_operand" "v")
 		       (match_operand:QI 3 "const_0_to_1_operand" "i")]
 		      UNSPEC_BCD_ADD_SUB)
 	 (match_operand:V2DF 4 "zero_constant" "j")))
-   (clobber (match_scratch:V1TI 0 "=v"))]
+   (clobber (match_scratch:VBCD 0 "=v"))]
   "TARGET_P8_VECTOR"
   "bcd<bcd_add_sub>. %0,%1,%2,%3"
   [(set_attr "type" "vecsimple")])
 
-(define_insn "*bcd<bcd_add_sub>_test2"
-  [(set (match_operand:V1TI 0 "register_operand" "=v")
-	(unspec:V1TI [(match_operand:V1TI 1 "register_operand" "v")
-		      (match_operand:V1TI 2 "register_operand" "v")
+(define_insn "*bcd<bcd_add_sub>_test2_<mode>"
+  [(set (match_operand:VBCD 0 "register_operand" "=v")
+	(unspec:VBCD [(match_operand:VBCD 1 "register_operand" "v")
+		      (match_operand:VBCD 2 "register_operand" "v")
 		      (match_operand:QI 3 "const_0_to_1_operand" "i")]
 		     UNSPEC_BCD_ADD_SUB))
    (set (reg:CCFP CR6_REGNO)
@@ -4540,15 +4542,15 @@ 
 }
    [(set_attr "type" "vecsimple")])
 
-(define_expand "bcd<bcd_add_sub>_<code>"
+(define_expand "bcd<bcd_add_sub>_<code>_<mode>"
   [(parallel [(set (reg:CCFP CR6_REGNO)
 		   (compare:CCFP
-		    (unspec:V2DF [(match_operand:V1TI 1 "register_operand")
-				  (match_operand:V1TI 2 "register_operand")
+		    (unspec:V2DF [(match_operand:VBCD 1 "register_operand")
+				  (match_operand:VBCD 2 "register_operand")
 				  (match_operand:QI 3 "const_0_to_1_operand")]
 				 UNSPEC_BCD_ADD_SUB)
 		    (match_dup 4)))
-	      (clobber (match_scratch:V1TI 5))])
+	      (clobber (match_scratch:VBCD 5))])
    (set (match_operand:SI 0 "register_operand")
 	(BCD_TEST:SI (reg:CCFP CR6_REGNO)
 		     (const_int 0)))]
@@ -4557,6 +4559,74 @@ 
   operands[4] = CONST0_RTX (V2DFmode);
 })
 
+(define_insn "*bcdinvalid_<mode>"
+  [(set (reg:CCFP CR6_REGNO)
+	(compare:CCFP
+	 (unspec:V2DF [(match_operand:VBCD 1 "register_operand" "v")]
+		      UNSPEC_BCDADD)
+	 (match_operand:V2DF 2 "zero_constant" "j")))
+   (clobber (match_scratch:VBCD 0 "=v"))]
+  "TARGET_P8_VECTOR"
+  "bcdadd. %0,%1,%1,0"
+  [(set_attr "type" "vecsimple")])
+
+(define_expand "bcdinvalid_<mode>"
+  [(parallel [(set (reg:CCFP CR6_REGNO)
+		   (compare:CCFP
+		    (unspec:V2DF [(match_operand:VBCD 1 "register_operand")]
+				 UNSPEC_BCDADD)
+		    (match_dup 2)))
+	      (clobber (match_scratch:VBCD 3))])
+   (set (match_operand:SI 0 "register_operand")
+	(unordered:SI (reg:CCFP CR6_REGNO)
+		      (const_int 0)))]
+  "TARGET_P8_VECTOR"
+{
+  operands[2] = CONST0_RTX (V2DFmode);
+})
+
+(define_insn "bcdshift_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand" "=v")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
+		       (match_operand:V16QI 2 "register_operand" "v")
+		       (match_operand:QI 3 "const_0_to_1_operand" "n")]
+		     UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P8_VECTOR"
+  "bcds. %0,%1,%2,%3"
+  [(set_attr "type" "vecsimple")])
+
+(define_expand "bcdmul10_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
+		      UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P9_VECTOR"
+{
+  rtx one = gen_reg_rtx (V16QImode);
+
+  emit_insn (gen_altivec_vspltisb (one, const1_rtx));
+  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
+
+  DONE;
+})
+
+(define_expand "bcddiv10_v16qi"
+  [(set (match_operand:V16QI 0 "register_operand")
+	(unspec:V16QI [(match_operand:V16QI 1 "register_operand")]
+		      UNSPEC_BCDSHIFT))
+   (clobber (reg:CCFP CR6_REGNO))]
+  "TARGET_P9_VECTOR"
+{
+  rtx one = gen_reg_rtx (V16QImode);
+
+  emit_insn (gen_altivec_vspltisb (one, constm1_rtx));
+  emit_insn (gen_bcdshift_v16qi (operands[0], one, operands[1], const0_rtx));
+
+  DONE;
+})
+
+
 ;; Peephole2 pattern to combine a bcdadd/bcdsub that calculates the value and
 ;; the bcdadd/bcdsub that tests the value.  The combiner won't work since
 ;; CR6 is a hard coded register.  Unfortunately, all of the Altivec predicate
diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md
index 8f822732bac..9a952300cd6 100644
--- a/gcc/config/rs6000/dfp.md
+++ b/gcc/config/rs6000/dfp.md
@@ -273,6 +273,28 @@ 
   "denbcd<q> %1,%0,%2"
   [(set_attr "type" "dfp")])
 
+(define_insn "dfp_denbcd_v16qi_inst"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
+	(unspec:TD [(match_operand:QI 1 "const_0_to_1_operand" "i")
+		    (match_operand:V16QI 2 "register_operand" "d")]
+		   UNSPEC_DENBCD))]
+  "TARGET_DFP"
+  "denbcdq %1,%0,%2"
+  [(set_attr "type" "dfp")])
+
+(define_expand "dfp_denbcd_v16qi"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
+	(unspec:TD [(match_operand:V16QI 1 "register_operand" "v")]
+		   UNSPEC_DENBCD))]
+  "TARGET_DFP"
+ {
+   // Move vs128 upper 64-bits and lower 64-bits to fp register pair
+   convert_move (operands[0], operands[1], true);
+   emit_insn (gen_dfp_denbcd_v16qi_inst (operands[0], GEN_INT(1),
+					 operands[0]));
+   DONE;
+ })
+
 (define_insn "dfp_dxex_<mode>"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
 	(unspec:DI [(match_operand:DDTD 1 "gpc_reg_operand" "d")]
diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
index 5b05da87f4b..a58102c3785 100644
--- a/gcc/config/rs6000/rs6000-builtin.def
+++ b/gcc/config/rs6000/rs6000-builtin.def
@@ -696,6 +696,14 @@ 
 /* Miscellaneous builtins for instructions added in ISA 2.07.  These
    instructions do require the ISA 2.07 vector support, but they aren't vector
    instructions.  */
+#define BU_P8V_MISC_1(ENUM, NAME, ATTR, ICODE)				\
+  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
+		    "__builtin_" NAME,			/* NAME */	\
+		    RS6000_BTM_P8_VECTOR,		/* MASK */	\
+		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
+		     | RS6000_BTC_UNARY),				\
+		    CODE_FOR_ ## ICODE)			/* ICODE */
+
 #define BU_P8V_MISC_3(ENUM, NAME, ATTR, ICODE)				\
   RS6000_BUILTIN_3 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
 		    "__builtin_" NAME,			/* NAME */	\
@@ -2668,16 +2676,55 @@  BU_P7_MISC_1 (CBCDTD,		"cbcdtd",	CONST,	cbcdtd)
 BU_P7_MISC_2 (ADDG6S,		"addg6s",	CONST,	addg6s)
 
 /* 3 argument BCD functions added in ISA 2.07.  */
-BU_P8V_MISC_3 (BCDADD,		"bcdadd",	CONST,	bcdadd)
-BU_P8V_MISC_3 (BCDADD_LT,	"bcdadd_lt",	CONST,	bcdadd_lt)
-BU_P8V_MISC_3 (BCDADD_EQ,	"bcdadd_eq",	CONST,	bcdadd_eq)
-BU_P8V_MISC_3 (BCDADD_GT,	"bcdadd_gt",	CONST,	bcdadd_gt)
-BU_P8V_MISC_3 (BCDADD_OV,	"bcdadd_ov",	CONST,	bcdadd_unordered)
-BU_P8V_MISC_3 (BCDSUB,		"bcdsub",	CONST,	bcdsub)
-BU_P8V_MISC_3 (BCDSUB_LT,	"bcdsub_lt",	CONST,	bcdsub_lt)
-BU_P8V_MISC_3 (BCDSUB_EQ,	"bcdsub_eq",	CONST,	bcdsub_eq)
-BU_P8V_MISC_3 (BCDSUB_GT,	"bcdsub_gt",	CONST,	bcdsub_gt)
-BU_P8V_MISC_3 (BCDSUB_OV,	"bcdsub_ov",	CONST,	bcdsub_unordered)
+BU_P8V_MISC_3 (BCDADD_V1TI,	"bcdadd_v1ti",	CONST,	bcdadd_v1ti)
+BU_P8V_MISC_3 (BCDADD_V16QI,	"bcdadd_v16qi",	CONST,	bcdadd_v16qi)
+BU_P8V_MISC_3 (BCDADD_LT_V1TI,	"bcdadd_lt_v1ti",  CONST, bcdadd_lt_v1ti)
+BU_P8V_MISC_3 (BCDADD_LT_V16QI,	"bcdadd_lt_v16qi", CONST, bcdadd_lt_v16qi)
+BU_P8V_MISC_3 (BCDADD_EQ_V1TI,	"bcdadd_eq_v1ti",  CONST, bcdadd_eq_v1ti)
+BU_P8V_MISC_3 (BCDADD_EQ_V16QI,	"bcdadd_eq_v16qi", CONST, bcdadd_eq_v16qi)
+BU_P8V_MISC_3 (BCDADD_GT_V1TI,	"bcdadd_gt_v1ti",  CONST, bcdadd_gt_v1ti)
+BU_P8V_MISC_3 (BCDADD_GT_V16QI,	"bcdadd_gt_v16qi", CONST, bcdadd_gt_v16qi)
+BU_P8V_MISC_3 (BCDADD_OV_V1TI,	"bcdadd_ov_v1ti",  CONST, bcdadd_unordered_v1ti)
+BU_P8V_MISC_3 (BCDADD_OV_V16QI,	"bcdadd_ov_v16qi", CONST, bcdadd_unordered_v16qi)
+
+BU_P8V_MISC_3 (BCDSUB_V1TI,	"bcdsub_v1ti",	CONST,	bcdsub_v1ti)
+BU_P8V_MISC_3 (BCDSUB_V16QI,	"bcdsub_v16qi",	CONST,	bcdsub_v16qi)
+BU_P8V_MISC_3 (BCDSUB_LT_V1TI,	"bcdsub_lt_v1ti",  CONST, bcdsub_lt_v1ti)
+BU_P8V_MISC_3 (BCDSUB_LT_V16QI,	"bcdsub_lt_v16qi", CONST, bcdsub_lt_v16qi)
+BU_P8V_MISC_3 (BCDSUB_LE_V1TI,	"bcdsub_le_v1ti",  CONST, bcdsub_le_v1ti)
+BU_P8V_MISC_3 (BCDSUB_LE_V16QI,	"bcdsub_le_v16qi", CONST, bcdsub_le_v16qi)
+BU_P8V_MISC_3 (BCDSUB_EQ_V1TI,	"bcdsub_eq_v1ti",  CONST, bcdsub_eq_v1ti)
+BU_P8V_MISC_3 (BCDSUB_EQ_V16QI,	"bcdsub_eq_v16qi", CONST, bcdsub_eq_v16qi)
+BU_P8V_MISC_3 (BCDSUB_GT_V1TI,	"bcdsub_gt_v1ti",  CONST, bcdsub_gt_v1ti)
+BU_P8V_MISC_3 (BCDSUB_GT_V16QI,	"bcdsub_gt_v16qi", CONST, bcdsub_gt_v16qi)
+BU_P8V_MISC_3 (BCDSUB_GE_V1TI,	"bcdsub_ge_v1ti",  CONST, bcdsub_ge_v1ti)
+BU_P8V_MISC_3 (BCDSUB_GE_V16QI,	"bcdsub_ge_v16qi", CONST, bcdsub_ge_v16qi)
+BU_P8V_MISC_3 (BCDSUB_OV_V1TI,	"bcdsub_ov_v1ti",  CONST, bcdsub_unordered_v1ti)
+BU_P8V_MISC_3 (BCDSUB_OV_V16QI,	"bcdsub_ov_v16qi", CONST, bcdsub_unordered_v16qi)
+
+BU_P8V_MISC_1 (BCDINVALID_V1TI,	"bcdinvalid_v1ti",  CONST, bcdinvalid_v1ti)
+BU_P8V_MISC_1 (BCDINVALID_V16QI, "bcdinvalid_v16qi", CONST, bcdinvalid_v16qi)
+
+BU_P9V_AV_1 (BCDMUL10_V16QI, "bcdmul10_v16qi", CONST, bcdmul10_v16qi)
+BU_P9V_AV_1 (BCDDIV10_V16QI, "bcddiv10_v16qi", CONST, bcddiv10_v16qi)
+BU_P8V_MISC_1 (DENBCD_V16QI,	"denb2dfp_v16qi", CONST, dfp_denbcd_v16qi)
+
+BU_P8V_OVERLOAD_3 (BCDADD,	"bcdadd")
+BU_P8V_OVERLOAD_3 (BCDADD_LT,	"bcdadd_lt")
+BU_P8V_OVERLOAD_3 (BCDADD_EQ,	"bcdadd_eq")
+BU_P8V_OVERLOAD_3 (BCDADD_GT,	"bcdadd_gt")
+BU_P8V_OVERLOAD_3 (BCDADD_OV,	"bcdadd_ov")
+BU_P8V_OVERLOAD_3 (BCDSUB,	"bcdsub")
+BU_P8V_OVERLOAD_3 (BCDSUB_LT,	"bcdsub_lt")
+BU_P8V_OVERLOAD_3 (BCDSUB_LE,	"bcdsub_le")
+BU_P8V_OVERLOAD_3 (BCDSUB_EQ,	"bcdsub_eq")
+BU_P8V_OVERLOAD_3 (BCDSUB_GT,	"bcdsub_gt")
+BU_P8V_OVERLOAD_3 (BCDSUB_GE,	"bcdsub_ge")
+BU_P8V_OVERLOAD_3 (BCDSUB_OV,	"bcdsub_ov")
+BU_P8V_OVERLOAD_1 (BCDINVALID,	"bcdinvalid")
+BU_P9V_OVERLOAD_1 (BCDMUL10,	"bcdmul10")
+BU_P9V_OVERLOAD_1 (BCDDIV10,	"bcddiv10")
+BU_P8V_OVERLOAD_1 (DENBCD,	"denb2dfp")
 
 /* 2 argument pack/unpack 128-bit floating point types.  */
 BU_DFP_MISC_2 (PACK_TD,		"pack_dec128",		CONST,	packtd)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index b044778a7ae..92378e958a9 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -985,6 +985,82 @@  const struct altivec_builtin_types altivec_overloaded_builtins[] = {
     RS6000_BTI_unsigned_V4SI, RS6000_BTI_V4SF, RS6000_BTI_INTSI, 0 },
   { ALTIVEC_BUILTIN_VEC_CTU, VSX_BUILTIN_XVCVDPUXDS_SCALE,
     RS6000_BTI_unsigned_V2DI, RS6000_BTI_V2DF, RS6000_BTI_INTSI, 0 },
+
+  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V1TI,
+    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD, MISC_BUILTIN_BCDADD_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_LT, MISC_BUILTIN_BCDADD_LT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_EQ, MISC_BUILTIN_BCDADD_EQ_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_GT, MISC_BUILTIN_BCDADD_GT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDADD_OV, MISC_BUILTIN_BCDADD_OV_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, 0, 0 },
+  { P8V_BUILTIN_VEC_BCDINVALID, MISC_BUILTIN_BCDINVALID_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P9V_BUILTIN_VEC_BCDMUL10, P9V_BUILTIN_BCDMUL10_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+  { P9V_BUILTIN_VEC_BCDDIV10, P9V_BUILTIN_BCDDIV10_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P8V_BUILTIN_VEC_DENBCD, MISC_BUILTIN_DENBCD_V16QI,
+    RS6000_BTI_dfloat128, RS6000_BTI_unsigned_V16QI, 0, 0 },
+
+  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V1TI,
+    RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB, MISC_BUILTIN_BCDSUB_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LT, MISC_BUILTIN_BCDSUB_LT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_LE, MISC_BUILTIN_BCDSUB_LE_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_EQ, MISC_BUILTIN_BCDSUB_EQ_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GT, MISC_BUILTIN_BCDSUB_GT_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI,  RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_GE, MISC_BUILTIN_BCDSUB_GE_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V1TI,
+    RS6000_BTI_INTSI, RS6000_BTI_V1TI, RS6000_BTI_V1TI, RS6000_BTI_INTSI },
+  { P8V_BUILTIN_VEC_BCDSUB_OV, MISC_BUILTIN_BCDSUB_OV_V16QI,
+    RS6000_BTI_INTSI, RS6000_BTI_unsigned_V16QI,
+    RS6000_BTI_unsigned_V16QI, RS6000_BTI_INTSI },
+
+
   { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVSP,
     RS6000_BTI_V4SF, RS6000_BTI_V4SF, RS6000_BTI_V4SF, 0 },
   { VSX_BUILTIN_VEC_DIV, VSX_BUILTIN_XVDIVDP,
@@ -10570,14 +10646,22 @@  rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
     }
   else if (icode == CODE_FOR_vsx_set_v2df
            || icode == CODE_FOR_vsx_set_v2di
-	   || icode == CODE_FOR_bcdadd
-	   || icode == CODE_FOR_bcdadd_lt
-	   || icode == CODE_FOR_bcdadd_eq
-	   || icode == CODE_FOR_bcdadd_gt
-	   || icode == CODE_FOR_bcdsub
-	   || icode == CODE_FOR_bcdsub_lt
-	   || icode == CODE_FOR_bcdsub_eq
-	   || icode == CODE_FOR_bcdsub_gt)
+	   || icode == CODE_FOR_bcdadd_v16qi
+	   || icode == CODE_FOR_bcdadd_v1ti
+	   || icode == CODE_FOR_bcdadd_lt_v16qi
+	   || icode == CODE_FOR_bcdadd_lt_v1ti
+	   || icode == CODE_FOR_bcdadd_eq_v16qi
+	   || icode == CODE_FOR_bcdadd_eq_v1ti
+	   || icode == CODE_FOR_bcdadd_gt_v16qi0001-Add-bcd-builtings-listed-in-appendix-B-of-the-ABI.patch
+	   || icode == CODE_FOR_bcdadd_gt_v1ti
+	   || icode == CODE_FOR_bcdsub_v16qi
+	   || icode == CODE_FOR_bcdsub_v1ti
+	   || icode == CODE_FOR_bcdsub_lt_v16qi
+	   || icode == CODE_FOR_bcdsub_lt_v1ti
+	   || icode == CODE_FOR_bcdsub_eq_v16qi
+	   || icode == CODE_FOR_bcdsub_eq_v1ti
+	   || icode == CODE_FOR_bcdsub_gt_v16qi
+	   || icode == CODE_FOR_bcdsub_gt_v1ti)
     {
       /* Only allow 1-bit unsigned literals.  */
       STRIP_NOPS (arg2);
@@ -10601,7 +10685,8 @@  rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
 	}
     }
   else if (icode == CODE_FOR_dfp_denbcd_dd
-	   || icode == CODE_FOR_dfp_denbcd_td)
+	   || icode == CODE_FOR_dfp_denbcd_td
+	   || icode == CODE_FOR_dfp_denbcd_v16qi)
     {
       /* Only allow 1-bit unsigned literals.  */
       STRIP_NOPS (arg0);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 5be1cbecf60..0b701ee506f 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -20161,15 +20161,28 @@  __int128 vec_vsubuqm (__int128, __int128);
 __uint128 vec_vsubuqm (__uint128, __uint128);
 
 vector __int128 __builtin_bcdadd (vector __int128, vector __int128, const int);
+vector unsigned char __builtin_bcdadd (vector unsigned char, vector unsigned char,
+                                       const int);
 int __builtin_bcdadd_lt (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_lt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_eq (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_eq (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_gt (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_gt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdadd_ov (vector __int128, vector __int128, const int);
+int __builtin_bcdadd_ov (vector unsigned char, vector unsigned char, const int);
+
 vector __int128 __builtin_bcdsub (vector __int128, vector __int128, const int);
+vector unsigned char __builtin_bcdsub (vector unsigned char, vector unsigned char,
+                                       const int);
 int __builtin_bcdsub_lt (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_lt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_eq (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_eq (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_gt (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_gt (vector unsigned char, vector unsigned char, const int);
 int __builtin_bcdsub_ov (vector __int128, vector __int128, const int);
+int __builtin_bcdsub_ov (vector unsigned char, vector unsigned char, const int);
 @end smallexample
 
 @node PowerPC AltiVec Built-in Functions Available on ISA 3.0
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-2.c b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
index 2f51dee257f..95c3699a144 100644
--- a/gcc/testsuite/gcc.target/powerpc/bcd-2.c
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-2.c
@@ -14,6 +14,8 @@ 
 /* { dg-final { scan-assembler-not   "stxvw4x" 	      } } */
 /* { dg-final { scan-assembler-not   "stxvd2x" 	      } } */
 
+#include <altivec.h>
+
 typedef __int128_t __attribute__((__vector_size__(16)))	vector_128_t;
 typedef __int128_t					scalar_128_t;
 typedef	unsigned long long				scalar_64_t;
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-3.c b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
index 1b20841ae1c..7948a0c95e2 100644
--- a/gcc/testsuite/gcc.target/powerpc/bcd-3.c
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-3.c
@@ -18,6 +18,8 @@  typedef __int128_t __attribute__((__vector_size__(16)))	vector_128_t;
 typedef __int128_t					scalar_128_t;
 typedef	unsigned long long				scalar_64_t;
 
+#include <altivec.h>
+
 /* Test whether the peephole works to allow folding a bcdadd, with a
    bcdadd_<test> into a single instruction.  */
 
diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-4.c b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
new file mode 100644
index 00000000000..708ad7b6b3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/bcd-4.c
@@ -0,0 +1,519 @@ 
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target power10_hw } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
+/* { dg-final { scan-assembler-times "\mbcdadd\M" 7 } } */
+/* { dg-final { scan-assembler-times "\mbcdsub\M" 18 } } */
+/* { dg-final { scan-assembler-times "\mbcds\M" 2 } } */
+/* { dg-final { scan-assembler-times "\mdenbcdq\M" 1 } } */
+
+#include <altivec.h>
+
+#define DEBUG 0
+
+#if DEBUG
+#include <stdio.h>
+#endif
+
+
+#define BCD_POS0  12    //  0xC
+#define BCD_POS1  15    //  0xF
+#define BCD_NEG   13    //  0xD
+
+void abort (void);
+
+  union conv_t
+    {
+      _Decimal128 d128;
+      vector  unsigned char ch;
+      vector  long long unsigned int vllui;
+    } conv;
+  
+_Decimal128 convert_vec_char (vector unsigned char a)
+{
+  union conv_t conv;
+  _Decimal128 result;
+  
+  conv.ch = a;
+  result = conv.d128;
+  return result;
+}
+			      
+vector unsigned char maxbcd(unsigned int sign)
+{
+  vector unsigned char result;
+  int i;
+
+  for (i = 15; i > 0; i--)
+    result[i] = 0x99;
+
+  result[0] = sign << 4 | 0x9;
+}
+
+vector unsigned char num2bcd(long int a, int encoding)
+{
+  int i;
+  unsigned int hi, low, sign;
+  
+  vector unsigned char result;
+
+  if (a > 0) {
+    if (encoding == 0)
+      sign = BCD_POS0;
+    else
+      sign = BCD_POS1;
+
+  } else {
+    sign = BCD_NEG;
+    a = -a;
+  }
+
+  hi = a % 10;   // 1st digit
+  a = a / 10;
+  result[0] = hi << 4| sign;
+
+  for (i = 1; i < 16; i++)
+    {
+      low = a % 10;
+      a = a / 10;
+      hi = a % 10;
+      a = a / 10;
+      result[i] = hi << 4 | low;
+    }
+
+
+  return result;
+}
+
+int main ()
+{
+  int i;
+  long int value_a, value_b, value_result;
+  vector unsigned char a, b, result, exp_result;
+  _Decimal128 result_d128, exp_result_d128;
+
+  /* Make a and b positive BCD numbers */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_b = 101010;
+  b = num2bcd(value_b, 0);
+ 
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdadd (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not match "
+	     "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS0);
+#else
+      abort();
+#endif
+
+  /* Make a and b positive BCD numbers using alternate positive encoding.  */
+  value_a = 1030507;
+  a = num2bcd(value_a, 1);
+
+  value_b = 204060;
+  b = num2bcd(value_b, 1);
+
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 1);
+  
+  result = __builtin_bcdadd (a, b, 1);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* Result should be positive, alternate encoding.  */
+  if ((result[0] & 0xF) != BCD_POS1)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign of result is %d.  Does not "
+	   "match expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+  /* Make a and b negative BCD numbers */
+  value_a = -1030507;
+  a = num2bcd(value_a, 0);
+
+  value_b = -1010101;
+  b = num2bcd(value_b, 0);
+
+  value_result = value_a + value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdadd (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i]  != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdadd, neg result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be negative */
+  if ((result[0] & 0xF) != BCD_NEG)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign, neg of result is %d.  Does not "
+	   "match expected_result = %d\n",
+	     result[0] & 0xF, BCD_NEG);
+#else
+    abort();
+#endif
+
+ 
+  /* Make a negative, b positive BCD numbers */
+  value_a = -1030507;
+  a = num2bcd(value_a, 0);
+
+  value_b = 1010101;
+  b = num2bcd(value_b, 0);
+
+  value_result = value_a - value_b;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdsub (a, b, 0);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR: __builtin_bcdsub, neg result[%d] = %d does not match "
+	     "expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive, alt encoding */
+  if ((result[0] & 0xF) != BCD_NEG)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd sign, of result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_NEG);
+#else
+    abort();
+#endif
+
+  /* Make a and b positive BCD numbers */
+  value_a = 1030507;
+  a = num2bcd(value_a, 1);
+
+  value_b = 1010101;
+  b = num2bcd(value_b, 1);
+
+  value_result = value_a - value_b;
+  exp_result = num2bcd(value_result, 1);
+  
+  result = __builtin_bcdsub (a, b, 1);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcdsub, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS1)
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+      abort();
+#endif
+
+  /* Test overflow add and subtract.  */
+  a = maxbcd(BCD_POS0);
+  b = maxbcd(BCD_POS0);
+
+  if(__builtin_bcdadd_ofl (a, b, 0) == 0)
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd did not overflow as expected\n");
+#else
+    abort();
+#endif
+
+  value_a = 99999999;
+  a = num2bcd(value_a, 0);
+
+  value_b = 999999999;
+  b = num2bcd(value_b, 0);
+
+  if(__builtin_bcdadd_ofl (a, b, 0))
+#if DEBUG
+    printf("ERROR: __builtin_bcdadd unexpectedly overflowed\n");
+#else
+    abort();
+#endif
+
+  a = maxbcd(BCD_NEG);
+  b = maxbcd(BCD_NEG);
+
+  if (__builtin_bcdsub_ofl (a, b, 0) == 0)
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub did not overflow as expected\n");
+#else
+    abort();
+#endif
+
+  value_a = -99999999;
+  a = num2bcd(value_a, 0);
+
+  value_b = -999999999;
+  b = num2bcd(value_b, 0);
+
+  if (__builtin_bcdsub_ofl (a, b, 0))
+#if DEBUG
+    printf("ERROR: __builtin_bcdsub unexpectedly overflowed\n");
+#else
+    abort();
+#endif
+
+  /* Test arguments for valid/invalid */
+  if (__builtin_bcdinvalid (a))
+#if DEBUG
+    printf("ERROR: __builtin_invalid input is unexpectedly invalid.\n");
+#else
+    abort();
+#endif
+
+  a[3] = 0xBB;     /* an invalid BCD digit */
+  if (!__builtin_bcdinvalid (a))
+#if DEBUG
+    printf("ERROR: __builtin_invalid input is unexpectedly valid.\n");
+#else
+    abort();
+#endif
+
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_b = 101010;
+  b = num2bcd(value_b, 0);
+
+  /* Test equality */
+  if (__builtin_bcdcmpeq (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmpeq (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpeq result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+
+  /* Test a greater then b, inputs already setup this way.  */
+  if (!__builtin_bcdcmpgt (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpgt (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpgt (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpgt input equal, result is unexpectedly "
+	   "1.\n");
+#else
+    abort();
+#endif
+
+
+  if (!__builtin_bcdcmpge (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmpge (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmpge (b, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmpge inputs equal result is unexpectedly "
+	   "0.\n");
+#else
+    abort();
+#endif
+
+  /* Test a less then b.  */
+  value_a = 101010;
+  a = num2bcd(value_a, 0);
+  value_b = 1020304;
+  b = num2bcd(value_b, 0);
+
+  if (!__builtin_bcdcmplt (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmplt (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmplt (b, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmplt inputs equal result is unexpectedly "
+	   "1.\n");
+#else
+    abort();
+#endif
+
+
+  if (!__builtin_bcdcmple (a, b))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple result is unexpectedly 0.\n");
+#else
+    abort();
+#endif
+
+  if (__builtin_bcdcmple (b, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple result is unexpectedly 1.\n");
+#else
+    abort();
+#endif
+
+  if (!__builtin_bcdcmple (a, a))
+#if DEBUG
+    printf("ERROR: __builtin__bcdcmple inputs equal result is unexpectedly "
+	   "0.\n");
+#else
+    abort();
+#endif
+
+  /* Test multipy 10 */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_result = value_a * 10;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcdmul10 (a);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcdmul10, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if 0
+    printf("ERROR: __builtin_bcdmul10 sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	   result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+  /* Test divide 10 */
+  value_a = 1020304;
+  a = num2bcd(value_a, 0);
+
+  value_result = value_a / 10;
+  exp_result = num2bcd(value_result, 0);
+  
+  result = __builtin_bcddiv10 (a);
+
+  for (i = 0; i < 16; i++)
+    if (exp_result[i] != result[i]) {
+#if DEBUG
+      printf("ERROR:carll __builtin_bcddiv10, pos result[%d] = %d does not "
+	     "match expected_result[%d] = %d\n",
+	     i, result[i], i, exp_result[i]);
+#else
+      abort();
+#endif
+    }
+
+  /* result should be positive */
+  if ((result[0] & 0xF) != BCD_POS0)
+#if DEBUG
+    printf("ERROR: __builtin_bcddiv10 sign, result is %d.  Does not match "
+	   "expected_result = %d\n",
+	     result[0] & 0xF, BCD_POS1);
+#else
+    abort();
+#endif
+
+   value_a = 1020304;
+   exp_result_d128 = 1020304;
+   a = num2bcd(value_a, 0);
+
+   conv.ch = a;
+   conv.d128 = __builtin_bcd2dfp (a);
+   result_d128 = conv.d128;
+   
+   if (result_d128 != exp_result_d128)
+#if DEBUG
+     printf("ERROR: __builtin_bcd2dfp, result does not match expected_result."
+	    "\n");
+#else
+     abort();
+#endif
+}
+