[PATCH] S/390: Hardware transactional memory support

Andreas Krebbel krebbel@linux.vnet.ibm.com
Fri Jun 21 10:23:00 GMT 2013


Hi,

the attached patch implements support for hardware transactional
memory in the S/390 backend.

The transactional execution facility has been made available with IBM
Enterprise EC12.  Documentation can be found in the Principles of
Operation manual:
http://publibfi.boulder.ibm.com/epubs/pdf/dz9zr009.pdf

The patch implements a set of GCC style builtins as well as the
builtins provided with the IBM XL compiler for compatibility reasons.

The GCC builtins are used to implement HTM support in libitm. All
libitm testcases succeed with this patch applied (and some libitm
bugfixes from Torvald Riegel).

The builtins are enabled by default when compiling with -march=zEC12.
They can be disabled with the -mno-htm switch.

Bootstrapped and regtested on s390 and s390x (configured with
--with-arch=zEC12).

Any comments?

Bye,

-Andreas-


2013-06-21  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* config/s390/s390.c: Rename UNSPEC_CCU_TO_INT to
	UNSPEC_STRCMPCC_TO_INT and UNSPEC_CCZ_TO_INT to UNSPEC_CC_TO_INT.
	(struct machine_function): Add tbegin_p.
	(s390_canonicalize_comparison): Fold CC mode compares to
	conditional jump if possible.
	(s390_emit_jump): Return the emitted jump.
	(s390_branch_condition_mask, s390_branch_condition_mnemonic):
	Handle CCRAWmode compares.
	(s390_option_override): Default to -mhtm if available.
	(s390_reg_clobbered_rtx): Handle floating point regs as well.
	(s390_regs_ever_clobbered): Use s390_regs_ever_clobbered also for
	FPRs instead of df_regs_ever_live_p.
	(s390_optimize_nonescaping_tx): New function.
	(s390_init_frame_layout): Extend clobbered_regs array to cover
	FPRs as well.
	(s390_emit_prologue): Call s390_optimize_nonescaping_tx.
	(s390_expand_tbegin): New function.
	(enum s390_builtin): New enum definition.
	(code_for_builtin): New array definition.
	(s390_init_builtins): New function.
	(s390_expand_builtin): New function.
	(TARGET_INIT_BUILTINS): Define.
	(TARGET_EXPAND_BUILTIN): Define.
	* common/config/s390/s390-common.c (processor_flags_table): Add
	PF_TX.
	* config/s390/predicates.md (s390_comparison): Handle CCRAWmode.
	(s390_alc_comparison): Likewise.
	* config/s390/s390-modes.def: Add CCRAWmode.
	* config/s390/s390.h (processor_flags): Add PF_TX.
	(TARGET_CPU_HTM): Define macro.
	(TARGET_HTM): Define macro.
	(TARGET_CPU_CPP_BUILTINS): Define __HTM__ for htm.
	* config/s390/s390.md: Rename UNSPEC_CCU_TO_INT to
	UNSPEC_STRCMPCC_TO_INT and UNSPEC_CCZ_TO_INT to UNSPEC_CC_TO_INT.
	(UNSPECV_TBEGIN, UNSPECV_TBEGINC, UNSPECV_TEND, UNSPECV_TABORT)
	(UNSPECV_ETND, UNSPECV_NTSTG, UNSPECV_PPA): New unspecv enum
	values.
	(TBEGIN_MASK, TBEGINC_MASK): New constants.
	("*cc_to_int"): Move up.
	("*mov<mode>cc", "*cjump_64", "*cjump_31"): Accept integer
	constants other than 0.
	("*ccraw_to_int"): New insn and splitter definition.
	("tbegin", "tbegin_nofloat", "tbegin_retry")
	("tbegin_retry_nofloat", "tbeginc", "tend", "tabort")
	("tx_assist"): New expander.
	("tbegin_1", "tbegin_nofloat_1", "*tbeginc_1", "*tend_1")
	("*tabort_1", "etnd", "ntstg", "*ppa"): New insn definition.
	* config/s390/s390.opt: Add -mhtm option.
	* config/s390/s390-protos.h (s390_emit_jump): Add return type.
	* config/s390/htmxlintrin.h: New file.
	* config/s390/htmintrin.h: New file.
	* config/s390/s390intrin.h: New file.
	* doc/extend.texi: Document htm builtins.
	* config.gcc: Add the new header files to extra_headers.

2013-06-21  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* config/s390/target.h: Include htmintrin.h.
	(_HTM_ITM_RETRIES): New macro definition.
	(htm_available, htm_init, htm_begin, htm_begin_success)
	(htm_commit, htm_abort, htm_abort_should_retry): New functions.

2013-06-21  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* gcc.target/s390/htm-1.c: New file.
	* gcc.target/s390/htm-nofloat-1.c: New file.
	* gcc.target/s390/htm-xl-intrin-1.c: New file.

---
 gcc/common/config/s390/s390-common.c            |    2 
 gcc/config.gcc                                  |    1 
 gcc/config/s390/htmintrin.h                     |   57 ++
 gcc/config/s390/htmxlintrin.h                   |  182 +++++++
 gcc/config/s390/predicates.md                   |   12 
 gcc/config/s390/s390-modes.def                  |    9 
 gcc/config/s390/s390-protos.h                   |    3 
 gcc/config/s390/s390.c                          |  564 ++++++++++++++++++++-!
 gcc/config/s390/s390.h                          |   37 !
 gcc/config/s390/s390.md                         |  281 ++++++++++!
 gcc/config/s390/s390.opt                        |    4 
 gcc/config/s390/s390intrin.h                    |   33 +
 gcc/doc/extend.texi                             |  115 ++++
 gcc/testsuite/gcc.target/s390/htm-1.c           |   36 +
 gcc/testsuite/gcc.target/s390/htm-nofloat-1.c   |   12 
 gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c |   37 +
 libitm/config/s390/target.h                     |   59 ++
 17 files changed, 1285 insertions(+), 22 deletions(-), 137 modifications(!)

Index: gcc/config/s390/s390.c
===================================================================
*** gcc/config/s390/s390.c.orig
--- gcc/config/s390/s390.c
*************** struct GTY(()) machine_function
*** 367,372 ****
--- 367,376 ----
    const char *some_ld_name;
  
    bool has_landing_pad_p;
+ 
+   /* True if the current function may contain a tbegin clobbering
+      FPRs.  */
+   bool tbegin_p;
  };
  
  /* Few accessor macros for struct cfun->machine->s390_frame_layout.  */
*************** s390_canonicalize_comparison (int *code,
*** 824,832 ****
        *op1 = constm1_rtx;
      }
  
!   /* Remove redundant UNSPEC_CCU_TO_INT conversions if possible.  */
    if (GET_CODE (*op0) == UNSPEC
!       && XINT (*op0, 1) == UNSPEC_CCU_TO_INT
        && XVECLEN (*op0, 0) == 1
        && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode
        && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
--- 828,836 ----
        *op1 = constm1_rtx;
      }
  
!   /* Remove redundant UNSPEC_STRCMPCC_TO_INT conversions if possible.  */
    if (GET_CODE (*op0) == UNSPEC
!       && XINT (*op0, 1) == UNSPEC_STRCMPCC_TO_INT
        && XVECLEN (*op0, 0) == 1
        && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode
        && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
*************** s390_canonicalize_comparison (int *code,
*** 852,876 ****
  	}
      }
  
!   /* Remove redundant UNSPEC_CCZ_TO_INT conversions if possible.  */
    if (GET_CODE (*op0) == UNSPEC
!       && XINT (*op0, 1) == UNSPEC_CCZ_TO_INT
        && XVECLEN (*op0, 0) == 1
-       && GET_MODE (XVECEXP (*op0, 0, 0)) == CCZmode
        && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
        && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM
!       && *op1 == const0_rtx)
      {
        enum rtx_code new_code = UNKNOWN;
!       switch (*code)
  	{
! 	  case EQ: new_code = EQ;  break;
! 	  case NE: new_code = NE;  break;
! 	  default: break;
  	}
  
        if (new_code != UNKNOWN)
  	{
  	  *op0 = XVECEXP (*op0, 0, 0);
  	  *code = new_code;
  	}
--- 856,890 ----
  	}
      }
  
!   /* Remove redundant UNSPEC_CC_TO_INT conversions if possible.  */
    if (GET_CODE (*op0) == UNSPEC
!       && XINT (*op0, 1) == UNSPEC_CC_TO_INT
        && XVECLEN (*op0, 0) == 1
        && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
        && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM
!       && CONST_INT_P (*op1))
      {
        enum rtx_code new_code = UNKNOWN;
!       switch (GET_MODE (XVECEXP (*op0, 0, 0)))
  	{
! 	case CCZmode:
! 	case CCRAWmode:
! 	  switch (*code)
! 	    {
! 	    case EQ: new_code = EQ;  break;
! 	    case NE: new_code = NE;  break;
! 	    default: break;
! 	    }
! 	  break;
! 	default: break;
  	}
  
        if (new_code != UNKNOWN)
  	{
+ 	  /* 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;
  	}
*************** s390_emit_compare_and_swap (enum rtx_cod
*** 942,951 ****
  			    const0_rtx);
  }
  
! /* Emit a jump instruction to TARGET.  If COND is NULL_RTX, emit an
!    unconditional jump, else a conditional jump under condition COND.  */
  
! void
  s390_emit_jump (rtx target, rtx cond)
  {
    rtx insn;
--- 956,966 ----
  			    const0_rtx);
  }
  
! /* Emit a jump instruction to TARGET and return it.  If COND is
!    NULL_RTX, emit an unconditional jump, else a conditional jump under
!    condition COND.  */
  
! rtx
  s390_emit_jump (rtx target, rtx cond)
  {
    rtx insn;
*************** s390_emit_jump (rtx target, rtx cond)
*** 955,961 ****
      target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx);
  
    insn = gen_rtx_SET (VOIDmode, pc_rtx, target);
!   emit_jump_insn (insn);
  }
  
  /* Return branch condition mask to implement a branch
--- 970,976 ----
      target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx);
  
    insn = gen_rtx_SET (VOIDmode, pc_rtx, target);
!   return emit_jump_insn (insn);
  }
  
  /* Return branch condition mask to implement a branch
*************** s390_branch_condition_mask (rtx code)
*** 971,977 ****
  
    gcc_assert (GET_CODE (XEXP (code, 0)) == REG);
    gcc_assert (REGNO (XEXP (code, 0)) == CC_REGNUM);
!   gcc_assert (XEXP (code, 1) == const0_rtx);
  
    switch (GET_MODE (XEXP (code, 0)))
      {
--- 986,995 ----
  
    gcc_assert (GET_CODE (XEXP (code, 0)) == REG);
    gcc_assert (REGNO (XEXP (code, 0)) == CC_REGNUM);
!   gcc_assert (XEXP (code, 1) == const0_rtx
! 	      || (GET_MODE (XEXP (code, 0)) == CCRAWmode
! 		  && CONST_INT_P (XEXP (code, 1))));
! 
  
    switch (GET_MODE (XEXP (code, 0)))
      {
*************** s390_branch_condition_mask (rtx code)
*** 1145,1150 ****
--- 1163,1179 ----
          }
        break;
  
+     case CCRAWmode:
+       switch (GET_CODE (code))
+ 	{
+ 	case EQ:
+ 	  return INTVAL (XEXP (code, 1));
+ 	case NE:
+ 	  return (INTVAL (XEXP (code, 1))) ^ 0xf;
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+ 
      default:
        return -1;
      }
*************** s390_branch_condition_mnemonic (rtx code
*** 1204,1210 ****
  
    if (GET_CODE (XEXP (code, 0)) == REG
        && REGNO (XEXP (code, 0)) == CC_REGNUM
!       && XEXP (code, 1) == const0_rtx)
      mask = s390_branch_condition_mask (code);
    else
      mask = s390_compare_and_branch_condition_mask (code);
--- 1233,1241 ----
  
    if (GET_CODE (XEXP (code, 0)) == REG
        && REGNO (XEXP (code, 0)) == CC_REGNUM
!       && (XEXP (code, 1) == const0_rtx
! 	  || (GET_MODE (XEXP (code, 0)) == CCRAWmode
! 	      && CONST_INT_P (XEXP (code, 1)))))
      mask = s390_branch_condition_mask (code);
    else
      mask = s390_compare_and_branch_condition_mask (code);
*************** s390_option_override (void)
*** 1602,1607 ****
--- 1633,1643 ----
    if (!(target_flags_explicit & MASK_HARD_DFP) && TARGET_DFP)
      target_flags |= MASK_HARD_DFP;
  
+   /* Enable hardware transactions if available and not explicitly
+      disabled by user.  E.g. with -m31 -march=zEC12 -mzarch */
+   if (!(target_flags_explicit & MASK_OPT_HTM) && TARGET_CPU_HTM && TARGET_ZARCH)
+     target_flags |= MASK_OPT_HTM;
+ 
    if (TARGET_HARD_DFP && !TARGET_DFP)
      {
        if (target_flags_explicit & MASK_HARD_DFP)
*************** s390_reg_clobbered_rtx (rtx setreg, cons
*** 7334,7344 ****
    if (GET_CODE (setreg) == SUBREG)
      {
        rtx inner = SUBREG_REG (setreg);
!       if (!GENERAL_REG_P (inner))
  	return;
        regno = subreg_regno (setreg);
      }
!   else if (GENERAL_REG_P (setreg))
      regno = REGNO (setreg);
    else
      return;
--- 7370,7380 ----
    if (GET_CODE (setreg) == SUBREG)
      {
        rtx inner = SUBREG_REG (setreg);
!       if (!GENERAL_REG_P (inner) && !FP_REG_P (inner))
  	return;
        regno = subreg_regno (setreg);
      }
!   else if (GENERAL_REG_P (setreg) || FP_REG_P (setreg))
      regno = REGNO (setreg);
    else
      return;
*************** s390_regs_ever_clobbered (int *regs_ever
*** 7361,7373 ****
    rtx cur_insn;
    unsigned int i;
  
!   memset (regs_ever_clobbered, 0, 16 * sizeof (int));
  
    /* For non-leaf functions we have to consider all call clobbered regs to be
       clobbered.  */
    if (!crtl->is_leaf)
      {
!       for (i = 0; i < 16; i++)
  	regs_ever_clobbered[i] = call_really_used_regs[i];
      }
  
--- 7397,7409 ----
    rtx cur_insn;
    unsigned int i;
  
!   memset (regs_ever_clobbered, 0, 32 * sizeof (int));
  
    /* For non-leaf functions we have to consider all call clobbered regs to be
       clobbered.  */
    if (!crtl->is_leaf)
      {
!       for (i = 0; i < 32; i++)
  	regs_ever_clobbered[i] = call_really_used_regs[i];
      }
  
*************** s390_regs_ever_clobbered (int *regs_ever
*** 7389,7395 ****
       See expand_builtin_unwind_init.  For regs_ever_live this is done by
       reload.  */
    if (cfun->has_nonlocal_label)
!     for (i = 0; i < 16; i++)
        if (!call_really_used_regs[i])
  	regs_ever_clobbered[i] = 1;
  
--- 7425,7431 ----
       See expand_builtin_unwind_init.  For regs_ever_live this is done by
       reload.  */
    if (cfun->has_nonlocal_label)
!     for (i = 0; i < 32; i++)
        if (!call_really_used_regs[i])
  	regs_ever_clobbered[i] = 1;
  
*************** s390_register_info (int clobbered_regs[]
*** 7455,7471 ****
  {
    int i, j;
  
-   /* fprs 8 - 15 are call saved for 64 Bit ABI.  */
-   cfun_frame_layout.fpr_bitmap = 0;
-   cfun_frame_layout.high_fprs = 0;
-   if (TARGET_64BIT)
-     for (i = 24; i < 32; i++)
-       if (df_regs_ever_live_p (i) && !global_regs[i])
- 	{
- 	  cfun_set_fpr_bit (i - 16);
- 	  cfun_frame_layout.high_fprs++;
- 	}
- 
    /* Find first and last gpr to be saved.  We trust regs_ever_live
       data, except that we don't save and restore global registers.
  
--- 7491,7496 ----
*************** s390_register_info (int clobbered_regs[]
*** 7474,7479 ****
--- 7499,7527 ----
  
    s390_regs_ever_clobbered (clobbered_regs);
  
+   /* fprs 8 - 15 are call saved for 64 Bit ABI.  */
+   if (!epilogue_completed)
+     {
+       cfun_frame_layout.fpr_bitmap = 0;
+       cfun_frame_layout.high_fprs = 0;
+       if (TARGET_64BIT)
+ 	for (i = 24; i < 32; i++)
+ 	  /* During reload we have to use the df_regs_ever_live infos
+ 	     since reload is marking FPRs used as spill slots there as
+ 	     live before actually making the code changes.  Without
+ 	     this we fail during elimination offset verification.  */
+ 	  if ((clobbered_regs[i]
+ 	       || (df_regs_ever_live_p (i)
+ 		   && (lra_in_progress
+ 		       || reload_in_progress
+ 		       || crtl->saves_all_registers)))
+ 	      && !global_regs[i])
+ 	    {
+ 	      cfun_set_fpr_bit (i - 16);
+ 	      cfun_frame_layout.high_fprs++;
+ 	    }
+     }
+ 
    for (i = 0; i < 16; i++)
      clobbered_regs[i] = clobbered_regs[i] && !global_regs[i] && !fixed_regs[i];
  
*************** s390_init_frame_layout (void)
*** 7724,7730 ****
  {
    HOST_WIDE_INT frame_size;
    int base_used;
!   int clobbered_regs[16];
  
    /* On S/390 machines, we may need to perform branch splitting, which
       will require both base and return address register.  We have no
--- 7772,7778 ----
  {
    HOST_WIDE_INT frame_size;
    int base_used;
!   int clobbered_regs[32];
  
    /* On S/390 machines, we may need to perform branch splitting, which
       will require both base and return address register.  We have no
*************** s390_init_frame_layout (void)
*** 7759,7764 ****
--- 7807,7963 ----
    while (frame_size != cfun_frame_layout.frame_size);
  }
  
+ /* Remove the FPR clobbers from a tbegin insn if it can be proven that
+    the TX is nonescaping.  A transaction is considered escaping if
+    there is at least one path from tbegin returning CC0 to the
+    function exit block without an tend.
+ 
+    The check so far has some limitations:
+    - only single tbegin/tend BBs are supported
+    - the first cond jump after tbegin must separate the CC0 path from ~CC0
+    - when CC is copied to a GPR and the CC0 check is done with the GPR
+      this is not supported
+ */
+ 
+ static void
+ s390_optimize_nonescaping_tx (void)
+ {
+   const unsigned int CC0 = 1 << 3;
+   basic_block tbegin_bb = NULL;
+   basic_block tend_bb = NULL;
+   basic_block bb;
+   rtx insn;
+   bool result = true;
+   int bb_index;
+   rtx tbegin_insn = NULL_RTX;
+ 
+   if (!cfun->machine->tbegin_p)
+     return;
+ 
+   for (bb_index = 0; bb_index < n_basic_blocks; bb_index++)
+     {
+       bb = BASIC_BLOCK (bb_index);
+ 
+       FOR_BB_INSNS (bb, insn)
+ 	{
+ 	  rtx ite, cc, pat, target;
+ 	  unsigned HOST_WIDE_INT mask;
+ 
+ 	  if (!INSN_P (insn) || INSN_CODE (insn) <= 0)
+ 	    continue;
+ 
+ 	  pat = PATTERN (insn);
+ 
+ 	  if (GET_CODE (pat) == PARALLEL)
+ 	    pat = XVECEXP (pat, 0, 0);
+ 
+ 	  if (GET_CODE (pat) != SET
+ 	      || GET_CODE (SET_SRC (pat)) != UNSPEC_VOLATILE)
+ 	    continue;
+ 
+ 	  if (XINT (SET_SRC (pat), 1) == UNSPECV_TBEGIN)
+ 	    {
+ 	      rtx tmp;
+ 
+ 	      tbegin_insn = insn;
+ 
+ 	      /* Just return if the tbegin doesn't have clobbers.  */
+ 	      if (GET_CODE (PATTERN (insn)) != PARALLEL)
+ 		return;
+ 
+ 	      if (tbegin_bb != NULL)
+ 		return;
+ 
+ 	      /* Find the next conditional jump.  */
+ 	      for (tmp = NEXT_INSN (insn);
+ 		   tmp != NULL_RTX;
+ 		   tmp = NEXT_INSN (tmp))
+ 		{
+ 		  if (reg_set_p (gen_rtx_REG (CCmode, CC_REGNUM), tmp))
+ 		    return;
+ 		  if (!JUMP_P (tmp))
+ 		    continue;
+ 
+ 		  ite = SET_SRC (PATTERN (tmp));
+ 		  if (GET_CODE (ite) != IF_THEN_ELSE)
+ 		    continue;
+ 
+ 		  cc = XEXP (XEXP (ite, 0), 0);
+ 		  if (!REG_P (cc) || !CC_REGNO_P (REGNO (cc))
+ 		      || GET_MODE (cc) != CCRAWmode
+ 		      || GET_CODE (XEXP (XEXP (ite, 0), 1)) != CONST_INT)
+ 		    return;
+ 
+ 		  if (bb->succs->length () != 2)
+ 		    return;
+ 
+ 		  mask = INTVAL (XEXP (XEXP (ite, 0), 1));
+ 		  if (GET_CODE (XEXP (ite, 0)) == NE)
+ 		    mask ^= 0xf;
+ 
+ 		  if (mask == CC0)
+ 		    target = XEXP (ite, 1);
+ 		  else if (mask == (CC0 ^ 0xf))
+ 		    target = XEXP (ite, 2);
+ 		  else
+ 		    return;
+ 
+ 		  {
+ 		    edge_iterator ei;
+ 		    edge e1, e2;
+ 
+ 		    ei = ei_start (bb->succs);
+ 		    e1 = ei_safe_edge (ei);
+ 		    ei_next (&ei);
+ 		    e2 = ei_safe_edge (ei);
+ 
+ 		    if (e2->flags & EDGE_FALLTHRU)
+ 		      {
+ 			e2 = e1;
+ 			e1 = ei_safe_edge (ei);
+ 		      }
+ 
+ 		    if (!(e1->flags & EDGE_FALLTHRU))
+ 		      return;
+ 
+ 		    tbegin_bb = (target == pc_rtx) ? e1->dest : e2->dest;
+ 		  }
+ 		  if (tmp == BB_END (bb))
+ 		    break;
+ 		}
+ 	    }
+ 
+ 	  if (XINT (SET_SRC (pat), 1) == UNSPECV_TEND)
+ 	    {
+ 	      if (tend_bb != NULL)
+ 		return;
+ 	      tend_bb = bb;
+ 	    }
+ 	}
+     }
+ 
+   /* Either we successfully remove the FPR clobbers here or we are not
+      able to do anything for this TX.  Both cases don't qualify for
+      another look.  */
+   cfun->machine->tbegin_p = false;
+ 
+   if (tbegin_bb == NULL || tend_bb == NULL)
+     return;
+ 
+   calculate_dominance_info (CDI_POST_DOMINATORS);
+   result = dominated_by_p (CDI_POST_DOMINATORS, tbegin_bb, tend_bb);
+   free_dominance_info (CDI_POST_DOMINATORS);
+ 
+   if (!result)
+     return;
+ 
+   PATTERN (tbegin_insn) = XVECEXP (PATTERN (tbegin_insn), 0, 0);
+   INSN_CODE (tbegin_insn) = -1;
+   df_insn_rescan (tbegin_insn);
+ 
+   return;
+ }
+ 
  /* Update frame layout.  Recompute actual register save data based on
     current info and update regs_ever_live for the special registers.
     May be called multiple times, but may never cause *more* registers
*************** s390_init_frame_layout (void)
*** 7767,7773 ****
  static void
  s390_update_frame_layout (void)
  {
!   int clobbered_regs[16];
  
    s390_register_info (clobbered_regs);
  
--- 7966,7972 ----
  static void
  s390_update_frame_layout (void)
  {
!   int clobbered_regs[32];
  
    s390_register_info (clobbered_regs);
  
*************** s390_emit_prologue (void)
*** 8204,8211 ****
    int offset;
    int next_fpr = 0;
  
!   /* Complete frame layout.  */
  
    s390_update_frame_layout ();
  
    /* Annotate all constant pool references to let the scheduler know
--- 8403,8412 ----
    int offset;
    int next_fpr = 0;
  
!   /* Try to get rid of the FPR clobbers.  */
!   s390_optimize_nonescaping_tx ();
  
+   /* Complete frame layout.  */
    s390_update_frame_layout ();
  
    /* Annotate all constant pool references to let the scheduler know
*************** s390_gimplify_va_arg (tree valist, tree
*** 9353,9358 ****
--- 9554,9847 ----
    return build_va_arg_indirect_ref (addr);
  }
  
+ /* Emit rtl for the tbegin or tbegin_retry (RETRY != NULL_RTX)
+    expanders.
+    DEST  - Register location where CC will be stored.
+    TDB   - Pointer to a 256 byte area where to store the transaction.
+            diagnostic block. NULL if TDB is not needed.
+    RETRY - Retry count value.  If non-NULL a retry loop for CC2
+            is emitted
+    CLOBBER_FPRS_P - If true clobbers for all FPRs are emitted as part
+                     of the tbegin instruction pattern.  */
+ 
+ void
+ s390_expand_tbegin (rtx dest, rtx tdb, rtx retry, bool clobber_fprs_p)
+ {
+   const int CC0 = 1 << 3;
+   const int CC1 = 1 << 2;
+   const int CC3 = 1 << 0;
+   rtx abort_label = gen_label_rtx ();
+   rtx leave_label = gen_label_rtx ();
+   rtx retry_reg = gen_reg_rtx (SImode);
+   rtx retry_label = NULL_RTX;
+   rtx jump;
+   rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
+ 
+   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,
+ 				     gen_rtx_REG (CCRAWmode, CC_REGNUM),
+ 				     gen_rtx_CONST_INT (VOIDmode, CC0)));
+ 
+   JUMP_LABEL (jump) = abort_label;
+   LABEL_NUSES (abort_label) = 1;
+   add_reg_note (jump, REG_BR_PROB, very_unlikely);
+ 
+   /* Initialize CC return value.  */
+   emit_move_insn (dest, const0_rtx);
+ 
+   s390_emit_jump (leave_label, NULL_RTX);
+   LABEL_NUSES (leave_label) = 1;
+   emit_barrier ();
+ 
+   /* Abort handler code.  */
+ 
+   emit_label (abort_label);
+   if (retry != NULL_RTX)
+     {
+       rtx count = gen_reg_rtx (SImode);
+       jump = s390_emit_jump (leave_label,
+ 			     gen_rtx_EQ (VOIDmode,
+ 			       gen_rtx_REG (CCRAWmode, CC_REGNUM),
+ 			       gen_rtx_CONST_INT (VOIDmode, CC1 | CC3)));
+       LABEL_NUSES (leave_label) = 2;
+       add_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,
+ 					      retry_reg,
+ 					      retry_reg));
+       JUMP_LABEL (jump) = retry_label;
+       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);
+ }
+ 
+ /* Builtins.  */
+ 
+ enum s390_builtin
+ {
+   S390_BUILTIN_TBEGIN,
+   S390_BUILTIN_TBEGIN_NOFLOAT,
+   S390_BUILTIN_TBEGIN_RETRY,
+   S390_BUILTIN_TBEGIN_RETRY_NOFLOAT,
+   S390_BUILTIN_TBEGINC,
+   S390_BUILTIN_TEND,
+   S390_BUILTIN_TABORT,
+   S390_BUILTIN_NON_TX_STORE,
+   S390_BUILTIN_TX_NESTING_DEPTH,
+   S390_BUILTIN_TX_ASSIST,
+ 
+   S390_BUILTIN_max
+ };
+ 
+ static enum insn_code const code_for_builtin[S390_BUILTIN_max] = {
+   CODE_FOR_tbegin,
+   CODE_FOR_tbegin_nofloat,
+   CODE_FOR_tbegin_retry,
+   CODE_FOR_tbegin_retry_nofloat,
+   CODE_FOR_tbeginc,
+   CODE_FOR_tend,
+   CODE_FOR_tabort,
+   CODE_FOR_ntstg,
+   CODE_FOR_etnd,
+   CODE_FOR_tx_assist
+ };
+ 
+ static void
+ s390_init_builtins (void)
+ {
+   tree ftype, uint64_type;
+ 
+   /* void foo (void) */
+   ftype = build_function_type_list (void_type_node, NULL_TREE);
+   add_builtin_function ("__builtin_tbeginc", ftype, S390_BUILTIN_TBEGINC,
+ 			BUILT_IN_MD, NULL, NULL_TREE);
+ 
+   /* void foo (int) */
+   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,
+ 				    integer_type_node, NULL_TREE);
+   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);
+   add_builtin_function ("__builtin_tx_nesting_depth", ftype,
+ 			S390_BUILTIN_TX_NESTING_DEPTH,
+ 			BUILT_IN_MD, NULL, NULL_TREE);
+   add_builtin_function ("__builtin_tend", ftype,
+ 			S390_BUILTIN_TEND, BUILT_IN_MD,	NULL, NULL_TREE);
+ 
+   /* void foo (uint64_t *, uint64_t) */
+   if (TARGET_64BIT)
+     uint64_type = long_unsigned_type_node;
+   else
+     uint64_type = long_long_unsigned_type_node;
+ 
+    ftype = build_function_type_list (void_type_node,
+  				    build_pointer_type (uint64_type),
+ 				    uint64_type, NULL_TREE);
+   add_builtin_function ("__builtin_non_tx_store", ftype,
+ 			S390_BUILTIN_NON_TX_STORE,
+ 			BUILT_IN_MD, NULL, NULL_TREE);
+ }
+ 
+ /* Expand an expression EXP that calls a built-in function,
+    with result going to TARGET if that's convenient
+    (and in mode MODE if that's convenient).
+    SUBTARGET may be used as the target for computing one of EXP's operands.
+    IGNORE is nonzero if the value is to be ignored.  */
+ 
+ static rtx
+ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+ 		     enum machine_mode mode ATTRIBUTE_UNUSED,
+ 		     int ignore ATTRIBUTE_UNUSED)
+ {
+ #define MAX_ARGS 2
+ 
+   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+   enum insn_code icode;
+   rtx op[MAX_ARGS], pat;
+   int arity;
+   bool nonvoid;
+   tree arg;
+   call_expr_arg_iterator iter;
+ 
+   if (fcode >= S390_BUILTIN_max)
+     internal_error ("bad builtin fcode");
+   icode = code_for_builtin[fcode];
+   if (icode == 0)
+     internal_error ("bad builtin fcode");
+ 
+   if (!TARGET_ZEC12)
+     error ("Transactional execution builtins require zEC12 or later\n");
+ 
+   if (!TARGET_HTM && TARGET_ZEC12)
+     error ("Transactional execution builtins not enabled (-mtx)\n");
+ 
+   /* Set a flag in the machine specific cfun part in order to support
+      saving/restoring of FPRs.  */
+   if (fcode == S390_BUILTIN_TBEGIN || fcode == S390_BUILTIN_TBEGIN_RETRY)
+     cfun->machine->tbegin_p = true;
+ 
+   nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+ 
+   arity = 0;
+   FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+     {
+       const struct insn_operand_data *insn_op;
+ 
+       if (arg == error_mark_node)
+ 	return NULL_RTX;
+       if (arity >= MAX_ARGS)
+ 	return NULL_RTX;
+ 
+       insn_op = &insn_data[icode].operand[arity + nonvoid];
+ 
+       op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
+ 
+       if (!(*insn_op->predicate) (op[arity], insn_op->mode))
+ 	{
+ 	  if (insn_op->predicate == memory_operand)
+ 	    {
+ 	      /* Don't move a NULL pointer into a register. Otherwise
+ 		 we have to rely on combine being able to move it back
+ 		 in order to get an immediate 0 in the instruction.  */
+ 	      if (op[arity] != const0_rtx)
+ 		op[arity] = copy_to_mode_reg (Pmode, op[arity]);
+ 	      op[arity] = gen_rtx_MEM (insn_op->mode, op[arity]);
+ 	    }
+ 	  else
+ 	    op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
+ 	}
+ 
+       arity++;
+     }
+ 
+   if (nonvoid)
+     {
+       enum machine_mode tmode = insn_data[icode].operand[0].mode;
+       if (!target
+ 	  || GET_MODE (target) != tmode
+ 	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))
+ 	target = gen_reg_rtx (tmode);
+     }
+ 
+   switch (arity)
+     {
+     case 0:
+       pat = GEN_FCN (icode) (target);
+       break;
+     case 1:
+       if (nonvoid)
+         pat = GEN_FCN (icode) (target, op[0]);
+       else
+ 	pat = GEN_FCN (icode) (op[0]);
+       break;
+     case 2:
+       if (nonvoid)
+ 	pat = GEN_FCN (icode) (target, op[0], op[1]);
+       else
+ 	pat = GEN_FCN (icode) (op[0], op[1]);
+       break;
+     default:
+       gcc_unreachable ();
+     }
+   if (!pat)
+     return NULL_RTX;
+   emit_insn (pat);
+ 
+   if (nonvoid)
+     return target;
+   else
+     return const0_rtx;
+ }
+ 
+ 
  /* Output assembly code for the trampoline template to
     stdio stream FILE.
  
*************** s390_loop_unroll_adjust (unsigned nunrol
*** 11008,11013 ****
--- 11497,11507 ----
  #undef TARGET_RETURN_IN_MEMORY
  #define TARGET_RETURN_IN_MEMORY s390_return_in_memory
  
+ #undef  TARGET_INIT_BUILTINS
+ #define TARGET_INIT_BUILTINS s390_init_builtins
+ #undef  TARGET_EXPAND_BUILTIN
+ #define TARGET_EXPAND_BUILTIN s390_expand_builtin
+ 
  #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
  #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA s390_output_addr_const_extra
  
Index: gcc/common/config/s390/s390-common.c
===================================================================
*** gcc/common/config/s390/s390-common.c.orig
--- gcc/common/config/s390/s390-common.c
*************** EXPORTED_CONST int processor_flags_table
*** 42,48 ****
      /* z196 */   PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
                   | PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196,
      /* zEC12 */  PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
!                  | PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12
    };
  
  /* Change optimizations to be performed, depending on the
--- 42,48 ----
      /* z196 */   PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
                   | PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196,
      /* zEC12 */  PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT
!                  | PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12 | PF_TX
    };
  
  /* Change optimizations to be performed, depending on the
Index: gcc/config/s390/predicates.md
===================================================================
*** gcc/config/s390/predicates.md.orig
--- gcc/config/s390/predicates.md
***************
*** 176,182 ****
  {
    if (GET_CODE (XEXP (op, 0)) != REG
        || REGNO (XEXP (op, 0)) != CC_REGNUM
!       || XEXP (op, 1) != const0_rtx)
      return false;
  
    return (s390_branch_condition_mask (op) >= 0);
--- 176,186 ----
  {
    if (GET_CODE (XEXP (op, 0)) != REG
        || REGNO (XEXP (op, 0)) != CC_REGNUM
!       || (XEXP (op, 1) != const0_rtx
!           && !(CONST_INT_P (XEXP (op, 1))
! 	       && GET_MODE (XEXP (op, 0)) == CCRAWmode
! 	       && INTVAL (XEXP (op, 1)) >= 0
!                && INTVAL (XEXP (op, 1)) <= 15)))
      return false;
  
    return (s390_branch_condition_mask (op) >= 0);
***************
*** 224,230 ****
  
    if (GET_CODE (XEXP (op, 0)) != REG
        || REGNO (XEXP (op, 0)) != CC_REGNUM
!       || XEXP (op, 1) != const0_rtx)
      return false;
  
    switch (GET_MODE (XEXP (op, 0)))
--- 228,238 ----
  
    if (GET_CODE (XEXP (op, 0)) != REG
        || REGNO (XEXP (op, 0)) != CC_REGNUM
!       || (XEXP (op, 1) != const0_rtx
!           && !(CONST_INT_P (XEXP (op, 1))
! 	       && GET_MODE (XEXP (op, 0)) == CCRAWmode
! 	       && INTVAL (XEXP (op, 1)) >= 0
!                && INTVAL (XEXP (op, 1)) <= 15)))
      return false;
  
    switch (GET_MODE (XEXP (op, 0)))
Index: gcc/config/s390/s390-modes.def
===================================================================
*** gcc/config/s390/s390-modes.def.orig
--- gcc/config/s390/s390-modes.def
*************** The compare and swap instructions sets t
*** 152,157 ****
--- 152,165 ----
  operands were equal/unequal. The CCZ1 mode ensures the result can be
  effectively placed into a register.
  
+ CCRAW
+ 
+ The cc mode generated by a non-compare instruction.  The condition
+ code mask for the CC consumer is determined by the comparison operator
+ (only EQ and NE allowed) and the immediate value given as second
+ operand to the operator.  For the other CC modes this value used to be
+ 0.
+ 
  */
  
  
*************** CC_MODE (CCT);
*** 172,174 ****
--- 180,183 ----
  CC_MODE (CCT1);
  CC_MODE (CCT2);
  CC_MODE (CCT3);
+ CC_MODE (CCRAW);
Index: gcc/config/s390/s390.h
===================================================================
*** gcc/config/s390/s390.h.orig
--- gcc/config/s390/s390.h
*************** enum processor_flags
*** 34,40 ****
    PF_DFP = 16,
    PF_Z10 = 32,
    PF_Z196 = 64,
!   PF_ZEC12 = 128
  };
  
  /* This is necessary to avoid a warning about comparing different enum
--- 34,41 ----
    PF_DFP = 16,
    PF_Z10 = 32,
    PF_Z196 = 64,
!   PF_ZEC12 = 128,
!   PF_TX = 256
  };
  
  /* This is necessary to avoid a warning about comparing different enum
*************** enum processor_flags
*** 61,66 ****
--- 62,69 ----
   	(s390_arch_flags & PF_Z196)
  #define TARGET_CPU_ZEC12 \
   	(s390_arch_flags & PF_ZEC12)
+ #define TARGET_CPU_HTM \
+  	(s390_arch_flags & PF_TX)
  
  /* These flags indicate that the generated code should run on a cpu
     providing the respective hardware facility when run in
*************** enum processor_flags
*** 78,83 ****
--- 81,88 ----
         (TARGET_ZARCH && TARGET_CPU_Z196)
  #define TARGET_ZEC12 \
         (TARGET_ZARCH && TARGET_CPU_ZEC12)
+ #define TARGET_HTM \
+        (TARGET_ZARCH && TARGET_CPU_HTM && TARGET_OPT_HTM)
  
  
  #define TARGET_AVOID_CMP_AND_BRANCH (s390_tune == PROCESSOR_2817_Z196)
*************** enum processor_flags
*** 93,115 ****
  #define TARGET_TPF 0
  
  /* Target CPU builtins.  */
! #define TARGET_CPU_CPP_BUILTINS()			\
!   do							\
!     {							\
!       builtin_assert ("cpu=s390");			\
!       builtin_assert ("machine=s390");			\
!       builtin_define ("__s390__");			\
!       if (TARGET_ZARCH)					\
! 	builtin_define ("__zarch__");			\
!       if (TARGET_64BIT)					\
!         builtin_define ("__s390x__");			\
!       if (TARGET_LONG_DOUBLE_128)			\
!         builtin_define ("__LONG_DOUBLE_128__");		\
!     }							\
    while (0)
  
  #ifdef DEFAULT_TARGET_64BIT
! #define TARGET_DEFAULT             (MASK_64BIT | MASK_ZARCH | MASK_HARD_DFP)
  #else
  #define TARGET_DEFAULT             0
  #endif
--- 98,122 ----
  #define TARGET_TPF 0
  
  /* Target CPU builtins.  */
! #define TARGET_CPU_CPP_BUILTINS()					\
!   do									\
!     {									\
!       builtin_assert ("cpu=s390");					\
!       builtin_assert ("machine=s390");					\
!       builtin_define ("__s390__");					\
!       if (TARGET_ZARCH)							\
! 	builtin_define ("__zarch__");					\
!       if (TARGET_64BIT)							\
!         builtin_define ("__s390x__");					\
!       if (TARGET_LONG_DOUBLE_128)					\
!         builtin_define ("__LONG_DOUBLE_128__");				\
!       if (TARGET_HTM)							\
! 	builtin_define ("__HTM__");					\
!     }									\
    while (0)
  
  #ifdef DEFAULT_TARGET_64BIT
! #define TARGET_DEFAULT             (MASK_64BIT | MASK_ZARCH | MASK_HARD_DFP | MASK_OPT_HTM)
  #else
  #define TARGET_DEFAULT             0
  #endif
Index: gcc/config/s390/s390.md
===================================================================
*** gcc/config/s390/s390.md.orig
--- gcc/config/s390/s390.md
***************
*** 59,69 ****
  (define_c_enum "unspec" [
     ; Miscellaneous
     UNSPEC_ROUND
-    UNSPEC_CCU_TO_INT
-    UNSPEC_CCZ_TO_INT
     UNSPEC_ICM
     UNSPEC_TIE
  
     ; GOT/PLT and lt-relative accesses
     UNSPEC_LTREL_OFFSET
     UNSPEC_LTREL_BASE
--- 59,75 ----
  (define_c_enum "unspec" [
     ; Miscellaneous
     UNSPEC_ROUND
     UNSPEC_ICM
     UNSPEC_TIE
  
+    ; Convert CC into a str comparison result and copy it into an
+    ; integer register
+    ; cc0->0, cc1->1, cc2->-1, (cc3->-1)
+    UNSPEC_STRCMPCC_TO_INT
+ 
+    ; Copy CC as is into the lower 2 bits of an integer register
+    UNSPEC_CC_TO_INT
+ 
     ; GOT/PLT and lt-relative accesses
     UNSPEC_LTREL_OFFSET
     UNSPEC_LTREL_BASE
***************
*** 138,143 ****
--- 144,158 ----
     ; Atomic Support
     UNSPECV_CAS
     UNSPECV_ATOMIC_OP
+ 
+    ; Transactional Execution support
+    UNSPECV_TBEGIN
+    UNSPECV_TBEGINC
+    UNSPECV_TEND
+    UNSPECV_TABORT
+    UNSPECV_ETND
+    UNSPECV_NTSTG
+    UNSPECV_PPA
    ])
  
  ;;
***************
*** 191,196 ****
--- 206,214 ----
     (PFPO_OP1_TYPE_SHIFT           8)
    ])
  
+ ; Immediate operands for tbegin and tbeginc
+ (define_constants [(TBEGIN_MASK  65292)]) ; 0xff0c
+ (define_constants [(TBEGINC_MASK 65288)]) ; 0xff08
  
  ;; Instruction operand type as used in the Principles of Operation.
  ;; Used to determine defaults for length and other attribute values.
***************
*** 2251,2257 ****
  
  (define_insn "movcc"
    [(set (match_operand:CC 0 "nonimmediate_operand" "=d,c,d,d,d,R,T")
! 	(match_operand:CC 1 "nonimmediate_operand" "d,d,c,R,T,d,d"))]
    ""
    "@
     lr\t%0,%1
--- 2269,2275 ----
  
  (define_insn "movcc"
    [(set (match_operand:CC 0 "nonimmediate_operand" "=d,c,d,d,d,R,T")
! 	(match_operand:CC 1 "nonimmediate_operand" " d,d,c,R,T,d,d"))]
    ""
    "@
     lr\t%0,%1
***************
*** 2583,2589 ****
       (use (reg:SI 0))])
     (parallel
      [(set (match_operand:SI 0 "register_operand" "=d")
! 	  (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_CCU_TO_INT))
       (clobber (reg:CC CC_REGNUM))])]
    ""
  {
--- 2601,2607 ----
       (use (reg:SI 0))])
     (parallel
      [(set (match_operand:SI 0 "register_operand" "=d")
! 	  (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_STRCMPCC_TO_INT))
       (clobber (reg:CC CC_REGNUM))])]
    ""
  {
***************
*** 2825,2831 ****
                       (match_dup 2)]
                       UNSPEC_TDC_INSN))
     (set (match_operand:SI 0 "register_operand" "=d")
!         (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
    "TARGET_HARD_FLOAT"
  {
    operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
--- 2843,2849 ----
                       (match_dup 2)]
                       UNSPEC_TDC_INSN))
     (set (match_operand:SI 0 "register_operand" "=d")
!         (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))]
    "TARGET_HARD_FLOAT"
  {
    operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
***************
*** 2837,2848 ****
                       (match_dup 2)]
                       UNSPEC_TDC_INSN))
     (set (match_operand:SI 0 "register_operand" "=d")
!         (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
    "TARGET_HARD_FLOAT"
  {
    operands[2] = GEN_INT (S390_TDC_INFINITY);
  })
  
  ; This insn is used to generate all variants of the Test Data Class
  ; instruction, namely tcxb, tcdb, and tceb.  The insn's first operand
  ; is the register to be tested and the second one is the bit mask
--- 2855,2875 ----
                       (match_dup 2)]
                       UNSPEC_TDC_INSN))
     (set (match_operand:SI 0 "register_operand" "=d")
!         (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))]
    "TARGET_HARD_FLOAT"
  {
    operands[2] = GEN_INT (S390_TDC_INFINITY);
  })
  
+ (define_insn_and_split "*cc_to_int"
+   [(set (match_operand:SI 0 "register_operand" "=d")
+         (unspec:SI [(match_operand 1 "register_operand" "0")]
+                    UNSPEC_CC_TO_INT))]
+   "operands != NULL"
+   "#"
+   "reload_completed"
+   [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))])
+ 
  ; This insn is used to generate all variants of the Test Data Class
  ; instruction, namely tcxb, tcdb, and tceb.  The insn's first operand
  ; is the register to be tested and the second one is the bit mask
***************
*** 2858,2871 ****
     [(set_attr "op_type" "RXE")
      (set_attr "type"  "fsimp<mode>")])
  
- (define_insn_and_split "*ccz_to_int"
-   [(set (match_operand:SI 0 "register_operand" "=d")
-         (unspec:SI [(match_operand:CCZ 1 "register_operand" "0")]
-                    UNSPEC_CCZ_TO_INT))]
-   ""
-   "#"
-   "reload_completed"
-   [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))])
  
  
  ;
--- 2885,2890 ----
***************
*** 3210,3216 ****
  (define_insn_and_split "cmpint"
    [(set (match_operand:SI 0 "register_operand" "=d")
          (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                    UNSPEC_CCU_TO_INT))
     (clobber (reg:CC CC_REGNUM))]
    ""
    "#"
--- 3229,3235 ----
  (define_insn_and_split "cmpint"
    [(set (match_operand:SI 0 "register_operand" "=d")
          (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                    UNSPEC_STRCMPCC_TO_INT))
     (clobber (reg:CC CC_REGNUM))]
    ""
    "#"
***************
*** 3223,3232 ****
  (define_insn_and_split "*cmpint_cc"
    [(set (reg CC_REGNUM)
          (compare (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                             UNSPEC_CCU_TO_INT)
                   (const_int 0)))
     (set (match_operand:SI 0 "register_operand" "=d")
!         (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT))]
    "s390_match_ccmode (insn, CCSmode)"
    "#"
    "&& reload_completed"
--- 3242,3251 ----
  (define_insn_and_split "*cmpint_cc"
    [(set (reg CC_REGNUM)
          (compare (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                             UNSPEC_STRCMPCC_TO_INT)
                   (const_int 0)))
     (set (match_operand:SI 0 "register_operand" "=d")
!         (unspec:SI [(match_dup 1)] UNSPEC_STRCMPCC_TO_INT))]
    "s390_match_ccmode (insn, CCSmode)"
    "#"
    "&& reload_completed"
***************
*** 3243,3249 ****
  (define_insn_and_split "*cmpint_sign"
    [(set (match_operand:DI 0 "register_operand" "=d")
          (sign_extend:DI (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                                    UNSPEC_CCU_TO_INT)))
     (clobber (reg:CC CC_REGNUM))]
    "TARGET_ZARCH"
    "#"
--- 3262,3268 ----
  (define_insn_and_split "*cmpint_sign"
    [(set (match_operand:DI 0 "register_operand" "=d")
          (sign_extend:DI (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                                    UNSPEC_STRCMPCC_TO_INT)))
     (clobber (reg:CC CC_REGNUM))]
    "TARGET_ZARCH"
    "#"
***************
*** 3257,3267 ****
    [(set (reg CC_REGNUM)
          (compare (ashiftrt:DI (ashift:DI (subreg:DI
                     (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                               UNSPEC_CCU_TO_INT) 0)
                     (const_int 32)) (const_int 32))
                   (const_int 0)))
     (set (match_operand:DI 0 "register_operand" "=d")
!         (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT)))]
    "s390_match_ccmode (insn, CCSmode) && TARGET_ZARCH"
    "#"
    "&& reload_completed"
--- 3276,3286 ----
    [(set (reg CC_REGNUM)
          (compare (ashiftrt:DI (ashift:DI (subreg:DI
                     (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
!                               UNSPEC_STRCMPCC_TO_INT) 0)
                     (const_int 32)) (const_int 32))
                   (const_int 0)))
     (set (match_operand:DI 0 "register_operand" "=d")
!         (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_STRCMPCC_TO_INT)))]
    "s390_match_ccmode (insn, CCSmode) && TARGET_ZARCH"
    "#"
    "&& reload_completed"
***************
*** 5512,5518 ****
  	(if_then_else:GPR
  	  (match_operator 1 "s390_comparison"
  	    [(match_operand 2 "cc_reg_operand"        " c,c, c, c, c, c, c")
! 	     (const_int 0)])
  	  (match_operand:GPR 3 "nonimmediate_operand" " d,0,QS, 0, d, 0,QS")
  	  (match_operand:GPR 4 "nonimmediate_operand" " 0,d, 0,QS, 0, d,QS")))]
    "TARGET_Z196"
--- 5531,5537 ----
  	(if_then_else:GPR
  	  (match_operator 1 "s390_comparison"
  	    [(match_operand 2 "cc_reg_operand"        " c,c, c, c, c, c, c")
! 	     (match_operand 5 "const_int_operand"     "")])
  	  (match_operand:GPR 3 "nonimmediate_operand" " d,0,QS, 0, d, 0,QS")
  	  (match_operand:GPR 4 "nonimmediate_operand" " 0,d, 0,QS, 0, d,QS")))]
    "TARGET_Z196"
***************
*** 7912,7918 ****
  (define_insn "*cjump_64"
    [(set (pc)
          (if_then_else
!           (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
            (label_ref (match_operand 0 "" ""))
            (pc)))]
    "TARGET_CPU_ZARCH"
--- 7931,7938 ----
  (define_insn "*cjump_64"
    [(set (pc)
          (if_then_else
!           (match_operator 1 "s390_comparison" [(reg CC_REGNUM)
! 					       (match_operand 2 "const_int_operand" "")])
            (label_ref (match_operand 0 "" ""))
            (pc)))]
    "TARGET_CPU_ZARCH"
***************
*** 7931,7937 ****
  (define_insn "*cjump_31"
    [(set (pc)
          (if_then_else
!           (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
            (label_ref (match_operand 0 "" ""))
            (pc)))]
    "!TARGET_CPU_ZARCH"
--- 7951,7958 ----
  (define_insn "*cjump_31"
    [(set (pc)
          (if_then_else
!           (match_operator 1 "s390_comparison" [(reg CC_REGNUM)
! 					       (match_operand 2 "const_int_operand" "")])
            (label_ref (match_operand 0 "" ""))
            (pc)))]
    "!TARGET_CPU_ZARCH"
***************
*** 9800,9802 ****
--- 9821,10037 ----
    "cpsdr\t%0,%2,%1"
    [(set_attr "op_type"  "RRF")
     (set_attr "type"     "fsimp<mode>")])
+ 
+ 
+ ;;
+ ;;- Transactional execution instructions
+ ;;
+ 
+ ; This splitter helps combine to make use of CC directly when
+ ; comparing the integer result of a tbegin builtin with a constant.
+ ; The unspec is already removed by canonicalize_comparison. So this
+ ; splitters only job is to turn the PARALLEL into separate insns
+ ; again.  Unfortunately this only works with the very first cc/int
+ ; compare since combine is not able to deal with data flow across
+ ; basic block boundaries.
+ 
+ ; It needs to be an insn pattern as well since combine does not apply
+ ; the splitter directly.  Combine would only use it if it actually
+ ; would reduce the number of instructions.
+ (define_insn_and_split "*ccraw_to_int"
+   [(set (pc)
+ 	(if_then_else
+ 	 (match_operator 0 "s390_eqne_operator"
+ 			 [(reg:CCRAW CC_REGNUM)
+ 			  (match_operand 1 "const_int_operand" "")])
+ 	 (label_ref (match_operand 2 "" ""))
+ 	 (pc)))
+    (set (match_operand:SI 3 "register_operand" "=d")
+ 	(unspec:SI [(reg:CCRAW CC_REGNUM)] UNSPEC_CC_TO_INT))]
+   ""
+   "#"
+   ""
+   [(set (match_dup 3)
+ 	(unspec:SI [(reg:CCRAW CC_REGNUM)] UNSPEC_CC_TO_INT))
+    (set (pc)
+ 	(if_then_else (match_op_dup 0 [(reg:CCRAW CC_REGNUM) (match_dup 1)])
+ 		      (label_ref (match_dup 2))
+ 		      (pc)))]
+   "")
+ 
+ ; Non-constrained transaction begin
+ 
+ (define_expand "tbegin"
+   [(match_operand:SI 0 "register_operand" "=d")
+    (match_operand:BLK 1 "memory_operand"  "=Q")]
+   "TARGET_HTM"
+ {
+   s390_expand_tbegin (operands[0], operands[1], NULL_RTX, true);
+   DONE;
+ })
+ 
+ (define_expand "tbegin_nofloat"
+   [(match_operand:SI 0 "register_operand" "=d")
+    (match_operand:BLK 1 "memory_operand"  "=Q")]
+   "TARGET_HTM"
+ {
+   s390_expand_tbegin (operands[0], operands[1], NULL_RTX, false);
+   DONE;
+ })
+ 
+ (define_expand "tbegin_retry"
+   [(match_operand:SI 0 "register_operand" "=d")
+    (match_operand:BLK 1 "memory_operand"  "=Q")
+    (match_operand 2 "const_int_operand")]
+   "TARGET_HTM"
+ {
+   s390_expand_tbegin (operands[0], operands[1], operands[2], true);
+   DONE;
+ })
+ 
+ (define_expand "tbegin_retry_nofloat"
+   [(match_operand:SI 0 "register_operand" "=d")
+    (match_operand:BLK 1 "memory_operand"  "=Q")
+    (match_operand 2 "const_int_operand")]
+   "TARGET_HTM"
+ {
+   s390_expand_tbegin (operands[0], operands[1], operands[2], false);
+   DONE;
+ })
+ 
+ (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))
+    (clobber (reg:DF 19))
+    (clobber (reg:DF 20))
+    (clobber (reg:DF 21))
+    (clobber (reg:DF 22))
+    (clobber (reg:DF 23))
+    (clobber (reg:DF 24))
+    (clobber (reg:DF 25))
+    (clobber (reg:DF 26))
+    (clobber (reg:DF 27))
+    (clobber (reg:DF 28))
+    (clobber (reg:DF 29))
+    (clobber (reg:DF 30))
+    (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")])
+ 
+ 
+ ; Constrained transaction begin
+ 
+ (define_expand "tbeginc"
+   [(set (reg:CCRAW CC_REGNUM)
+ 	(unspec_volatile:CCRAW [(const_int TBEGINC_MASK)]
+ 			       UNSPECV_TBEGINC))]
+   "TARGET_HTM"
+   "")
+ 
+ (define_insn "*tbeginc_1"
+   [(set (reg:CCRAW CC_REGNUM)
+ 	(unspec_volatile:CCRAW [(match_operand 0 "const_int_operand" " D")]
+ 			       UNSPECV_TBEGINC))]
+   "TARGET_HTM && INTVAL (operands[0]) >= 0 && INTVAL (operands[0]) <= 0xffff"
+   "tbeginc\t0,%x0"
+   [(set_attr "op_type" "SIL")])
+ 
+ ; Transaction end
+ 
+ (define_expand "tend"
+   [(set (reg:CCRAW CC_REGNUM)
+ 	(unspec_volatile:CCRAW [(const_int 0)] UNSPECV_TEND))
+    (set (match_operand:SI 0 "register_operand" "=d")
+ 	(unspec:SI [(reg:CCRAW CC_REGNUM)] UNSPEC_CC_TO_INT))]
+   "TARGET_HTM"
+   "")
+ 
+ (define_insn "*tend_1"
+   [(set (reg:CCRAW CC_REGNUM)
+ 	(unspec_volatile:CCRAW [(const_int 0)] UNSPECV_TEND))]
+   "TARGET_HTM"
+   "tend"
+   [(set_attr "op_type" "S")])
+ 
+ ; Transaction abort
+ 
+ (define_expand "tabort"
+   [(unspec_volatile [(match_operand 0 "shift_count_or_setmem_operand" "")]
+ 		    UNSPECV_TABORT)]
+   "TARGET_HTM && operands != NULL"
+ {
+   if (CONST_INT_P (operands[0])
+       && INTVAL (operands[0]) >= 0 && INTVAL (operands[0]) <= 255)
+     {
+       error ("Invalid transaction abort code: " HOST_WIDE_INT_PRINT_DEC
+ 	     ".  Values in range 0 through 255 are reserved.",
+ 	     INTVAL (operands[0]));
+       FAIL;
+     }
+ })
+ 
+ (define_insn "*tabort_1"
+   [(unspec_volatile [(match_operand 0 "shift_count_or_setmem_operand" "")]
+ 		    UNSPECV_TABORT)]
+   "TARGET_HTM && operands != NULL"
+   "tabort\t%Y0"
+   [(set_attr "op_type" "S")])
+ 
+ ; Transaction extract nesting depth
+ 
+ (define_insn "etnd"
+   [(set (match_operand:SI 0 "register_operand" "=d")
+ 	(unspec_volatile:SI [(const_int 0)] UNSPECV_ETND))]
+   "TARGET_HTM"
+   "etnd\t%0"
+   [(set_attr "op_type" "RRE")])
+ 
+ ; Non-transactional store
+ 
+ (define_insn "ntstg"
+   [(set (match_operand:DI 0 "memory_operand" "=RT")
+ 	(unspec_volatile:DI [(match_operand:DI 1 "register_operand" "d")]
+ 			    UNSPECV_NTSTG))]
+   "TARGET_HTM"
+   "ntstg\t%1,%0"
+   [(set_attr "op_type" "RXY")])
+ 
+ ; Transaction perform processor assist
+ 
+ (define_expand "tx_assist"
+   [(set (match_dup 1) (const_int 0))
+    (unspec_volatile [(match_operand:SI 0 "register_operand" "d")
+ 		     (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")
+ 		     (match_operand:SI 1 "register_operand" "d")
+ 		     (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")])
Index: gcc/config/s390/s390.opt
===================================================================
*** gcc/config/s390/s390.opt.orig
--- gcc/config/s390/s390.opt
*************** mlong-double-64
*** 104,109 ****
--- 104,113 ----
  Target Report RejectNegative Negative(mlong-double-128) InverseMask(LONG_DOUBLE_128)
  Use 64-bit long double
  
+ mhtm
+ Target Report Mask(OPT_HTM)
+ Use hardware transactional execution instructions
+ 
  mpacked-stack
  Target Report Mask(PACKED_STACK)
  Use packed stack layout
Index: libitm/config/s390/target.h
===================================================================
*** libitm/config/s390/target.h.orig
--- libitm/config/s390/target.h
***************
*** 22,27 ****
--- 22,33 ----
     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     <http://www.gnu.org/licenses/>.  */
  
+ 
+ #include <htmintrin.h>
+ 
+ /* Number of retries for transient failures.  */
+ #define _HTM_ITM_RETRIES 10
+ 
  namespace GTM HIDDEN {
  
  #define HW_CACHELINE_SIZE 256
*************** cpu_relax (void)
*** 52,55 ****
--- 58,114 ----
    __asm volatile ("" : : : "memory");
  }
  
+ #ifdef __HTM__
+ #define USE_HTM_FASTPATH
+ 
+ static inline bool
+ htm_available ()
+ {
+   return true;
+ }
+ 
+ static inline uint32_t
+ htm_init ()
+ {
+   return htm_available () ? _HTM_ITM_RETRIES : 0;
+ }
+ 
+ static inline uint32_t
+ htm_begin ()
+ {
+   return __builtin_tbegin_nofloat (NULL);
+ }
+ 
+ static inline bool
+ htm_begin_success (uint32_t begin_ret)
+ {
+   return begin_ret == _HTM_TBEGIN_STARTED;
+ }
+ 
+ static inline void
+ htm_commit ()
+ {
+   __builtin_tend ();
+ }
+ 
+ static inline void
+ htm_abort ()
+ {
+   __builtin_tabort (_HTM_FIRST_USER_ABORT_CODE);
+ }
+ 
+ static inline bool
+ htm_abort_should_retry (uint32_t begin_ret)
+ {
+   return begin_ret == _HTM_TBEGIN_TRANSIENT;
+ }
+ 
+ static inline bool
+ htm_transaction_active ()
+ {
+   return __builtin_tx_nesting_depth() != 0;
+ }
+ 
+ #endif
+ 
  } // namespace GTM
Index: gcc/config/s390/s390-protos.h
===================================================================
*** gcc/config/s390/s390-protos.h.orig
--- gcc/config/s390/s390-protos.h
*************** extern bool s390_match_ccmode (rtx, enum
*** 58,64 ****
  extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
  extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
  extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
! extern void s390_emit_jump (rtx, rtx);
  extern bool symbolic_reference_mentioned_p (rtx);
  extern bool tls_symbolic_reference_mentioned_p (rtx);
  extern bool legitimate_la_operand_p (rtx);
--- 58,64 ----
  extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool);
  extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
  extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
! extern rtx s390_emit_jump (rtx, rtx);
  extern bool symbolic_reference_mentioned_p (rtx);
  extern bool tls_symbolic_reference_mentioned_p (rtx);
  extern bool legitimate_la_operand_p (rtx);
*************** extern void s390_expand_cs_hqi (enum mac
*** 87,92 ****
--- 87,93 ----
  				rtx, rtx, bool);
  extern void s390_expand_atomic (enum machine_mode, enum rtx_code,
  				rtx, rtx, rtx, bool);
+ extern void s390_expand_tbegin (rtx, rtx, rtx, bool);
  extern rtx s390_return_addr_rtx (int, rtx);
  extern rtx s390_back_chain_rtx (void);
  extern rtx s390_emit_call (rtx, rtx, rtx, rtx);
Index: gcc/testsuite/gcc.target/s390/htm-1.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-1.c
***************
*** 0 ****
--- 1,36 ----
+ /* This checks the availability of the low-level builtins introduced
+    for transactional execution.  */
+ 
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -march=zEC12" } */
+ 
+ #include <htmintrin.h>
+ 
+ int a = 0;
+ unsigned long g;
+ 
+ int
+ foo (struct __htm_tdb* tdb)
+ {
+ 
+   int cc;
+   int n;
+ 
+   cc = __builtin_tbegin (0);
+   cc = __builtin_tbegin (tdb);
+   cc = __builtin_tbegin_nofloat (0);
+   cc = __builtin_tbegin_nofloat (tdb);
+   cc = __builtin_tbegin_retry (0, 42);
+   cc = __builtin_tbegin_retry (tdb, 42);
+   cc = __builtin_tbegin_retry_nofloat (0, 42);
+   cc = __builtin_tbegin_retry_nofloat (tdb, 42);
+   __builtin_tbeginc ();
+   n = __builtin_tx_nesting_depth();
+   __builtin_non_tx_store(&g, n);
+   __builtin_tabort (42 + 255);
+   __builtin_tend();
+   __builtin_tx_assist (23);
+ }
+ /* Make sure the tdb NULL argument ends up as immediate value in the
+    instruction.  */
+ /* { dg-final { scan-assembler-times "tbegin\t0," 4 } } */
Index: gcc/testsuite/gcc.target/s390/htm-nofloat-1.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-nofloat-1.c
***************
*** 0 ****
--- 1,12 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O3 -march=zEC12" } */
+ 
+ int
+ foo ()
+ {
+   __builtin_tbegin_nofloat (0);
+   __builtin_tbegin_retry_nofloat (0, 42);
+ }
+ /* Make sure no FPR saves/restores are emitted.  */
+ /* { dg-final { scan-assembler-not "std" } } */
+ /* { dg-final { scan-assembler-not "ld" } } */
Index: gcc/config/s390/htmintrin.h
===================================================================
*** /dev/null
--- gcc/config/s390/htmintrin.h
***************
*** 0 ****
--- 1,57 ----
+ /* GNU compiler hardware transactional execution intrinsics
+    Copyright (C) 2013 Free Software Foundation, Inc.
+    Contributed by Andreas Krebbel (Andreas.Krebbel@de.ibm.com)
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #ifndef _HTMINTRIN_H
+ #define _HTMINTRIN_H
+ 
+ 
+ /* Condition codes generated by tbegin  */
+ #define _HTM_TBEGIN_STARTED       0
+ #define _HTM_TBEGIN_INDETERMINATE 1
+ #define _HTM_TBEGIN_TRANSIENT     2
+ #define _HTM_TBEGIN_PERSISTENT    3
+ 
+ /* The abort codes below this threshold are reserved for machine
+    use.  */
+ #define _HTM_FIRST_USER_ABORT_CODE 256
+ 
+ /* The transaction diagnostic block is it is defined in the Principles
+    of Operation chapter 5-91.  */
+ 
+ struct __htm_tdb {
+   unsigned char format;                /*   0 */
+   unsigned char flags;
+   unsigned char reserved1[4];
+   unsigned short nesting_depth;
+   unsigned long long abort_code;       /*   8 */
+   unsigned long long conflict_token;   /*  16 */
+   unsigned long long atia;             /*  24 */
+   unsigned char eaid;                  /*  32 */
+   unsigned char dxc;
+   unsigned char reserved2[2];
+   unsigned int program_int_id;
+   unsigned long long exception_id;     /*  40 */
+   unsigned long long bea;              /*  48 */
+   unsigned char reserved3[72];         /*  56 */
+   unsigned long long gprs[16];         /* 128 */
+ } __attribute__((__packed__, __aligned__ (8)));
+ 
+ 
+ #endif /* _HTMINTRIN_H */
Index: gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c
===================================================================
*** /dev/null
--- gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.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" } */
+ 
+ #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/doc/extend.texi
===================================================================
*** gcc/doc/extend.texi.orig
--- gcc/doc/extend.texi
*************** instructions, but allow the compiler to
*** 8839,8844 ****
--- 8839,8845 ----
  * PowerPC Built-in Functions::
  * PowerPC AltiVec/VSX Built-in Functions::
  * RX Built-in Functions::
+ * S/390 System z Built-in Functions::
  * SH Built-in Functions::
  * SPARC VIS Built-in Functions::
  * SPU Built-in Functions::
*************** bit in the processor status word.
*** 14414,14419 ****
--- 14415,14534 ----
  Generates the @code{wait} machine instruction.
  @end deftypefn
  
+ @node S/390 System z Built-in Functions
+ @subsection S/390 System z Built-in Functions
+ @deftypefn {Built-in Function} int __builtin_tbegin (void*)
+ Generates the @code{tbegin} machine instruction starting a
+ non-constraint hardware transaction.  If the parameter is non-NULL the
+ memory area is used to store the transaction diagnostic buffer and
+ will be passed as first operand to @code{tbegin}.  This buffer can be
+ defined using the @code{struct __htm_tdb} C struct defined in
+ @code{htmintrin.h} and must reside on a double-word boundary.  The
+ second tbegin operand is set to @code{0xff0c}. This enables
+ save/restore of all GPRs and disables aborts for FPR and AR
+ manipulations inside the transaction body.  The condition code set by
+ the tbegin instruction is returned as integer value.  The tbegin
+ instruction by definition overwrites the content of all FPRs.  The
+ compiler will generate code which saves and restores the FPRs.  For
+ soft-float code it is recommended to used the @code{*_nofloat}
+ variant.  In order to prevent a TDB from being written it is required
+ to pass an constant zero value as parameter.  Passing the zero value
+ through a variable is not sufficient.  Although modifications of
+ access registers inside the transaction will not trigger an
+ transaction abort it is not supported to actually modify them.  Access
+ registers do not get saved when entering a transaction. They will have
+ undefined state when reaching the abort code.
+ @end deftypefn
+ 
+ Macros for the possible return codes of tbegin are defined in the
+ @code{htmintrin.h} header file:
+ 
+ @table @code
+ @item _HTM_TBEGIN_STARTED
+ @code{tbegin} has been executed as part of normal processing.  The
+ transaction body is supposed to be executed.
+ @item _HTM_TBEGIN_INDETERMINATE
+ The transaction was aborted due to an indeterminate condition which
+ might be persistent.
+ @item _HTM_TBEGIN_TRANSIENT
+ The transaction aborted due to a transient failure.  The transaction
+ should be re-executed in that case.
+ @item _HTM_TBEGIN_PERSISTENT
+ The transaction aborted due to a persistent failure.  Re-execution
+ under same circumstances will not be productive.
+ @end table
+ 
+ @defmac _HTM_FIRST_USER_ABORT_CODE
+ The @code{_HTM_FIRST_USER_ABORT_CODE} defined in @code{htmintrin.h}
+ specifies the first abort code which can be used for
+ @code{__builtin_tabort}.  Values below this threshold are reserved for
+ machine use.
+ @end defmac
+ 
+ @deftp {Data type} {struct __htm_tdb}
+ The @code{struct __htm_tdb} defined in @code{htmintrin.h} describes
+ the structure of the transaction diagnostic block as specified in the
+ Principles of Operation manual chapter 5-91.
+ @end deftp
+ 
+ @deftypefn {Built-in Function} int __builtin_tbegin_nofloat (void*)
+ Same as @code{__builtin_tbegin} but without FPR saves and restores.
+ Using this variant in code making use of FPRs will leave the FPRs in
+ undefined state when entering the transaction abort handler code.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} int __builtin_tbegin_retry (void*, int)
+ In addition to @code{__builtin_tbegin} a loop for transient failures
+ is generated.  If tbegin returns a condition code of 2 the transaction
+ will be retried as often as specified in the second argument.  The
+ perform processor assist instruction is used to tell the CPU about the
+ number of fails so far.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} int __builtin_tbegin_retry_nofloat (void*, int)
+ Same as @code{__builtin_tbegin_retry} but without FPR saves and
+ restores.  Using this variant in code making use of FPRs will leave
+ the FPRs in undefined state when entering the transaction abort
+ handler code.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} void __builtin_tbeginc (void)
+ Generates the @code{tbeginc} machine instruction starting a constraint
+ hardware transaction.  The second operand is set to @code{0xff08}.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} int __builtin_tend (void)
+ Generates the @code{tend} machine instruction finishing a transaction
+ and making the changes visible to other threads.  The condition code
+ generated by tend is returned as integer value.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} void __builtin_tabort (int)
+ Generates the @code{tabort} machine instruction with the specified
+ abort code.  Abort codes from 0 through 255 are reserved and will
+ result in an error message.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} void __builtin_tx_assist (int)
+ Generates the @code{ppa rX,rY,1} machine instruction.  Where the
+ integer parameter is loaded into rX and a value of zero is loaded into
+ rY.  The integer parameter specifies the number of times the
+ transaction repeatedly aborted.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} int __builtin_tx_nesting_depth (void)
+ Generates the @code{etnd} machine instruction.  The current nesting
+ depth is returned as integer value.  For a nesting depth of 0 the code
+ is not executed as part of an transaction.
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} void __builtin_non_tx_store (unsigned long long *, unsigned long long)
+ 
+ Generates the @code{ntstg} machine instruction.  The second argument
+ is written to the first arguments location.  The store operation will
+ not be rolled-back in case of an transaction abort.
+ @end deftypefn
+ 
  @node SH Built-in Functions
  @subsection SH Built-in Functions
  The following built-in functions are supported on the SH1, SH2, SH3 and SH4
Index: gcc/config.gcc
===================================================================
*** gcc/config.gcc.orig
--- gcc/config.gcc
*************** s390*-*-*)
*** 453,458 ****
--- 453,459 ----
  	cpu_type=s390
  	need_64bit_hwint=yes
  	extra_options="${extra_options} fused-madd.opt"
+ 	extra_headers="s390intrin.h htmintrin.h htmxlintrin.h"
  	;;
  # Note the 'l'; we need to be able to match e.g. "shle" or "shl".
  sh[123456789lbe]*-*-* | sh-*-*)
Index: gcc/config/s390/s390intrin.h
===================================================================
*** /dev/null
--- gcc/config/s390/s390intrin.h
***************
*** 0 ****
--- 1,33 ----
+ /* S/390 System z specific intrinsics
+    Copyright (C) 2013 Free Software Foundation, Inc.
+    Contributed by Andreas Krebbel (Andreas.Krebbel@de.ibm.com)
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #ifndef  _S390INTRIN_H
+ #define _S390INTRIN_H
+ 
+ #ifndef __s390__
+   #error s390intrin.h included on wrong platform/compiler
+ #endif
+ 
+ #ifdef __HTM__
+ #include <htmintrin.h>
+ #endif
+ 
+ 
+ #endif /* _S390INTRIN_H*/
Index: gcc/config/s390/htmxlintrin.h
===================================================================
*** /dev/null
--- gcc/config/s390/htmxlintrin.h
***************
*** 0 ****
--- 1,182 ----
+ /* XL compiler hardware transactional execution intrinsics
+    Copyright (C) 2013 Free Software Foundation, Inc.
+    Contributed by Andreas Krebbel (Andreas.Krebbel@de.ibm.com)
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #ifndef _HTMXLINTRIN_H
+ #define _HTMXLINTRIN_H
+ 
+ #include <stdint.h>
+ 
+ #include <htmintrin.h>
+ 
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ 
+ /* These intrinsics are being made available for compatibility with
+    the IBM XL compiler.  For documentation please see the "z/OS XL
+    C/C++ Programming Guide" publically 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);
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_end ()
+ {
+   return __builtin_tend ();
+ }
+ 
+ extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_abort ()
+ {
+   return __builtin_tabort (_HTM_FIRST_USER_ABORT_CODE);
+ }
+ 
+ extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_named_abort (unsigned char const code)
+ {
+   return __builtin_tabort ((int)_HTM_FIRST_USER_ABORT_CODE + code);
+ }
+ 
+ extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_non_transactional_store (void* const addr, long long const value)
+ {
+   __builtin_non_tx_store ((uint64_t*)addr, (uint64_t)value);
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_nesting_depth (void* const tdb_ptr)
+ {
+   int depth = __builtin_tx_nesting_depth ();
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   if (depth != 0)
+     return depth;
+ 
+   if (tdb->format == 0)
+     return 0;
+   return tdb->nesting_depth;
+ }
+ 
+ /* Transaction failure diagnostics */
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_user_abort (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   if (tdb->format == 0)
+     return 0;
+ 
+   return !!(tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE);
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_named_user_abort (void* const tdb_ptr, unsigned char* code)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   if (tdb->format == 0)
+     return 0;
+ 
+   if (tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE)
+     {
+       *code = tdb->abort_code - _HTM_FIRST_USER_ABORT_CODE;
+       return 1;
+     }
+   return 0;
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_illegal (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   return (tdb->format == 0
+ 	  && (tdb->abort_code == 4 /* unfiltered program interruption */
+ 	      || tdb->abort_code == 11 /* restricted instruction */));
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_footprint_exceeded (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   return (tdb->format == 0
+ 	  && (tdb->abort_code == 7 /* fetch overflow */
+ 	      || tdb->abort_code == 8 /* store overflow */));
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_nested_too_deep (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   return tdb->format == 0 && tdb->abort_code == 13; /* depth exceeded */
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_conflict (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   return (tdb->format == 0
+ 	  && (tdb->abort_code == 9 /* fetch conflict */
+ 	      || tdb->abort_code == 10 /* store conflict */));
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_is_failure_persistent (long const result)
+ {
+   return result == _TBEGIN_PERSISTENT;
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_failure_address (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ #ifdef __s390x__
+   return tdb->atia;
+ #else
+   return tdb->atia & 0xffffffff;
+ #endif
+ }
+ 
+ extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __TM_failure_code (void* const tdb_ptr)
+ {
+   struct __tdb *tdb = (struct __tdb*)tdb_ptr;
+ 
+   return tdb->abort_code;
+ }
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ 
+ #endif /* _HTMXLINTRIN_H */



More information about the Gcc-patches mailing list