This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] S/390: More htm testcases plus some fixes


Hi,

Dominik wrote several execution testcases for the GCC testsuite.
Unfortunately they revealed a few issues with our current
implementation :(

The attached patch adds the testcase as well as the required fixes in
the S/390 backend.

With the patch the htm-nofloat-2 testcase fails.  Due to the
"returns_twice" flag on tbegin the optimizers fail to fold the
compares of the condition code and the s390_optimize_nonescaping_tx
routine in turn fails to optimize the simple transactions.  This will
hopefully be fixed with a follow-on patch.

I've run regression tests on z196, zEC12 with 32 and 64 bit. All fine
(except htm-nofloat-2).

I'll commit the patch to mainline and 4.8 after waiting a few days for
comments.

Bye,

-Andreas-


2013-11-18  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-18  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.

---
 gcc/config/s390/htmxlintrin.h                          |   25 
 gcc/config/s390/s390.c                                 |   44 
 gcc/config/s390/s390.md                                |   32 
 gcc/testsuite/gcc.target/s390/htm-1.c                  |   73 -
 gcc/testsuite/gcc.target/s390/htm-builtins-1.c         | 1073 +++++++++++++++++
 gcc/testsuite/gcc.target/s390/htm-builtins-2.c         |  682 ++++++++++
 gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c |  164 ++
 gcc/testsuite/gcc.target/s390/htm-builtins-compile-2.c |   12 
 gcc/testsuite/gcc.target/s390/htm-builtins-compile-3.c |   37 
 gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c        |   37 
 gcc/testsuite/gcc.target/s390/s390.exp                 |   13 
 11 files changed, 1997 insertions(+), 114 deletions(-), 81 modifications(!)

Index: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig
--- gcc/config/s390/s390.c
*************** s390_canonicalize_comparison (int *code,
*** 895,901 ****
  	{
  	  /* For CCRAWmode put the required cc mask into the second
  	     operand.  */
! 	  if (GET_MODE (XVECEXP (*op0, 0, 0)) == CCRAWmode)
  	    *op1 = gen_rtx_CONST_INT (VOIDmode, 1 << (3 - INTVAL (*op1)));
  	  *op0 = XVECEXP (*op0, 0, 0);
  	  *code = new_code;
--- 895,902 ----
  	{
  	  /* For CCRAWmode put the required cc mask into the second
  	     operand.  */
!         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;
*************** s390_optimize_nonescaping_tx (void)
*** 7968,7973 ****
--- 7969,7977 ----
      {
        bb = BASIC_BLOCK (bb_index);
  
+       if (!bb)
+ 	continue;
+ 
        FOR_BB_INSNS (bb, insn)
  	{
  	  rtx ite, cc, pat, target;
*************** s390_optimize_nonescaping_tx (void)
*** 8081,8087 ****
    if (!result)
      return;
  
!   PATTERN (tbegin_insn) = XVECEXP (PATTERN (tbegin_insn), 0, 0);
    INSN_CODE (tbegin_insn) = -1;
    df_insn_rescan (tbegin_insn);
  
--- 8085,8094 ----
    if (!result)
      return;
  
!   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);
  
*************** s390_expand_tbegin (rtx dest, rtx tdb, r
*** 9793,9798 ****
--- 9800,9806 ----
    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;
*************** s390_expand_tbegin (rtx dest, rtx tdb, r
*** 9801,9816 ****
    if (retry != NULL_RTX)
      {
        emit_move_insn (retry_reg, retry);
        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)));
    else
!     emit_insn (gen_tbegin_nofloat_1 (tdb,
! 		 gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK)));
  
    jump = s390_emit_jump (abort_label,
  			 gen_rtx_NE (VOIDmode,
--- 9809,9825 ----
    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 (gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK), tdb));
    else
!     emit_insn (gen_tbegin_nofloat_1 (gen_rtx_CONST_INT (VOIDmode, TBEGIN_MASK),
! 				     tdb));
  
    jump = s390_emit_jump (abort_label,
  			 gen_rtx_NE (VOIDmode,
*************** s390_expand_tbegin (rtx dest, rtx tdb, r
*** 9831,9836 ****
--- 9840,9849 ----
    /* 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);
*************** s390_expand_tbegin (rtx dest, rtx tdb, r
*** 9842,9848 ****
        add_int_reg_note (jump, REG_BR_PROB, very_unlikely);
  
        /* CC2 - transient failure. Perform retry with ppa.  */
!       emit_move_insn (count, retry);
        emit_insn (gen_subsi3 (count, count, retry_reg));
        emit_insn (gen_tx_assist (count));
        jump = emit_jump_insn (gen_doloop_si64 (retry_label,
--- 9855,9861 ----
        add_int_reg_note (jump, REG_BR_PROB, very_unlikely);
  
        /* CC2 - transient failure. Perform retry with ppa.  */
!       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,
*************** s390_expand_tbegin (rtx dest, rtx tdb, r
*** 9852,9861 ****
        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);
  }
  
--- 9865,9870 ----
*************** static void
*** 9894,9899 ****
--- 9903,9911 ----
  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);
*************** s390_init_builtins (void)
*** 9904,9920 ****
    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);
    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);
    add_builtin_function ("__builtin_tbegin_nofloat", ftype,
  			S390_BUILTIN_TBEGIN_NOFLOAT,
! 			BUILT_IN_MD, NULL, NULL_TREE);
  
    /* int foo (void *, int) */
    ftype = build_function_type_list (integer_type_node, ptr_type_node,
--- 9916,9932 ----
    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, 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, returns_twice_attr);
    add_builtin_function ("__builtin_tbegin_nofloat", ftype,
  			S390_BUILTIN_TBEGIN_NOFLOAT,
! 			BUILT_IN_MD, NULL, returns_twice_attr);
  
    /* int foo (void *, int) */
    ftype = build_function_type_list (integer_type_node, ptr_type_node,
*************** s390_init_builtins (void)
*** 9922,9932 ****
    add_builtin_function ("__builtin_tbegin_retry", ftype,
  			S390_BUILTIN_TBEGIN_RETRY,
  			BUILT_IN_MD,
! 			NULL, NULL_TREE);
    add_builtin_function ("__builtin_tbegin_retry_nofloat", ftype,
  			S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
  			BUILT_IN_MD,
! 			NULL, NULL_TREE);
  
    /* int foo (void) */
    ftype = build_function_type_list (integer_type_node, NULL_TREE);
--- 9934,9944 ----
    add_builtin_function ("__builtin_tbegin_retry", ftype,
  			S390_BUILTIN_TBEGIN_RETRY,
  			BUILT_IN_MD,
! 			NULL, returns_twice_attr);
    add_builtin_function ("__builtin_tbegin_retry_nofloat", ftype,
  			S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
  			BUILT_IN_MD,
! 			NULL, returns_twice_attr);
  
    /* int foo (void) */
    ftype = build_function_type_list (integer_type_node, NULL_TREE);
Index: gcc/config/s390/s390.md
===================================================================
*** gcc/config/s390/s390.md.orig
--- gcc/config/s390/s390.md
***************
*** 155,160 ****
--- 155,161 ----
  
     ; Transactional Execution support
     UNSPECV_TBEGIN
+    UNSPECV_TBEGIN_TDB
     UNSPECV_TBEGINC
     UNSPECV_TEND
     UNSPECV_TABORT
***************
*** 9997,10005 ****
  
  (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")]
  			       UNSPECV_TBEGIN))
     (clobber (reg:DF 16))
     (clobber (reg:DF 17))
     (clobber (reg:DF 18))
--- 9998,10007 ----
  
  (define_insn "tbegin_1"
    [(set (reg:CCRAW CC_REGNUM)
! 	(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))
***************
*** 10018,10035 ****
     (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"
    [(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"
    [(set_attr "op_type" "SIL")])
  
  
--- 10020,10038 ----
     (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[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 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")])
  
  
***************
*** 10113,10127 ****
  ; 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)
  		     (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")
--- 10116,10127 ----
  ; Transaction perform processor assist
  
  (define_expand "tx_assist"
!   [(unspec_volatile [(match_operand:SI 0 "register_operand" "")
! 		     (reg:SI GPR0_REGNUM)
  		     (const_int 1)]
  		    UNSPECV_PPA)]
    "TARGET_HTM"
!   "")
  
  (define_insn "*ppa"
    [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
***************
*** 10129,10133 ****
  		     (match_operand 2 "const_int_operand" "I")]
  		    UNSPECV_PPA)]
    "TARGET_HTM && INTVAL (operands[2]) < 16"
!   "ppa\t%0,%1,1"
    [(set_attr "op_type" "RRF")])
--- 10129,10133 ----
  		     (match_operand 2 "const_int_operand" "I")]
  		    UNSPECV_PPA)]
    "TARGET_HTM && INTVAL (operands[2]) < 16"
!   "ppa\t%0,%1,%2"
    [(set_attr "op_type" "RRF")])
Index: gcc/config/s390/htmxlintrin.h
===================================================================
*** gcc/config/s390/htmxlintrin.h.orig
--- gcc/config/s390/htmxlintrin.h
*************** extern "C" {
*** 33,45 ****
     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__))
  __TM_simple_begin ()
  {
    return __builtin_tbegin_nofloat (0);
  }
  
! extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
  __TM_begin (void* const tdb)
  {
    return __builtin_tbegin_nofloat (tdb);
--- 33,52 ----
     the IBM XL compiler.  For documentation please see the "z/OS XL
     C/C++ Programming Guide" publicly available on the web.  */
  
! /* 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);
  }
  
! long
  __TM_begin (void* const tdb)
  {
    return __builtin_tbegin_nofloat (tdb);
*************** __TM_nesting_depth (void* const tdb_ptr)
*** 78,84 ****
    if (depth != 0)
      return depth;
  
!   if (tdb->format == 0)
      return 0;
    return tdb->nesting_depth;
  }
--- 85,91 ----
    if (depth != 0)
      return depth;
  
!   if (tdb->format != 1)
      return 0;
    return tdb->nesting_depth;
  }
*************** __TM_is_user_abort (void* const tdb_ptr)
*** 90,96 ****
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   if (tdb->format == 0)
      return 0;
  
    return !!(tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE);
--- 97,103 ----
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   if (tdb->format != 1)
      return 0;
  
    return !!(tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE);
*************** __TM_is_named_user_abort (void* const td
*** 101,107 ****
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   if (tdb->format == 0)
      return 0;
  
    if (tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE)
--- 108,114 ----
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   if (tdb->format != 1)
      return 0;
  
    if (tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE)
*************** __TM_is_illegal (void* const tdb_ptr)
*** 117,123 ****
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return (tdb->format == 0
  	  && (tdb->abort_code == 4 /* unfiltered program interruption */
  	      || tdb->abort_code == 11 /* restricted instruction */));
  }
--- 124,130 ----
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return (tdb->format == 1
  	  && (tdb->abort_code == 4 /* unfiltered program interruption */
  	      || tdb->abort_code == 11 /* restricted instruction */));
  }
*************** __TM_is_footprint_exceeded (void* const 
*** 127,133 ****
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return (tdb->format == 0
  	  && (tdb->abort_code == 7 /* fetch overflow */
  	      || tdb->abort_code == 8 /* store overflow */));
  }
--- 134,140 ----
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return (tdb->format == 1
  	  && (tdb->abort_code == 7 /* fetch overflow */
  	      || tdb->abort_code == 8 /* store overflow */));
  }
*************** __TM_is_nested_too_deep (void* const tdb
*** 137,143 ****
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return tdb->format == 0 && tdb->abort_code == 13; /* depth exceeded */
  }
  
  extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
--- 144,150 ----
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return tdb->format == 1 && tdb->abort_code == 13; /* depth exceeded */
  }
  
  extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
*************** __TM_is_conflict (void* const tdb_ptr)
*** 145,151 ****
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return (tdb->format == 0
  	  && (tdb->abort_code == 9 /* fetch conflict */
  	      || tdb->abort_code == 10 /* store conflict */));
  }
--- 152,158 ----
  {
    struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
  
!   return (tdb->format == 1
  	  && (tdb->abort_code == 9 /* fetch conflict */
  	      || tdb->abort_code == 10 /* store conflict */));
  }
Index: gcc/testsuite/gcc.target/s390/htm-builtins-1.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-builtins-1.c
***************
*** 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;
+   }
+ }
Index: gcc/testsuite/gcc.target/s390/htm-builtins-2.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-builtins-2.c
***************
*** 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;
+   }
+ }
Index: gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-builtins-compile-1.c
***************
*** 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" } } */
Index: gcc/testsuite/gcc.target/s390/htm-builtins-compile-2.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-builtins-compile-2.c
***************
*** 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: gcc/testsuite/gcc.target/s390/s390.exp
===================================================================
*** gcc/testsuite/gcc.target/s390/s390.exp.orig
--- gcc/testsuite/gcc.target/s390/s390.exp
*************** if ![istarget s390*-*-*] then {
*** 24,29 ****
--- 24,42 ----
  # 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 {
Index: gcc/testsuite/gcc.target/s390/htm-builtins-compile-3.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-builtins-compile-3.c
***************
*** 0 ****
--- 1,37 ----
+ /* This checks the availability of the XL compiler intrinsics for
+    transactional execution with the expected prototypes.  */
+ 
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -march=zEC12 -mzarch" } */
+ 
+ #include <htmxlintrin.h>
+ 
+ int a = 0;
+ unsigned long g;
+ 
+ int
+ foo ()
+ {
+   struct __htm_tdb *tdb_struct;
+   void * const tdb = tdb_struct;
+   long result;
+   unsigned char code;
+ 
+   result = __TM_simple_begin ();
+   result = __TM_begin (tdb);
+   result = __TM_end ();
+   __TM_abort ();
+   __TM_named_abort (42);
+   __TM_non_transactional_store (&g, 42);
+   result = __TM_nesting_depth (tdb);
+ 
+   result = __TM_is_user_abort (tdb);
+   result = __TM_is_named_user_abort (tdb, &code);
+   result = __TM_is_illegal (tdb);
+   result = __TM_is_footprint_exceeded (tdb);
+   result = __TM_is_nested_too_deep (tdb);
+   result = __TM_is_conflict (tdb);
+   result = __TM_is_failure_persistent (result);
+   result = __TM_failure_address (tdb);
+   result = __TM_failure_code (tdb);
+ }
Index: gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c
===================================================================
*** gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c
--- /dev/null
***************
*** 1,37 ****
- /* This checks the availability of the XL compiler intrinsics for
-    transactional execution with the expected prototypes.  */
- 
- /* { dg-do compile } */
- /* { dg-options "-O3 -march=zEC12 -mzarch" } */
- 
- #include <htmxlintrin.h>
- 
- int a = 0;
- unsigned long g;
- 
- int
- foo ()
- {
-   struct __htm_tdb *tdb_struct;
-   void * const tdb = tdb_struct;
-   long result;
-   unsigned char code;
- 
-   result = __TM_simple_begin ();
-   result = __TM_begin (tdb);
-   result = __TM_end ();
-   __TM_abort ();
-   __TM_named_abort (42);
-   __TM_non_transactional_store (&g, 42);
-   result = __TM_nesting_depth (tdb);
- 
-   result = __TM_is_user_abort (tdb);
-   result = __TM_is_named_user_abort (tdb, &code);
-   result = __TM_is_illegal (tdb);
-   result = __TM_is_footprint_exceeded (tdb);
-   result = __TM_is_nested_too_deep (tdb);
-   result = __TM_is_conflict (tdb);
-   result = __TM_is_failure_persistent (result);
-   result = __TM_failure_address (tdb);
-   result = __TM_failure_code (tdb);
- }
--- 0 ----
Index: gcc/testsuite/gcc.target/s390/htm-1.c
===================================================================
*** gcc/testsuite/gcc.target/s390/htm-1.c
--- /dev/null
***************
*** 1,73 ****
- /* 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 } } */
--- 0 ----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]