From: Pat Haugen Date: Thu, 17 Apr 2014 18:26:47 +0000 (+0000) Subject: rs6000.md (addti3, subti3): New. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=32337f1014e18221050f034723d3b75f2b08c908;p=gcc.git rs6000.md (addti3, subti3): New. * config/rs6000/rs6000.md (addti3, subti3): New. * gcc.target/powerpc/ti_math1.c: New. * gcc.target/powerpc/ti_math2.c: New. From-SVN: r209489 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 24305918c9f..11df5164e0a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2014-04-17 Pat Haugen + + * config/rs6000/rs6000.md (addti3, subti3): New. + 2014-04-17 H.J. Lu PR target/60863 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 64c9e7c1006..4daaeb01639 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -6534,6 +6534,49 @@ [(set_attr "length" "8") (set_attr "type" "fpload")]) +;; Define the TImode operations that can be done in a small number +;; of instructions. The & constraints are to prevent the register +;; allocator from allocating registers that overlap with the inputs +;; (for example, having an input in 7,8 and an output in 6,7). We +;; also allow for the output being the same as one of the inputs. + +(define_insn "addti3" + [(set (match_operand:TI 0 "gpc_reg_operand" "=&r,&r,r,r") + (plus:TI (match_operand:TI 1 "gpc_reg_operand" "%r,r,0,0") + (match_operand:TI 2 "reg_or_short_operand" "r,I,r,I")))] + "TARGET_64BIT" +{ + if (WORDS_BIG_ENDIAN) + return (GET_CODE (operands[2])) != CONST_INT + ? \"addc %L0,%L1,%L2\;adde %0,%1,%2\" + : \"addic %L0,%L1,%2\;add%G2e %0,%1\"; + else + return (GET_CODE (operands[2])) != CONST_INT + ? \"addc %0,%1,%2\;adde %L0,%L1,%L2\" + : \"addic %0,%1,%2\;add%G2e %L0,%L1\"; +} + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "subti3" + [(set (match_operand:TI 0 "gpc_reg_operand" "=&r,&r,r,r,r") + (minus:TI (match_operand:TI 1 "reg_or_short_operand" "r,I,0,r,I") + (match_operand:TI 2 "gpc_reg_operand" "r,r,r,0,0")))] + "TARGET_64BIT" +{ + if (WORDS_BIG_ENDIAN) + return (GET_CODE (operands[1]) != CONST_INT) + ? \"subfc %L0,%L2,%L1\;subfe %0,%2,%1\" + : \"subfic %L0,%L2,%1\;subf%G1e %0,%2\"; + else + return (GET_CODE (operands[1]) != CONST_INT) + ? \"subfc %0,%2,%1\;subfe %L0,%L2,%L1\" + : \"subfic %0,%2,%1\;subf%G1e %L0,%L2\"; +} + [(set_attr "type" "two") + (set_attr "length" "8")]) + + ;; Define the DImode operations that can be done in a small number ;; of instructions. The & constraints are to prevent the register ;; allocator from allocating registers that overlap with the inputs diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index eb1ac11b5f1..fe8f81e8165 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-04-17 Pat Haugen + + * gcc.target/powerpc/ti_math1.c: New. + * gcc.target/powerpc/ti_math2.c: New. + 2014-04-17 Martin Jambor * gnat.dg/opt34.adb: New. diff --git a/gcc/testsuite/gcc.target/powerpc/ti_math1.c b/gcc/testsuite/gcc.target/powerpc/ti_math1.c new file mode 100644 index 00000000000..cdf92510048 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/ti_math1.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "addc" 1 } } */ +/* { dg-final { scan-assembler-times "adde" 1 } } */ +/* { dg-final { scan-assembler-times "subfc" 1 } } */ +/* { dg-final { scan-assembler-times "subfe" 1 } } */ +/* { dg-final { scan-assembler-not "subf " } } */ + +__int128 +add_128 (__int128 *ptr, __int128 val) +{ + return (*ptr + val); +} + +__int128 +sub_128 (__int128 *ptr, __int128 val) +{ + return (*ptr - val); +} + diff --git a/gcc/testsuite/gcc.target/powerpc/ti_math2.c b/gcc/testsuite/gcc.target/powerpc/ti_math2.c new file mode 100644 index 00000000000..b9c03300d84 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/ti_math2.c @@ -0,0 +1,73 @@ +/* { dg-do run { target { powerpc*-*-* && lp64 } } } */ +/* { dg-options "-O2 -fno-inline" } */ + +union U { + __int128 i128; + struct { + long l1; + long l2; + } s; +}; + +union U u1,u2; + +__int128 +create_128 (long most_sig, long least_sig) +{ + union U u; + +#if __LITTLE_ENDIAN__ + u.s.l1 = least_sig; + u.s.l2 = most_sig; +#else + u.s.l1 = most_sig; + u.s.l2 = least_sig; +#endif + return u.i128; +} + +long most_sig (union U * u) +{ +#if __LITTLE_ENDIAN__ + return (*u).s.l2; +#else + return (*u).s.l1; +#endif +} + +long least_sig (union U * u) +{ +#if __LITTLE_ENDIAN__ + return (*u).s.l1; +#else + return (*u).s.l2; +#endif +} + +__int128 +add_128 (__int128 *ptr, __int128 val) +{ + return (*ptr + val); +} + +__int128 +sub_128 (__int128 *ptr, __int128 val) +{ + return (*ptr - val); +} + +int +main (void) +{ + /* Do a simple add/sub to make sure carry is happening between the dwords + and that dwords are in correct endian order. */ + u1.i128 = create_128 (1, -1); + u2.i128 = add_128 (&u1.i128, 1); + if ((most_sig (&u2) != 2) || (least_sig (&u2) != 0)) + __builtin_abort (); + u2.i128 = sub_128 (&u2.i128, 1); + if ((most_sig (&u2) != 1) || (least_sig (&u2) != -1)) + __builtin_abort (); + return 0; +} +