]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
2013-11-20 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
authorkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Nov 2013 11:48:07 +0000 (11:48 +0000)
committerkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 20 Nov 2013 11:48:07 +0000 (11:48 +0000)
    Dominik Vogt  <vogt@linux.vnet.ibm.com>

* config/s390/s390.c (s390_canonicalize_comparison): Don't fold
int comparisons with an out of range condition code.
(s390_optimize_nonescaping_tx): Skip empty BBs.
Generate the new tbegin RTX when removing the FPR clobbers (with
two SETs).
(s390_expand_tbegin): Fix the retry loop counter.  Copy CC to the
result before doing the retry calculations.
(s390_init_builtins): Make tbegin "returns_twice" and tabort
"noreturn".
* config/s390/s390.md (UNSPECV_TBEGIN_TDB): New constant used for
the TDB setting part of an tbegin.
("tbegin_1", "tbegin_nofloat_1"): Add a set for the TDB.
("tx_assist"): Set unused argument to an immediate zero instead of
loading zero into a GPR and pass it as argument.
* config/s390/htmxlintrin.h (__TM_simple_begin, __TM_begin):
Remove inline and related attributes.
(__TM_nesting_depth, __TM_is_user_abort, __TM_is_named_user_abort)
(__TM_is_illegal, __TM_is_footprint_exceeded)
(__TM_is_nested_too_deep, __TM_is_conflict): Fix format value
check.

2013-11-20  Dominik Vogt  <vogt@linux.vnet.ibm.com>

* gcc.target/s390/htm-1.c: Rename to ...
* gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c: ... this
one.
* gcc.target/s390/htm-xl-intrin-1.c: Rename to ...
* gcc.target/s390/htm-builtins-compile-3.c: ... this one.
* gcc.target/s390/htm-builtins-compile-2.c: New testcase.
* gcc.target/s390/htm-builtins-1.c: New testcase.
* gcc.target/s390/htm-builtins-2.c: New testcase.
* gcc.target/s390/s390.exp: Add check for htm machine.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205099 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/config/s390/htmxlintrin.h
gcc/config/s390/s390.c
gcc/config/s390/s390.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/s390/htm-1.c [deleted file]
gcc/testsuite/gcc.target/s390/htm-builtins-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/htm-builtins-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/htm-builtins-compile-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/htm-builtins-compile-3.c [moved from gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c with 100% similarity]
gcc/testsuite/gcc.target/s390/s390.exp

index 2bd67d0ef4954bb1d09c588e181f5689c6eb1c22..dbe26236c51f2626e233188d673457e87ea60baa 100644 (file)
@@ -1,3 +1,27 @@
+2013-11-20  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
+           Dominik Vogt  <vogt@linux.vnet.ibm.com>
+
+       * config/s390/s390.c (s390_canonicalize_comparison): Don't fold
+       int comparisons with an out of range condition code.
+       (s390_optimize_nonescaping_tx): Skip empty BBs.
+       Generate the new tbegin RTX when removing the FPR clobbers (with
+       two SETs).
+       (s390_expand_tbegin): Fix the retry loop counter.  Copy CC to the
+       result before doing the retry calculations.
+       (s390_init_builtins): Make tbegin "returns_twice" and tabort
+       "noreturn".
+       * config/s390/s390.md (UNSPECV_TBEGIN_TDB): New constant used for
+       the TDB setting part of an tbegin.
+       ("tbegin_1", "tbegin_nofloat_1"): Add a set for the TDB.
+       ("tx_assist"): Set unused argument to an immediate zero instead of
+       loading zero into a GPR and pass it as argument.
+       * config/s390/htmxlintrin.h (__TM_simple_begin, __TM_begin):
+       Remove inline and related attributes.
+       (__TM_nesting_depth, __TM_is_user_abort, __TM_is_named_user_abort)
+       (__TM_is_illegal, __TM_is_footprint_exceeded)
+       (__TM_is_nested_too_deep, __TM_is_conflict): Fix format value
+       check.
+
 2013-11-20  Richard Biener  <rguenther@suse.de>
 
        PR lto/59035
index 800d5f0aa0c4ae22eae3bdc66a358a734d5b1b0f..d1c7ec566e140f6db1e6300f8b38c02890b9ce08 100644 (file)
@@ -33,13 +33,20 @@ extern "C" {
    the IBM XL compiler.  For documentation please see the "z/OS XL
    C/C++ Programming Guide" publicly available on the web.  */
 
-extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+/* FIXME: __TM_simple_begin and __TM_begin should be marked
+   __always_inline__ as well but this currently produces an error
+   since the tbegin builtins are "returns_twice" and setjmp_call_p
+   (calls.c) therefore identifies the functions as calling setjmp.
+   The tree inliner currently refuses to inline functions calling
+   setjmp.  */
+
+long
 __TM_simple_begin ()
 {
   return __builtin_tbegin_nofloat (0);
 }
 
-extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+long
 __TM_begin (void* const tdb)
 {
   return __builtin_tbegin_nofloat (tdb);
@@ -78,7 +85,7 @@ __TM_nesting_depth (void* const tdb_ptr)
   if (depth != 0)
     return depth;
 
-  if (tdb->format == 0)
+  if (tdb->format != 1)
     return 0;
   return tdb->nesting_depth;
 }
@@ -90,7 +97,7 @@ __TM_is_user_abort (void* const tdb_ptr)
 {
   struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
 
-  if (tdb->format == 0)
+  if (tdb->format != 1)
     return 0;
 
   return !!(tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE);
@@ -101,7 +108,7 @@ __TM_is_named_user_abort (void* const tdb_ptr, unsigned char* code)
 {
   struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
 
-  if (tdb->format == 0)
+  if (tdb->format != 1)
     return 0;
 
   if (tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE)
@@ -117,7 +124,7 @@ __TM_is_illegal (void* const tdb_ptr)
 {
   struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
 
-  return (tdb->format == 0
+  return (tdb->format == 1
          && (tdb->abort_code == 4 /* unfiltered program interruption */
              || tdb->abort_code == 11 /* restricted instruction */));
 }
@@ -127,7 +134,7 @@ __TM_is_footprint_exceeded (void* const tdb_ptr)
 {
   struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
 
-  return (tdb->format == 0
+  return (tdb->format == 1
          && (tdb->abort_code == 7 /* fetch overflow */
              || tdb->abort_code == 8 /* store overflow */));
 }
@@ -137,7 +144,7 @@ __TM_is_nested_too_deep (void* const tdb_ptr)
 {
   struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
 
-  return tdb->format == 0 && tdb->abort_code == 13; /* depth exceeded */
+  return tdb->format == 1 && tdb->abort_code == 13; /* depth exceeded */
 }
 
 extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
@@ -145,7 +152,7 @@ __TM_is_conflict (void* const tdb_ptr)
 {
   struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
 
-  return (tdb->format == 0
+  return (tdb->format == 1
          && (tdb->abort_code == 9 /* fetch conflict */
              || tdb->abort_code == 10 /* store conflict */));
 }
index cae4a329f4e6fda3755dfe12243ad0ef56c2b00b..62d162ab087c9146eb78162756d3fb1606289a31 100644 (file)
@@ -900,7 +900,8 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
        {
          /* For CCRAWmode put the required cc mask into the second
             operand.  */
-         if (GET_MODE (XVECEXP (*op0, 0, 0)) == CCRAWmode)
+        if (GET_MODE (XVECEXP (*op0, 0, 0)) == CCRAWmode
+            && INTVAL (*op1) >= 0 && INTVAL (*op1) <= 3)
            *op1 = gen_rtx_CONST_INT (VOIDmode, 1 << (3 - INTVAL (*op1)));
          *op0 = XVECEXP (*op0, 0, 0);
          *code = new_code;
@@ -7973,6 +7974,9 @@ s390_optimize_nonescaping_tx (void)
     {
       bb = BASIC_BLOCK (bb_index);
 
+      if (!bb)
+       continue;
+
       FOR_BB_INSNS (bb, insn)
        {
          rtx ite, cc, pat, target;
@@ -8086,7 +8090,10 @@ s390_optimize_nonescaping_tx (void)
   if (!result)
     return;
 
-  PATTERN (tbegin_insn) = XVECEXP (PATTERN (tbegin_insn), 0, 0);
+  PATTERN (tbegin_insn) = gen_rtx_PARALLEL (VOIDmode,
+                           gen_rtvec (2,
+                                      XVECEXP (PATTERN (tbegin_insn), 0, 0),
+                                      XVECEXP (PATTERN (tbegin_insn), 0, 1)));
   INSN_CODE (tbegin_insn) = -1;
   df_insn_rescan (tbegin_insn);
 
@@ -9798,6 +9805,7 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
   const int CC3 = 1 << 0;
   rtx abort_label = gen_label_rtx ();
   rtx leave_label = gen_label_rtx ();
+  rtx retry_plus_two = gen_reg_rtx (SImode);
   rtx retry_reg = gen_reg_rtx (SImode);
   rtx retry_label = NULL_RTX;
   rtx jump;
@@ -9806,16 +9814,17 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
   if (retry != NULL_RTX)
     {
       emit_move_insn (retry_reg, retry);
+      emit_insn (gen_addsi3 (retry_plus_two, retry_reg, const2_rtx));
+      emit_insn (gen_addsi3 (retry_reg, retry_reg, const1_rtx));
       retry_label = gen_label_rtx ();
       emit_label (retry_label);
     }
 
   if (clobber_fprs_p)
-    emit_insn (gen_tbegin_1 (tdb,
-                gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK)));
+    emit_insn (gen_tbegin_1 (gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK), tdb));
   else
-    emit_insn (gen_tbegin_nofloat_1 (tdb,
-                gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK)));
+    emit_insn (gen_tbegin_nofloat_1 (gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK),
+                                    tdb));
 
   jump = s390_emit_jump (abort_label,
                         gen_rtx_NE (VOIDmode,
@@ -9836,6 +9845,10 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
   /* Abort handler code.  */
 
   emit_label (abort_label);
+  emit_move_insn (dest, gen_rtx_UNSPEC (SImode,
+                                       gen_rtvec (1, gen_rtx_REG (CCRAWmode,
+                                                                  CC_REGNUM)),
+                                       UNSPEC_CC_TO_INT));
   if (retry != NULL_RTX)
     {
       rtx count = gen_reg_rtx (SImode);
@@ -9847,7 +9860,7 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
       add_int_reg_note (jump, REG_BR_PROB, very_unlikely);
 
       /* CC2 - transient failure. Perform retry with ppa.  */
-      emit_move_insn (count, retry);
+      emit_move_insn (count, retry_plus_two);
       emit_insn (gen_subsi3 (count, count, retry_reg));
       emit_insn (gen_tx_assist (count));
       jump = emit_jump_insn (gen_doloop_si64 (retry_label,
@@ -9857,10 +9870,6 @@ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
       LABEL_NUSES (retry_label) = 1;
     }
 
-  emit_move_insn (dest, gen_rtx_UNSPEC (SImode,
-                                       gen_rtvec (1, gen_rtx_REG (CCRAWmode,
-                                                                  CC_REGNUM)),
-                                       UNSPEC_CC_TO_INT));
   emit_label (leave_label);
 }
 
@@ -9899,6 +9908,9 @@ static void
 s390_init_builtins (void)
 {
   tree ftype, uint64_type;
+  tree returns_twice_attr = tree_cons (get_identifier ("returns_twice"),
+                                      NULL, NULL);
+  tree noreturn_attr = tree_cons (get_identifier ("noreturn"), NULL, NULL);
 
   /* void foo (void) */
   ftype = build_function_type_list (void_type_node, NULL_TREE);
@@ -9909,17 +9921,17 @@ s390_init_builtins (void)
   ftype = build_function_type_list (void_type_node, integer_type_node,
                                    NULL_TREE);
   add_builtin_function ("__builtin_tabort", ftype,
-                       S390_BUILTIN_TABORT, BUILT_IN_MD, NULL, NULL_TREE);
+                       S390_BUILTIN_TABORT, BUILT_IN_MD, NULL, noreturn_attr);
   add_builtin_function ("__builtin_tx_assist", ftype,
                        S390_BUILTIN_TX_ASSIST, BUILT_IN_MD, NULL, NULL_TREE);
 
   /* int foo (void *) */
   ftype = build_function_type_list (integer_type_node, ptr_type_node, NULL_TREE);
   add_builtin_function ("__builtin_tbegin", ftype, S390_BUILTIN_TBEGIN,
-                       BUILT_IN_MD, NULL, NULL_TREE);
+                       BUILT_IN_MD, NULL, returns_twice_attr);
   add_builtin_function ("__builtin_tbegin_nofloat", ftype,
                        S390_BUILTIN_TBEGIN_NOFLOAT,
-                       BUILT_IN_MD, NULL, NULL_TREE);
+                       BUILT_IN_MD, NULL, returns_twice_attr);
 
   /* int foo (void *, int) */
   ftype = build_function_type_list (integer_type_node, ptr_type_node,
@@ -9927,11 +9939,11 @@ s390_init_builtins (void)
   add_builtin_function ("__builtin_tbegin_retry", ftype,
                        S390_BUILTIN_TBEGIN_RETRY,
                        BUILT_IN_MD,
-                       NULL, NULL_TREE);
+                       NULL, returns_twice_attr);
   add_builtin_function ("__builtin_tbegin_retry_nofloat", ftype,
                        S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
                        BUILT_IN_MD,
-                       NULL, NULL_TREE);
+                       NULL, returns_twice_attr);
 
   /* int foo (void) */
   ftype = build_function_type_list (integer_type_node, NULL_TREE);
index 8354e26389296f23bfd49a80235e2c547b05d867..d537d29d24f002f09514d00551b291321f0ccd8c 100644 (file)
 
    ; Transactional Execution support
    UNSPECV_TBEGIN
+   UNSPECV_TBEGIN_TDB
    UNSPECV_TBEGINC
    UNSPECV_TEND
    UNSPECV_TABORT
 
 (define_insn "tbegin_1"
   [(set (reg:CCRAW CC_REGNUM)
-       (unspec_volatile:CCRAW [(match_operand:BLK 0 "memory_operand"    "=Q")
-                               (match_operand     1 "const_int_operand" " D")]
+       (unspec_volatile:CCRAW [(match_operand 0 "const_int_operand" "D")]
                               UNSPECV_TBEGIN))
+   (set (match_operand:BLK 1 "memory_operand" "=Q")
+       (unspec_volatile:BLK [(match_dup 0)] UNSPECV_TBEGIN_TDB))
    (clobber (reg:DF 16))
    (clobber (reg:DF 17))
    (clobber (reg:DF 18))
    (clobber (reg:DF 31))]
 ; CONST_OK_FOR_CONSTRAINT_P does not work with D constraint since D is
 ; not supposed to be used for immediates (see genpreds.c).
-  "TARGET_HTM && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 0xffff"
-  "tbegin\t%0,%x1"
+  "TARGET_HTM && INTVAL (operands[0]) >= 0 && INTVAL (operands[0]) <= 0xffff"
+  "tbegin\t%1,%x0"
   [(set_attr "op_type" "SIL")])
 
 ; Same as above but without the FPR clobbers
 (define_insn "tbegin_nofloat_1"
   [(set (reg:CCRAW CC_REGNUM)
-       (unspec_volatile:CCRAW [(match_operand:BLK 0 "memory_operand"    "=Q")
-                               (match_operand     1 "const_int_operand" " D")]
-                              UNSPECV_TBEGIN))]
-  "TARGET_HTM && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 0xffff"
-  "tbegin\t%0,%x1"
+       (unspec_volatile:CCRAW [(match_operand 0 "const_int_operand" "D")]
+                              UNSPECV_TBEGIN))
+   (set (match_operand:BLK 1 "memory_operand" "=Q")
+       (unspec_volatile:BLK [(match_dup 0)] UNSPECV_TBEGIN_TDB))]
+  "TARGET_HTM && INTVAL (operands[0]) >= 0 && INTVAL (operands[0]) <= 0xffff"
+  "tbegin\t%1,%x0"
   [(set_attr "op_type" "SIL")])
 
 
 ; Transaction perform processor assist
 
 (define_expand "tx_assist"
-  [(set (match_dup 1) (const_int 0))
-   (unspec_volatile [(match_operand:SI 0 "register_operand" "")
-                    (match_dup 1)
+  [(unspec_volatile [(match_operand:SI 0 "register_operand" "")
+                    (reg:SI GPR0_REGNUM)
                     (const_int 1)]
                    UNSPECV_PPA)]
   "TARGET_HTM"
-{
-  operands[1] = gen_reg_rtx (SImode);
-})
+  "")
 
 (define_insn "*ppa"
   [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
                     (match_operand 2 "const_int_operand" "I")]
                    UNSPECV_PPA)]
   "TARGET_HTM && INTVAL (operands[2]) < 16"
-  "ppa\t%0,%1,1"
+  "ppa\t%0,%1,%2"
   [(set_attr "op_type" "RRF")])
index bb30fd36e6ae622aa5e746cbedc3a3e49cfee6de..606e4de6979a0112b41dc035ff947b8f274b075d 100644 (file)
@@ -1,3 +1,15 @@
+2013-11-20  Dominik Vogt  <vogt@linux.vnet.ibm.com>
+
+       * gcc.target/s390/htm-1.c: Rename to ...
+       * gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c: ... this
+       one.
+       * gcc.target/s390/htm-xl-intrin-1.c: Rename to ...
+       * gcc.target/s390/htm-builtins-compile-3.c: ... this one.
+       * gcc.target/s390/htm-builtins-compile-2.c: New testcase.
+       * gcc.target/s390/htm-builtins-1.c: New testcase.
+       * gcc.target/s390/htm-builtins-2.c: New testcase.
+       * gcc.target/s390/s390.exp: Add check for htm machine.
+
 2013-11-19  Joshua J Cogliati  <jrincayc@yahoo.com>
 
        PR c/53001
diff --git a/gcc/testsuite/gcc.target/s390/htm-1.c b/gcc/testsuite/gcc.target/s390/htm-1.c
deleted file mode 100644 (file)
index 245ba2c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This checks the availability of the low-level builtins introduced
-   for transactional execution.  */
-
-/* { dg-do compile } */
-/* { dg-options "-O3 -march=zEC12 -mzarch" } */
-
-#include <stdint.h>
-#include <htmintrin.h>
-
-int global = 0;
-uint64_t g;
-struct __htm_tdb global_tdb;
-
-int
-foo (struct __htm_tdb* tdb, int reg, int *mem, uint64_t *mem64)
-{
-
-  int cc;
-  int n;
-
-  cc = __builtin_tbegin (0);
-  cc = __builtin_tbegin (tdb);
-  cc = __builtin_tbegin (&global_tdb);
-
-  cc = __builtin_tbegin_nofloat (0);
-  cc = __builtin_tbegin_nofloat (&global_tdb);
-
-  cc = __builtin_tbegin_retry (0, 42);
-  cc = __builtin_tbegin_retry (0, reg);
-  cc = __builtin_tbegin_retry (0, *mem);
-  cc = __builtin_tbegin_retry (0, global);
-  cc = __builtin_tbegin_retry (tdb, 42);
-  cc = __builtin_tbegin_retry (&global_tdb, 42);
-
-  cc = __builtin_tbegin_retry_nofloat (0, 42);
-  cc = __builtin_tbegin_retry_nofloat (0, reg);
-  cc = __builtin_tbegin_retry_nofloat (0, *mem);
-  cc = __builtin_tbegin_retry_nofloat (0, global);
-  cc = __builtin_tbegin_retry_nofloat (&global_tdb, 42);
-
-  __builtin_tbeginc ();
-
-  n = __builtin_tx_nesting_depth();
-
-  __builtin_non_tx_store(&g, 23);
-  __builtin_non_tx_store(mem64, 23);
-  __builtin_non_tx_store(&g, reg);
-  __builtin_non_tx_store(&g, *mem);
-  __builtin_non_tx_store(&g, global);
-
-  __builtin_tabort (42 + 255);
-  __builtin_tabort (reg);
-  /* { dg-final { scan-assembler-times "tabort\t255" 1 } } */
-  __builtin_tabort (reg + 255);
-  __builtin_tabort (*mem);
-  __builtin_tabort (global);
-  /* Here global + 255 gets reloaded into a reg.  Better would be to
-     just reload global or *mem and get the +255 for free as address
-     arithmetic.  */
-  __builtin_tabort (*mem + 255);
-  __builtin_tabort (global + 255);
-
-  __builtin_tend();
-
-  __builtin_tx_assist (23);
-  __builtin_tx_assist (reg);
-  __builtin_tx_assist (*mem);
-  __builtin_tx_assist (global);
-}
-
-/* Make sure the tdb NULL argument ends up as immediate value in the
-   instruction.  */
-/* { dg-final { scan-assembler-times "tbegin\t0," 10 } } */
diff --git a/gcc/testsuite/gcc.target/s390/htm-builtins-1.c b/gcc/testsuite/gcc.target/s390/htm-builtins-1.c
new file mode 100644 (file)
index 0000000..c90490f
--- /dev/null
@@ -0,0 +1,1073 @@
+/* Functional tests of the htm __builtin_... macros.  */
+
+/* { dg-do run } */
+/* { dg-require-effective-target htm } */
+/* { dg-options "-O3 -march=zEC12 -mzarch" } */
+
+/* ---------------------------- included header files ---------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <htmintrin.h>
+
+/* ---------------------------- local definitions -------------------------- */
+
+#define DEFAULT_MAX_REPETITIONS 5
+#define DEFAULT_REQUIRED_QUORUM ((DEFAULT_MAX_REPETITIONS) - 1)
+#define NUM_WARMUP_RUNS 10
+
+/* ---------------------------- local macros ------------------------------- */
+
+#define TEST_DF_REP(name) \
+  { #name, name, DEFAULT_MAX_REPETITIONS, DEFAULT_REQUIRED_QUORUM }
+#define TEST_NO_REP(name) { #name, name, 1, 1 }
+
+/* ---------------------------- local types -------------------------------- */
+
+typedef int (*test_func_t)(void);
+
+typedef struct
+{
+  const char *name;
+  test_func_t test_func;
+  int max_repetitions;
+  int required_quorum;
+} test_table_entry_t;
+
+/* ---------------------------- local variables ---------------------------- */
+
+__attribute__ ((aligned(256))) static struct __htm_tdb local_tdb256;
+static struct __htm_tdb local_tdb;
+static int do_dump_tdb = 0;
+
+/* ---------------------------- exported variables (globals) --------------- */
+
+__attribute__ ((aligned(256))) struct
+{
+  float float_1;
+  float float_2;
+  float float_3;
+} global = { 1.0, 2.5, 0.0 };
+
+__attribute__ ((aligned(256))) struct
+{
+  volatile uint64_t c1;
+  volatile uint64_t c2;
+  volatile uint64_t c3;
+} counters = { 0, 0, 0 };
+
+/* ---------------------------- local helper functions --------------------- */
+
+static void dump_tdb (struct __htm_tdb *tdb)
+{
+  unsigned char *p;
+  int i;
+  int j;
+
+  if (do_dump_tdb == 0)
+    {
+      return;
+    }
+  p = (unsigned char *)tdb;
+  for (i = 0; i < 16; i++)
+    {
+      fprintf (stderr, "0x%02x  ", i * 16);
+      for (j = 0; j < 16; j++)
+       {
+         fprintf (stderr, "%02x", (int)p[i * 16 + j]);
+         if (j < 15)
+           {
+             fprintf (stderr, " ");
+           }
+         if (j == 7)
+           {
+             fprintf (stderr, " ");
+           }
+       }
+      fprintf (stderr, "\n");
+    }
+
+  return;
+}
+
+/* ---------------------------- local test functions ----------------------- */
+
+/* Check values of the constants defined in htmintrin.h.  */
+static int test_constants (void)
+{
+  if (_HTM_TBEGIN_STARTED != 0)
+    {
+      return 100 * _HTM_TBEGIN_STARTED + 1;
+    }
+  if (_HTM_TBEGIN_INDETERMINATE != 1)
+    {
+      return 100 * _HTM_TBEGIN_INDETERMINATE + 2;
+    }
+  if (_HTM_TBEGIN_TRANSIENT != 2)
+    {
+      return 100 * _HTM_TBEGIN_TRANSIENT + 3;
+    }
+  if (_HTM_TBEGIN_PERSISTENT != 3)
+    {
+      return 100 * _HTM_TBEGIN_PERSISTENT + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_ntstg_tend (void)
+{
+  int rc;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      __builtin_non_tx_store ((uint64_t *)&counters.c1, 1);
+      counters.c2 = 2;
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 5;
+       }
+      if (counters.c1 != 1)
+       {
+         return 100 * counters.c1 + 2;
+       }
+      if (counters.c2 != 2)
+       {
+         return 100 * counters.c2 + 3;
+       }
+    }
+  else
+    {
+      return 100 * rc + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_ntstg_tabort (void)
+{
+  float f;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  f = 0;
+  if (__builtin_tbegin ((void *)0) == 0)
+    {
+      __builtin_non_tx_store ((uint64_t *)&counters.c1, 1);
+      counters.c2 = 2;
+      f = 1;
+      __builtin_tabort (256);
+      return 1;
+    }
+  if (counters.c1 != 1)
+    {
+      return 100 * counters.c1 + 2;
+    }
+  if (counters.c2 != 0)
+    {
+      return 100 * counters.c2 + 3;
+    }
+  if (f != 0)
+    {
+      return 100 * f + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_nofloat (void)
+{
+  int rc;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
+    {
+      __builtin_non_tx_store ((uint64_t *)&counters.c1, 1);
+      counters.c2 = 2;
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 5;
+       }
+      if (counters.c1 != 1)
+       {
+         return 100 * counters.c1 + 2;
+       }
+      if (counters.c2 != 2)
+       {
+         return 100 * counters.c2 + 3;
+       }
+    }
+  else
+    {
+      return 100 * rc + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_retry (void)
+{
+  int rc;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  counters.c3 = 0;
+  if ((rc = __builtin_tbegin_retry ((void *)0, 5)) == 0)
+    {
+      int do_abort;
+
+      do_abort = (counters.c1 == 0) ? 1 : 0;
+      __builtin_non_tx_store (
+                            (uint64_t *)&counters.c1, counters.c1 + 1);
+      if (do_abort == 1)
+       {
+         __builtin_tabort (256);
+       }
+      counters.c2 = counters.c2 + 10;
+      __builtin_non_tx_store ((uint64_t *)&counters.c3, 3);
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 5;
+       }
+      if (counters.c1 != 2)
+       {
+         return 100 * counters.c1 + 2;
+       }
+      if (counters.c2 != 10)
+       {
+         return 100 * counters.c2 + 3;
+       }
+      if (counters.c3 != 3)
+       {
+         return 100 * counters.c3 + 6;
+       }
+    }
+  else
+    {
+      return 100 * rc + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_retry_nofloat (void)
+{
+  int rc;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  counters.c3 = 0;
+  if ((rc = __builtin_tbegin_retry_nofloat ((void *)0, 5)) == 0)
+    {
+      int do_abort;
+
+      do_abort = (counters.c1 == 0) ? 1 : 0;
+      __builtin_non_tx_store (
+                            (uint64_t *)&counters.c1, counters.c1 + 1);
+      if (do_abort == 1)
+       {
+         __builtin_tabort (256);
+       }
+      counters.c2 = counters.c2 + 10;
+      __builtin_non_tx_store ((uint64_t *)&counters.c3, 3);
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 5;
+       }
+      if (counters.c1 != 2)
+       {
+         return 100 * counters.c1 + 2;
+       }
+      if (counters.c2 != 10)
+       {
+         return 100 * counters.c2 + 3;
+       }
+      if (counters.c3 != 3)
+       {
+         return 100 * counters.c3 + 6;
+       }
+    }
+  else
+    {
+      return 100 * rc + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_aborts (void)
+{
+  float f;
+  int rc;
+
+  f = 77;
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      f = 88;
+      __builtin_tabort (256);
+      return 2;
+    }
+  else if (rc != 2)
+    {
+      return 3;
+    }
+  if (f != 77)
+    {
+      return 4;
+    }
+  f = 66;
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      f = 99;
+      __builtin_tabort (257);
+      return 5;
+    }
+  else if (rc != 3)
+    {
+      return 100 * rc + 6;
+    }
+  if (f != 66)
+    {
+      return 100 * f + 7;
+    }
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      global.float_3 = global.float_1 + global.float_2;
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 8;
+       }
+    }
+  else
+    {
+      return 100 * rc + 9;
+    }
+  if (global.float_3 != global.float_1 + global.float_2)
+    {
+      return 100 * rc + 10;
+    }
+
+  return 0;
+}
+
+static __attribute__((noinline)) void indirect_abort(int abort_code)
+{
+  __builtin_tabort (abort_code);
+
+  return;
+}
+
+static int test_tbegin_indirect_aborts (void)
+{
+  float f;
+  int rc;
+
+  f = 77;
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      f = 88;
+      indirect_abort(256);
+      return 2;
+    }
+  else if (rc != 2)
+    {
+      return 100 * rc + 3;
+    }
+  if (f != 77)
+    {
+      return 100 * rc + 4;
+    }
+  f = 66;
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      f = 99;
+      indirect_abort(257);
+      return 5;
+    }
+  else if (rc != 3)
+    {
+      return 100 * rc + 6;
+    }
+  if (f != 66)
+    {
+      return 100 * f + 7;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_nofloat_aborts (void)
+{
+  int rc;
+
+  if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
+    {
+      __builtin_tabort (256);
+      return 2;
+    }
+  if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
+    {
+      __builtin_tabort (257);
+      return 1005;
+    }
+  else if (rc != 3)
+    {
+      return 1000 * rc + 6;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_nofloat_indirect_aborts (void)
+{
+  int rc;
+
+  if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
+    {
+      indirect_abort (256);
+      return 2;
+    }
+  if ((rc = __builtin_tbegin_nofloat ((void *)0)) == 0)
+    {
+      indirect_abort (257);
+      return 1005;
+    }
+  else if (rc != 3)
+    {
+      return 1000 * rc + 6;
+    }
+
+  return 0;
+}
+
+static
+int _test_tbegin_retry_aborts (int retries, uint64_t abort_code)
+{
+  int rc;
+
+  counters.c1 = 0;
+  if ((rc = __builtin_tbegin_retry ((void *)0, retries)) == 0)
+    {
+      __builtin_non_tx_store ((uint64_t *)&counters.c1, counters.c1 + 1);
+      __builtin_tabort (abort_code);
+      return 2;
+    }
+  else
+    {
+      if ((abort_code & 1) == 0)
+       {
+         if (rc != 2)
+           {
+             return 100 * rc + 2003;
+           }
+         else if (counters.c1 != (uint64_t)retries + 1)
+           {
+             return 1000 * counters.c1 + 100 * retries + 4;
+           }
+       }
+      else
+       {
+         if (rc != 3)
+           {
+             return 100 * rc + 3005;
+           }
+         else if (counters.c1 != 1)
+           {
+             return 1000 * counters.c1 + 100 * retries + 6;
+           }
+       }
+    }
+
+  return 0;
+}
+
+static int test_tbegin_retry_aborts (void)
+{
+  int rc;
+  int retries;
+
+  for (retries = 1; retries <= 3; retries++)
+    {
+      rc = _test_tbegin_retry_aborts (retries, 256);
+      if (rc != 0)
+       {
+         return 10000 + rc;
+       }
+    }
+  for (retries = 1; retries <= 3; retries++)
+    {
+      rc = _test_tbegin_retry_aborts (retries, 257);
+      if (rc != 0)
+       {
+         return 20000 + rc;
+       }
+    }
+  if ((rc = __builtin_tbegin_retry ((void *)0, 5)) == 0)
+    {
+      global.float_3 = global.float_1 + global.float_2;
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 30000 + 100 * rc + 6;
+       }
+    }
+  else
+    {
+      return 30000 + 100 * rc + 7;
+    }
+
+  return 0;
+}
+
+static int _test_tbegin_retry_nofloat_aborts (int retries, uint64_t abort_code)
+{
+  int rc;
+
+  counters.c1 = 0;
+  if ((rc = __builtin_tbegin_retry_nofloat ((void *)0, retries)) == 0)
+    {
+      __builtin_non_tx_store ((uint64_t *)&counters.c1, counters.c1 + 1);
+      __builtin_tabort (abort_code);
+      return 2;
+    }
+  else
+    {
+      if ((abort_code & 1) == 0)
+       {
+         if (rc != 2)
+           {
+             return 100 * rc + 2003;
+           }
+         else if (counters.c1 != (uint64_t)retries + 1)
+           {
+             return 1000 * counters.c1 + 100 * retries + 4;
+           }
+       }
+      else
+       {
+         if (rc != 3)
+           {
+             return 100 * rc + 3005;
+           }
+         else if (counters.c1 != 1)
+           {
+             return 1000 * counters.c1 + 100 * retries + 6;
+           }
+       }
+    }
+
+  return 0;
+}
+
+static int test_tbegin_retry_nofloat_aborts (void)
+{
+  int rc;
+  int retries;
+
+  for (retries = 1; retries <= 3; retries++)
+    {
+      rc = _test_tbegin_retry_nofloat_aborts (retries, 256);
+      if (rc != 0)
+       {
+         return 10 * retries + rc;
+       }
+    }
+  for (retries = 1; retries <= 3; retries++)
+    {
+      rc = _test_tbegin_retry_nofloat_aborts (retries, 257);
+      if (rc != 0)
+       {
+         return 10000 + 10 * retries + rc;
+       }
+    }
+
+  return 0;
+}
+
+static int test_tbegin_tdb (void)
+{
+  int rc;
+
+  local_tdb.format = 0;
+  if ((rc = __builtin_tbegin (&local_tdb)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 1;
+       }
+      if (local_tdb.format != 0)
+       {
+         dump_tdb (&local_tdb);
+         return 100 * local_tdb.format + 2;
+       }
+    }
+  else
+    {
+      return 100 * rc + 3;
+    }
+  local_tdb.format = 0;
+  if ((rc = __builtin_tbegin (&local_tdb)) == 0)
+    {
+      __builtin_tabort (257);
+      return 4;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 100 * rc + 5;
+       }
+      if (local_tdb.format != 1)
+       {
+         dump_tdb (&local_tdb);
+         return 100 * local_tdb.format + 6;
+       }
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin (&local_tdb256)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 1100 * rc + 1;
+       }
+      if (local_tdb256.format != 0)
+       {
+         dump_tdb (&local_tdb256);
+         return 1100 * local_tdb256.format + 2;
+       }
+    }
+  else
+    {
+      return 1100 * rc + 3;
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin (&local_tdb256)) == 0)
+    {
+      __builtin_tabort (257);
+      return 2004;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 2100 * rc + 5;
+       }
+      if (local_tdb256.format != 1)
+       {
+         dump_tdb (&local_tdb256);
+         return 2100 * local_tdb256.format + 6;
+       }
+    }
+
+  return 0;
+}
+
+static int test_tbegin_nofloat_tdb (void)
+{
+  int rc;
+
+  local_tdb.format = 0;
+  if ((rc = __builtin_tbegin_nofloat (&local_tdb)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 1;
+       }
+      if (local_tdb.format != 0)
+       {
+         dump_tdb (&local_tdb);
+         return 100 * local_tdb.format + 2;
+       }
+    }
+  else
+    {
+      return 3;
+    }
+  local_tdb.format = 0;
+  if ((rc = __builtin_tbegin_nofloat (&local_tdb)) == 0)
+    {
+      __builtin_tabort (257);
+      return 4;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 100 * rc + 5;
+       }
+      if (local_tdb.format != 1)
+       {
+         dump_tdb (&local_tdb);
+         return 100 * local_tdb.format + 6;
+       }
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin_nofloat (&local_tdb256)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 1100 * rc + 1;
+       }
+      if (local_tdb256.format != 0)
+       {
+         dump_tdb (&local_tdb256);
+         return 1100 * local_tdb256.format + 2;
+       }
+    }
+  else
+    {
+      return 1003;
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin_nofloat (&local_tdb256)) == 0)
+    {
+      __builtin_tabort (257);
+      return 2004;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 2100 * rc + 5;
+       }
+      if (local_tdb256.format != 1)
+       {
+         dump_tdb (&local_tdb256);
+         return 2100 * local_tdb256.format + 6;
+       }
+    }
+
+  return 0;
+}
+
+static int test_tbegin_retry_tdb (void)
+{
+  int rc;
+
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin_retry (&local_tdb256, 2)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 1100 * rc + 1;
+       }
+      if (local_tdb256.format != 0)
+       {
+         dump_tdb (&local_tdb256);
+         return 1100 * local_tdb256.format + 2;
+       }
+    }
+  else
+    {
+      return 1003;
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin_retry (&local_tdb256, 2)) == 0)
+    {
+      __builtin_tabort (257);
+      return 2004;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 2100 * rc + 5;
+       }
+      if (local_tdb256.format != 1)
+       {
+         dump_tdb (&local_tdb256);
+         return 2100 * local_tdb256.format + 6;
+       }
+    }
+
+  return 0;
+}
+
+static int test_tbegin_retry_nofloat_tdb (void)
+{
+  int rc;
+
+  local_tdb.format = 0;
+  if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb, 2)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 100 * rc + 1;
+       }
+      if (local_tdb.format != 0)
+       {
+         dump_tdb (&local_tdb);
+         return 100 * local_tdb.format + 2;
+       }
+    }
+  else
+    {
+      return 100 * rc + 3;
+    }
+  local_tdb.format = 0;
+  if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb, 2)) == 0)
+    {
+      __builtin_tabort (257);
+      return 4;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 100 * rc + 5;
+       }
+      if (local_tdb.format != 1)
+       {
+         dump_tdb (&local_tdb);
+         return 100 * local_tdb.format + 6;
+       }
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb256, 2)) == 0)
+    {
+      rc = __builtin_tend ();
+      if (rc != 0)
+       {
+         return 1100 * rc + 1;
+       }
+      if (local_tdb256.format != 0)
+       {
+         dump_tdb (&local_tdb256);
+         return 1100 * local_tdb256.format + 2;
+       }
+    }
+  else
+    {
+      return 1100 * rc + 3;
+    }
+  local_tdb256.format = 0;
+  if ((rc = __builtin_tbegin_retry_nofloat (&local_tdb256, 2)) == 0)
+    {
+      __builtin_tabort (257);
+      return 2004;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 2100 * rc + 5;
+       }
+      if (local_tdb256.format != 1)
+       {
+         dump_tdb (&local_tdb256);
+         return 2100 * local_tdb256.format + 6;
+       }
+    }
+
+  return 0;
+}
+
+static int test_etnd (void)
+{
+  int rc;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  counters.c3 = 0;
+  if ((rc = __builtin_tbegin ((void *)0)) == 0)
+    {
+      counters.c1 = __builtin_tx_nesting_depth ();
+      if (__builtin_tbegin ((void *)0) == 0)
+       {
+         counters.c2 = __builtin_tx_nesting_depth ();
+         if (__builtin_tbegin ((void *)0) == 0)
+           {
+             counters.c3 = __builtin_tx_nesting_depth ();
+             __builtin_tend ();
+           }
+         __builtin_tend ();
+       }
+      __builtin_tend ();
+    }
+  else
+    {
+      return 100 * rc + 1;
+    }
+  if (counters.c1 != 1)
+    {
+      return 100 * counters.c1 + 2;
+    }
+  if (counters.c2 != 2)
+    {
+      return 100 * counters.c2 + 3;
+    }
+  if (counters.c3 != 3)
+    {
+      return 100 * counters.c3 + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbeginc (void)
+{
+  int rc;
+
+  counters.c1 = 0;
+  __builtin_tbeginc ();
+  counters.c1 = 1;
+  rc = __builtin_tend ();
+  if (rc != 0)
+    {
+      return 10000 * rc + 1;
+    }
+  if (counters.c1 != 1)
+    {
+      return 100000 * counters.c1 + 3;
+    }
+
+  return 0;
+}
+
+/* ---------------------------- local testing framework functions ---------- */
+
+static int run_one_test (const test_table_entry_t *test_entry)
+{
+  int do_print_passes;
+  int succeeded;
+  int rc;
+  int i;
+
+  /* Warmup run to get all necessary data and instruction pages into the page
+   * tables.  */
+  {
+    int run;
+
+    do_dump_tdb = 0;
+    for (run = 0; run < NUM_WARMUP_RUNS; run++)
+      {
+       test_entry->test_func ();
+      }
+    do_dump_tdb = 1;
+  }
+  do_print_passes = (
+                    test_entry->required_quorum != 1 ||
+                    test_entry->max_repetitions != 1);
+  printf ("RRR RUN  %s\n", test_entry->name);
+  if (do_print_passes == 1)
+    {
+      printf (
+            "         (requires %d successful out of %d runs)\n",
+            test_entry->required_quorum,
+            test_entry->max_repetitions);
+    }
+  succeeded = 0;
+  rc = 0;
+  for (rc = 0, i = 0; i < test_entry->max_repetitions; i++)
+    {
+      if (do_print_passes == 1)
+       {
+         if (i == 0)
+           {
+             printf ("        ");
+           }
+         else
+           {
+             printf (",");
+           }
+       }
+      rc = test_entry->test_func ();
+      if (rc == 0)
+       {
+         if (do_print_passes == 1)
+           {
+             printf (" success");
+           }
+         succeeded++;
+         if (succeeded >= test_entry->required_quorum)
+           {
+             break;
+           }
+       }
+      else
+       {
+         printf (" failed (rc = %d)", rc);
+       }
+    }
+  if (do_print_passes == 1 || rc != 0)
+    {
+      printf ("\n");
+    }
+  if (succeeded >= test_entry->required_quorum)
+    {
+      printf ("+++ OK   %s\n", test_entry->name);
+
+      return 0;
+    }
+  else
+    {
+      printf ("--- FAIL %s\n", test_entry->name);
+
+      return (rc != 0) ? rc : -1;
+    }
+}
+
+static int run_all_tests (const test_table_entry_t *test_table)
+{
+  const test_table_entry_t *test;
+  int rc;
+
+  for (
+       rc = 0, test = &test_table[0];
+       test->test_func != NULL && rc == 0; test++)
+    {
+      rc = run_one_test (test);
+    }
+
+  return rc;
+}
+
+/* ---------------------------- interface functions ------------------------ */
+
+int main (void)
+{
+  const test_table_entry_t test_table[] = {
+    TEST_NO_REP (test_constants),
+    TEST_DF_REP (test_tbegin_ntstg_tend),
+    TEST_DF_REP (test_tbegin_ntstg_tabort),
+    TEST_DF_REP (test_tbegin_nofloat),
+    TEST_NO_REP (test_tbegin_retry),
+    TEST_NO_REP (test_tbegin_retry_nofloat),
+    TEST_DF_REP (test_tbegin_aborts),
+    TEST_DF_REP (test_tbegin_indirect_aborts),
+    TEST_DF_REP (test_tbegin_nofloat_aborts),
+    TEST_DF_REP (test_tbegin_nofloat_indirect_aborts),
+    TEST_NO_REP (test_tbegin_retry_aborts),
+    TEST_NO_REP (test_tbegin_retry_nofloat_aborts),
+    TEST_DF_REP (test_tbegin_tdb),
+    TEST_DF_REP (test_tbegin_nofloat_tdb),
+    TEST_NO_REP (test_tbegin_retry_tdb),
+    TEST_NO_REP (test_tbegin_retry_nofloat_tdb),
+    TEST_DF_REP (test_etnd),
+    TEST_DF_REP (test_tbeginc),
+    { (void *)0, 0, 0 }
+  };
+
+  {
+    int rc;
+
+    rc = run_all_tests (test_table);
+
+    return rc;
+  }
+}
diff --git a/gcc/testsuite/gcc.target/s390/htm-builtins-2.c b/gcc/testsuite/gcc.target/s390/htm-builtins-2.c
new file mode 100644 (file)
index 0000000..15b0d12
--- /dev/null
@@ -0,0 +1,682 @@
+/* Functional tests of the htm __TM_... macros.  */
+
+/* { dg-do run } */
+/* { dg-require-effective-target htm } */
+/* { dg-options "-O3 -march=zEC12 -mzarch" } */
+
+/* ---------------------------- included header files ---------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <htmxlintrin.h>
+
+/* ---------------------------- local definitions -------------------------- */
+
+#define DEFAULT_MAX_REPETITIONS 5
+#define DEFAULT_REQUIRED_QUORUM ((DEFAULT_MAX_REPETITIONS) - 1)
+#define DEFAULT_ABORT_ADDRESS (0x12345678u)
+
+/* ---------------------------- local macros ------------------------------- */
+
+#define TEST_DF_REP(name) \
+  { #name, name, DEFAULT_MAX_REPETITIONS, DEFAULT_REQUIRED_QUORUM }
+#define TEST_NO_REP(name) { #name, name, 1, 1 }
+
+/* ---------------------------- local types -------------------------------- */
+
+typedef int (*test_func_t)(void);
+
+typedef struct
+{
+  const char *name;
+  test_func_t test_func;
+  int max_repetitions;
+  int required_quorum;
+} test_table_entry_t;
+
+typedef enum
+{
+  ABORT_T_SYSTEM = 0,
+  ABORT_T_USER = 1,
+} abort_user_t;
+
+typedef enum
+{
+  ABORT_T_NONE = 0,
+  ABORT_T_ILLEGAL,
+  ABORT_T_FOOTPRINT_EXCEEDED,
+  ABORT_T_NESTED_TOO_DEEP,
+  ABORT_T_CONFLICT,
+
+  ABORT_T_INVALID_ABORT_CODE
+} abort_t;
+
+/* ---------------------------- local variables ---------------------------- */
+
+__attribute__ ((aligned(256))) static struct __htm_tdb local_tdb256;
+static struct __htm_tdb local_tdb;
+
+static abort_t const abort_classes[] =
+{
+  ABORT_T_INVALID_ABORT_CODE,
+  ABORT_T_NONE,
+  ABORT_T_NONE,
+  ABORT_T_NONE,
+
+  ABORT_T_ILLEGAL,
+  ABORT_T_NONE,
+  ABORT_T_NONE,
+  ABORT_T_FOOTPRINT_EXCEEDED,
+
+  ABORT_T_FOOTPRINT_EXCEEDED,
+  ABORT_T_CONFLICT,
+  ABORT_T_CONFLICT,
+  ABORT_T_ILLEGAL,
+
+  ABORT_T_NONE,
+  ABORT_T_NESTED_TOO_DEEP,
+  ABORT_T_NONE,
+  ABORT_T_NONE,
+
+  ABORT_T_NONE
+};
+
+static size_t num_abort_classes = sizeof(abort_classes) / sizeof(abort_t);
+
+/* ---------------------------- exported variables (globals) --------------- */
+
+int global_int = 0;
+uint64_t global_u64 = 0;
+float global_float_1 = 1.0;
+float global_float_2 = 2.5;
+float global_float_3 = 0.0;
+__attribute__ ((aligned(256))) struct
+{
+  volatile uint64_t c1;
+  volatile uint64_t c2;
+  volatile uint64_t c3;
+} counters = { 0, 0, 0 };
+
+/* ---------------------------- local helper functions --------------------- */
+
+static void dump_tdb(struct __htm_tdb *tdb)
+{
+  unsigned char *p;
+  int i;
+  int j;
+
+  p = (unsigned char *)tdb;
+  for (i = 0; i < 16; i++)
+    {
+      fprintf(stderr, "0x%02x  ", i * 16);
+      for (j = 0; j < 16; j++)
+       {
+         fprintf(stderr, "%02x", (int)p[i * 16 + j]);
+         if (j < 15)
+           {
+             fprintf(stderr, " ");
+           }
+         if (j == 7)
+           {
+             fprintf(stderr, " ");
+           }
+       }
+      fprintf(stderr, "\n");
+    }
+
+  return;
+}
+
+static void make_fake_tdb(struct __htm_tdb *tdb)
+{
+  memset(tdb, 0, sizeof(*tdb));
+  tdb->format = 1;
+  tdb->nesting_depth = 1;
+  tdb->atia = DEFAULT_ABORT_ADDRESS;
+  tdb->abort_code = 11;
+
+  return;
+}
+
+static int check_abort_code_in_tdb(struct __htm_tdb *tdb, uint64_t abort_code)
+{
+  long expect_rc;
+  long rc;
+
+  if (abort_code != 0)
+    {
+      long addr;
+
+      addr = __TM_failure_address(&local_tdb);
+      if (addr != DEFAULT_ABORT_ADDRESS)
+       {
+         return 11;
+       }
+    }
+  {
+    long long tdb_abort_code;
+
+    tdb_abort_code = __TM_failure_code(tdb);
+    if ((uint64_t)tdb_abort_code != abort_code)
+      {
+       fprintf(
+               stderr, "tm_ac %" PRIu64 ", ac %" PRIu64
+               ", tdb_ac %" PRIu64 "\n",
+               (uint64_t)tdb_abort_code, abort_code,
+               (uint64_t)tdb->abort_code);
+       return 10;
+      }
+  }
+  expect_rc = (abort_code >= 256) ? 1 : 0;
+  rc = __TM_is_user_abort(tdb);
+  if (rc != expect_rc)
+    {
+      fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
+      return 1;
+    }
+  {
+    unsigned char code;
+
+    code = 0xffu;
+    rc = __TM_is_named_user_abort(tdb, &code);
+    if (rc != expect_rc)
+      {
+       fprintf(
+               stderr, "rc %ld, expect_rc %ld\n", rc,
+               expect_rc);
+       return 2;
+      }
+    if (expect_rc == 1 && code != abort_code - 256)
+      {
+       return 3;
+      }
+  }
+  if (abort_code > (uint64_t)num_abort_classes)
+    {
+      abort_code = (uint64_t)num_abort_classes;
+    }
+  expect_rc = (abort_classes[abort_code] == ABORT_T_ILLEGAL) ? 1 : 0;
+  rc = __TM_is_illegal(tdb);
+  if (rc != expect_rc)
+    {
+      dump_tdb(tdb);
+      fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
+      return 4;
+    }
+  expect_rc =
+    (abort_classes[abort_code] == ABORT_T_FOOTPRINT_EXCEEDED) ?
+    1 : 0;
+  rc = __TM_is_footprint_exceeded(tdb);
+  if (rc != expect_rc)
+    {
+      dump_tdb(tdb);
+      fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
+      return 5;
+    }
+  expect_rc =
+    (abort_classes[abort_code] == ABORT_T_NESTED_TOO_DEEP) ? 1 : 0;
+  rc = __TM_is_nested_too_deep(tdb);
+  if (rc != expect_rc)
+    {
+      dump_tdb(tdb);
+      fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
+      return 6;
+    }
+  expect_rc = (abort_classes[abort_code] == ABORT_T_CONFLICT) ? 1 : 0;
+  rc = __TM_is_conflict(tdb);
+  if (rc != expect_rc)
+    {
+      dump_tdb(tdb);
+      fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
+      return 7;
+    }
+
+  return 0;
+}
+
+/* ---------------------------- local test functions ----------------------- */
+
+/* Not a test; make sure that the involved global cachelines are reserved for
+ * writing.  */
+static int init_cache(void)
+{
+  make_fake_tdb(&local_tdb);
+  make_fake_tdb(&local_tdb256);
+  global_int = 0;
+  global_u64 = 0;
+  global_float_1 = 1.0;
+  global_float_2 = 2.5;
+  global_float_3 = 0.0;
+  counters.c1 = 0;
+  counters.c2 = 0;
+  counters.c3 = 0;
+
+  return 0;
+}
+
+static int test_abort_classification(void)
+{
+  int i;
+
+  make_fake_tdb(&local_tdb);
+  for (i = 0; i <= 256; i++)
+    {
+      int rc;
+
+      local_tdb.abort_code = (uint64_t)i;
+      rc = check_abort_code_in_tdb(&local_tdb, (uint64_t)i);
+      if (rc != 0)
+       {
+         return 100 * i + rc;
+       }
+    }
+
+  return 0;
+}
+
+static int test_cc_classification(void)
+{
+  long rc;
+
+  rc = __TM_is_failure_persistent(0);
+  if (rc != 0)
+    {
+      return 1;
+    }
+  rc = __TM_is_failure_persistent(1);
+  if (rc != 0)
+    {
+      return 2;
+    }
+  rc = __TM_is_failure_persistent(2);
+  if (rc != 0)
+    {
+      return 3;
+    }
+  rc = __TM_is_failure_persistent(3);
+  if (rc != 1)
+    {
+      return 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_ntstg_tend(void)
+{
+  long rc;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  if ((rc = __TM_simple_begin()) == 0)
+    {
+      __TM_non_transactional_store((uint64_t *)&counters.c1, 1);
+      counters.c2 = 2;
+      rc = __TM_end();
+      if (rc != 0)
+       {
+         return 100 * rc + 5;
+       }
+      if (counters.c1 != 1)
+       {
+         return 100 * counters.c1 + 2;
+       }
+      if (counters.c2 != 2)
+       {
+         return 100 * counters.c2 + 3;
+       }
+    }
+  else
+    {
+      return 100 * rc + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_ntstg_tabort(void)
+{
+  register float f;
+
+  counters.c1 = 0;
+  counters.c2 = 0;
+  f = 0;
+  if (__TM_simple_begin() == 0)
+    {
+      __TM_non_transactional_store((uint64_t *)&counters.c1, 1);
+      counters.c2 = 2;
+      f = 1;
+      __TM_named_abort(0);
+      return 1;
+    }
+  if (counters.c1 != 1)
+    {
+      return 100 * counters.c1 + 2;
+    }
+  if (counters.c2 != 0)
+    {
+      return 100 * counters.c2 + 3;
+    }
+  if (f != 0)
+    {
+      return 100 * f + 4;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_aborts(void)
+{
+  float f;
+  long rc;
+
+  f = 77;
+  if ((rc = __TM_simple_begin()) == 0)
+    {
+      f = 88;
+      __TM_abort();
+      return 2;
+    }
+  else if (rc != 2)
+    {
+      return 3;
+    }
+  if (f != 77)
+    {
+      return 4;
+    }
+  f = 66;
+  if ((rc = __TM_simple_begin()) == 0)
+    {
+      f = 99;
+      __TM_named_abort(3);
+      return 5;
+    }
+  else if (rc != 3)
+    {
+      return 100 * rc + 6;
+    }
+  if (f != 66)
+    {
+      return 100 * f + 7;
+    }
+  if ((rc = __TM_simple_begin()) == 0)
+    {
+      global_float_3 = global_float_1 + global_float_2;
+      rc = __TM_end();
+      if (rc != 0)
+       {
+         return 100 * rc + 8;
+       }
+    }
+  else
+    {
+      return 100 * rc + 9;
+    }
+  if (global_float_3 != global_float_1 + global_float_2)
+    {
+      return 100 * rc + 10;
+    }
+
+  return 0;
+}
+
+static int test_tbegin_tdb(void)
+{
+  long rc;
+
+  local_tdb.format = 0;
+  if ((rc = __TM_begin(&local_tdb)) == 0)
+    {
+      rc = __TM_end();
+      if (rc != 0)
+       {
+         return 100 * rc + 1;
+       }
+      if (local_tdb.format != 0)
+       {
+         dump_tdb(&local_tdb);
+         return 100 * local_tdb.format + 2;
+       }
+    }
+  else
+    {
+      return 100 * rc + 3;
+    }
+  local_tdb.format = 0;
+  if ((rc = __TM_begin(&local_tdb)) == 0)
+    {
+      __TM_named_abort(1);
+      return 4;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 100 * rc + 5;
+       }
+      if (local_tdb.format != 1)
+       {
+         dump_tdb(&local_tdb);
+         return 100 * local_tdb.format + 6;
+       }
+    }
+  local_tdb256.format = 0;
+  if ((rc = __TM_begin(&local_tdb256)) == 0)
+    {
+      rc = __TM_end();
+      if (rc != 0)
+       {
+         return 1100 * rc + 1;
+       }
+      if (local_tdb256.format != 0)
+       {
+         dump_tdb(&local_tdb256);
+         return 1100 * local_tdb256.format + 2;
+       }
+    }
+  else
+    {
+      return 1100 * rc + 3;
+    }
+#if 1 /*!!!does not work*/
+  local_tdb256.format = 0;
+  if ((rc = __TM_begin(&local_tdb256)) == 0)
+    {
+      __TM_named_abort(1);
+      return 2004;
+    }
+  else
+    {
+      if (rc != 3)
+       {
+         return 2100 * rc + 5;
+       }
+      if (local_tdb256.format != 1)
+       {
+         dump_tdb(&local_tdb256);
+         return 2100 * local_tdb256.format + 6;
+       }
+    }
+#endif
+
+  return 0;
+}
+
+static int test_etnd(void)
+{
+  long rc;
+
+  {
+    long nd;
+
+    make_fake_tdb(&local_tdb);
+    local_tdb.nesting_depth = 0;
+    nd = __TM_nesting_depth(&local_tdb);
+    if (nd != 0)
+      {
+       return 1;
+      }
+    local_tdb.nesting_depth = 7;
+    nd = __TM_nesting_depth(&local_tdb);
+    if (nd != 7)
+      {
+       return 7;
+      }
+    local_tdb.format = 0;
+    nd = __TM_nesting_depth(&local_tdb);
+    if (nd != 0)
+      {
+       return 2;
+      }
+  }
+  counters.c1 = 0;
+  counters.c1 = 0;
+  counters.c2 = 0;
+  counters.c3 = 0;
+  if ((rc = __TM_simple_begin()) == 0)
+    {
+      counters.c1 = __TM_nesting_depth(0);
+      if (__TM_simple_begin() == 0)
+       {
+         counters.c2 = __TM_nesting_depth(0);
+         if (__TM_simple_begin() == 0)
+           {
+             counters.c3 = __TM_nesting_depth(0);
+             __TM_end();
+           }
+         __TM_end();
+       }
+      __TM_end();
+    }
+  else
+    {
+      return 100 * rc + 1;
+    }
+  if (counters.c1 != 1)
+    {
+      return 100 * counters.c1 + 2;
+    }
+  if (counters.c2 != 2)
+    {
+      return 100 * counters.c2 + 3;
+    }
+  if (counters.c3 != 3)
+    {
+      return 100 * counters.c3 + 4;
+    }
+
+  return 0;
+}
+
+/* ---------------------------- local testing framework functions ---------- */
+
+static int run_one_test(const test_table_entry_t *test_entry)
+{
+  int do_print_passes;
+  int succeeded;
+  int rc;
+  int i;
+
+  do_print_passes = (
+                    test_entry->required_quorum != 1 ||
+                    test_entry->max_repetitions != 1);
+  printf("RRR RUN  %s\n", test_entry->name);
+  if (do_print_passes == 1)
+    {
+      printf(
+            "         (requires %d successful out of %d runs)\n",
+            test_entry->required_quorum,
+            test_entry->max_repetitions);
+    }
+  succeeded = 0;
+  rc = 0;
+  for (rc = 0, i = 0; i < test_entry->max_repetitions; i++)
+    {
+      if (do_print_passes == 1)
+       {
+         if (i == 0)
+           {
+             printf("        ");
+           }
+         else
+           {
+             printf(",");
+           }
+       }
+      rc = test_entry->test_func();
+      if (rc == 0)
+       {
+         if (do_print_passes == 1)
+           {
+             printf(" success");
+           }
+         succeeded++;
+         if (succeeded >= test_entry->required_quorum)
+           {
+             break;
+           }
+       }
+      else
+       {
+         printf(" failed (rc = %d)", rc);
+       }
+    }
+  if (do_print_passes == 1 || rc != 0)
+    {
+      printf("\n");
+    }
+  if (succeeded >= test_entry->required_quorum)
+    {
+      printf("+++ OK   %s\n", test_entry->name);
+
+      return 0;
+    }
+  else
+    {
+      printf("--- FAIL %s\n", test_entry->name);
+
+      return (rc != 0) ? rc : -1;
+    }
+}
+
+static int run_all_tests(const test_table_entry_t *test_table)
+{
+  const test_table_entry_t *test;
+  int rc;
+
+  for (
+       rc = 0, test = &test_table[0];
+       test->test_func != NULL && rc == 0; test++)
+    {
+      rc = run_one_test(test);
+    }
+
+  return rc;
+}
+
+/* ---------------------------- interface functions ------------------------ */
+
+int main(void)
+{
+  const test_table_entry_t test_table[] = {
+    TEST_NO_REP(init_cache),
+    TEST_NO_REP(test_abort_classification),
+    TEST_NO_REP(test_cc_classification),
+    TEST_DF_REP(test_tbegin_ntstg_tend),
+    TEST_DF_REP(test_tbegin_ntstg_tabort),
+    TEST_DF_REP(test_tbegin_aborts),
+    TEST_DF_REP(test_tbegin_tdb),
+    TEST_DF_REP(test_etnd),
+    { (void *)0, 0, 0 }
+  };
+
+  {
+    int rc;
+
+    rc = run_all_tests(test_table);
+
+    return rc;
+  }
+}
diff --git a/gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c b/gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c
new file mode 100644 (file)
index 0000000..c1b98e2
--- /dev/null
@@ -0,0 +1,164 @@
+/* This checks the availability of the low-level builtins introduced
+   for transactional execution.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=zEC12 -mzarch" } */
+
+#include <stdint.h>
+#include <htmintrin.h>
+
+int global = 0;
+uint64_t g;
+struct __htm_tdb global_tdb;
+
+int
+foo (struct __htm_tdb* tdb, int reg, int *mem, uint64_t *mem64)
+{
+
+  int cc;
+  int n;
+
+  __builtin_tbegin ((void *)0);
+  __builtin_tbegin ((void *)-99999);
+  __builtin_tbegin ((void *)99999);
+  while (__builtin_tbegin ((void *)0) != 0)
+  {
+  }
+  cc = __builtin_tbegin ((void *)0x12345678);
+  cc = __builtin_tbegin (tdb);
+  cc = __builtin_tbegin (&global_tdb);
+  cc = __builtin_tbegin ((void *)(long long)(reg + 0x12345678));
+  cc = __builtin_tbegin ((void *)(long long)(reg));
+
+  __builtin_tbegin_nofloat ((void *)0);
+  __builtin_tbegin_nofloat ((void *)-99999);
+  __builtin_tbegin_nofloat ((void *)99999);
+  cc = __builtin_tbegin_nofloat ((void *)0x12345678);
+  cc = __builtin_tbegin_nofloat (tdb);
+  cc = __builtin_tbegin_nofloat (&global_tdb);
+  cc = __builtin_tbegin_nofloat ((void *)(long long)(reg + 0x12345678));
+  cc = __builtin_tbegin_nofloat ((void *)(long long)(reg));
+
+  __builtin_tbegin_retry ((void *)0, 0);
+  cc = __builtin_tbegin_retry ((void *)0, 1);
+  cc = __builtin_tbegin_retry ((void *)0, -1);
+  cc = __builtin_tbegin_retry ((void *)0, 42);
+  cc = __builtin_tbegin_retry ((void *)0, reg);
+  cc = __builtin_tbegin_retry ((void *)0, *mem);
+  cc = __builtin_tbegin_retry ((void *)0, global);
+  cc = __builtin_tbegin_retry (tdb, 42);
+  cc = __builtin_tbegin_retry (&global_tdb, 42);
+  cc = __builtin_tbegin_retry ((void *)0x12345678, global);
+  cc = __builtin_tbegin_retry (
+         (void *)(long long) (reg + 0x12345678), global + 1);
+  cc = __builtin_tbegin_retry (
+         (void *)(long long)(reg), global - 1);
+
+  __builtin_tbegin_retry_nofloat ((void *)0, 0);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0, 1);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0, -1);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0, 42);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0, reg);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0, *mem);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0, global);
+  cc = __builtin_tbegin_retry_nofloat (tdb, 42);
+  cc = __builtin_tbegin_retry_nofloat (&global_tdb, 42);
+  cc = __builtin_tbegin_retry_nofloat ((void *)0x12345678, global);
+  cc = __builtin_tbegin_retry_nofloat (
+         (void *)(long long) (reg + 0x12345678), global + 1);
+  cc = __builtin_tbegin_retry_nofloat (
+         (void *)(long long)(reg), global - 1);
+
+  __builtin_tbeginc ();
+
+  __builtin_tx_nesting_depth ();
+  n = __builtin_tx_nesting_depth ();
+
+  __builtin_non_tx_store (mem64, 0);
+  {
+         const uint64_t val_var = 0x1122334455667788;
+
+         __builtin_non_tx_store (mem64, val_var);
+  }
+  __builtin_non_tx_store (mem64, (uint64_t)reg);
+  __builtin_non_tx_store (mem64, g);
+  __builtin_non_tx_store ((uint64_t *)0, 0);
+  __builtin_non_tx_store ((uint64_t *)0x12345678, 0);
+  __builtin_non_tx_store (&g, 23);
+  __builtin_non_tx_store (&g, reg);
+  __builtin_non_tx_store (&g, *mem);
+  __builtin_non_tx_store (&g, global);
+
+  __builtin_tend();
+
+  __builtin_tx_assist (0);
+  __builtin_tx_assist (1);
+  __builtin_tx_assist (reg);
+  __builtin_tx_assist (*mem);
+  __builtin_tx_assist (global);
+}
+
+/* The taborts must go into separate function since they are
+   "noreturn".  */
+
+void
+tabort1 ()
+{
+  __builtin_tabort (256);
+}
+
+void
+tabort2 (int reg)
+{
+  __builtin_tabort (reg);
+}
+
+void
+tabort3 (int reg)
+{
+  /* { dg-final { scan-assembler-times "tabort\t255" 1 } } */
+  __builtin_tabort (reg + 255);
+}
+
+void
+tabort4 (int *mem)
+{
+  __builtin_tabort (*mem);
+}
+
+void
+tabort5 ()
+{
+  __builtin_tabort (global);
+}
+
+void
+tabort6 (int *mem)
+{
+  /* Here global + 255 gets reloaded into a reg.  Better would be to
+     just reload global or *mem and get the +255 for free as address
+     arithmetic.  */
+  __builtin_tabort (*mem + 255);
+}
+
+void
+tabort7 ()
+{
+  __builtin_tabort (global + 255);
+}
+
+void
+tabort8 ()
+{
+  __builtin_tabort (-1);
+}
+
+
+/* Make sure the tdb NULL argument ends up as immediate value in the
+   instruction.  */
+/* { dg-final { scan-assembler-times "tbegin\t0," 17 } } */
+/* { dg-final { scan-assembler-times "tbegin\t" 41 } } */
+/* Check number of occurences of certain instructions.  */
+/* { dg-final { scan-assembler-times "tbeginc\t" 1 } } */
+/* { dg-final { scan-assembler-times "tabort\t" 8 } } */
+/* { dg-final { scan-assembler "ppa\t" } } */
diff --git a/gcc/testsuite/gcc.target/s390/htm-builtins-compile-2.c b/gcc/testsuite/gcc.target/s390/htm-builtins-compile-2.c
new file mode 100644 (file)
index 0000000..67d76a6
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=zEC12 -mzarch" } */
+
+void must_not_compile1 (void)
+{
+  __builtin_tabort (0); /* { dg-error "Invalid transaction abort code:" } */
+}
+
+void must_not_compile2 (void)
+{
+  __builtin_tabort (255); /* { dg-error "Invalid transaction abort code:" } */
+}
index a4a6609cb01307fcd3e59c2eca6cb027af811b7d..f7f9ad25607d3ab97a562b5976aa42b312c79fb0 100644 (file)
@@ -24,6 +24,19 @@ if ![istarget s390*-*-*] then {
 # Load support procs.
 load_lib gcc-dg.exp
 
+# Return 1 if htm (etnd - extract nesting depth) instructions can be
+# compiled.
+proc check_effective_target_htm { } {
+    if { ![check_runtime s390_check_htm [subst {
+       int main (void)
+       {
+           unsigned int nd = 77;
+           asm (".insn rre,0xb2ec0000,%0,0" : "=d" (nd));
+           return nd;
+       }
+    }]] } { return 0 } else { return 1 }
+}
+
 # If a testcase doesn't have special options, use these.
 global DEFAULT_CFLAGS
 if ![info exists DEFAULT_CFLAGS] then {