2013-06-27 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
authorkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 27 Jun 2013 07:44:11 +0000 (07:44 +0000)
committerkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 27 Jun 2013 07:44:11 +0000 (07:44 +0000)
* 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-27  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.

2013-06-27  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.

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

20 files changed:
gcc/ChangeLog
gcc/common/config/s390/s390-common.c
gcc/config.gcc
gcc/config/s390/htmintrin.h [new file with mode: 0644]
gcc/config/s390/htmxlintrin.h [new file with mode: 0644]
gcc/config/s390/predicates.md
gcc/config/s390/s390-modes.def
gcc/config/s390/s390-protos.h
gcc/config/s390/s390.c
gcc/config/s390/s390.h
gcc/config/s390/s390.md
gcc/config/s390/s390.opt
gcc/config/s390/s390intrin.h [new file with mode: 0644]
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/s390/htm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/htm-nofloat-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c [new file with mode: 0644]
libitm/ChangeLog
libitm/config/s390/target.h

index 5f56b61..d1d1113 100644 (file)
@@ -1,3 +1,60 @@
+2013-06-27  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-26  Thomas Schwinge  <thomas@codesourcery.com>
 
        * config/i386/gnu.h [TARGET_LIBC_PROVIDES_SSP]
index 1ffe93e..c2031b7 100644 (file)
@@ -42,7 +42,7 @@ EXPORTED_CONST int processor_flags_table[] =
     /* 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_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12 | PF_TX
   };
 
 /* Change optimizations to be performed, depending on the
index 0ad7217..e3c00b4 100644 (file)
@@ -453,6 +453,7 @@ s390*-*-*)
        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-*-*)
diff --git a/gcc/config/s390/htmintrin.h b/gcc/config/s390/htmintrin.h
new file mode 100644 (file)
index 0000000..7aaa9f5
--- /dev/null
@@ -0,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 */
diff --git a/gcc/config/s390/htmxlintrin.h b/gcc/config/s390/htmxlintrin.h
new file mode 100644 (file)
index 0000000..bb14219
--- /dev/null
@@ -0,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 __htm_tdb *tdb = (struct __htm_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 __htm_tdb *tdb = (struct __htm_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 __htm_tdb *tdb = (struct __htm_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 __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 */));
+}
+
+extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_footprint_exceeded (void* const tdb_ptr)
+{
+  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 */));
+}
+
+extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_nested_too_deep (void* const tdb_ptr)
+{
+  struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+  return tdb->format == 0 && tdb->abort_code == 13; /* depth exceeded */
+}
+
+extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_conflict (void* const tdb_ptr)
+{
+  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 */));
+}
+
+extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__TM_is_failure_persistent (long const result)
+{
+  return result == _HTM_TBEGIN_PERSISTENT;
+}
+
+extern __inline long __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+__TM_failure_address (void* const tdb_ptr)
+{
+  struct __htm_tdb *tdb = (struct __htm_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 __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+  return tdb->abort_code;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HTMXLINTRIN_H */
index 523326e..069b424 100644 (file)
 {
   if (GET_CODE (XEXP (op, 0)) != REG
       || REGNO (XEXP (op, 0)) != CC_REGNUM
-      || XEXP (op, 1) != const0_rtx)
+      || (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);
 
   if (GET_CODE (XEXP (op, 0)) != REG
       || REGNO (XEXP (op, 0)) != CC_REGNUM
-      || XEXP (op, 1) != const0_rtx)
+      || (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 419108f..5e0b50c 100644 (file)
@@ -152,6 +152,14 @@ The compare and swap instructions sets the condition code to 0/1 if the
 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.
+
 */
 
 
@@ -172,3 +180,4 @@ CC_MODE (CCT);
 CC_MODE (CCT1);
 CC_MODE (CCT2);
 CC_MODE (CCT3);
+CC_MODE (CCRAW);
index 1a82053..67283df 100644 (file)
@@ -58,7 +58,7 @@ extern bool s390_match_ccmode (rtx, enum machine_mode);
 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 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);
@@ -87,6 +87,7 @@ extern void s390_expand_cs_hqi (enum machine_mode, rtx, rtx, rtx,
                                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 06d1228..2cacf6f 100644 (file)
@@ -367,6 +367,10 @@ struct GTY(()) machine_function
   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.  */
@@ -824,9 +828,9 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
       *op1 = constm1_rtx;
     }
 
-  /* Remove redundant UNSPEC_CCU_TO_INT conversions if possible.  */
+  /* Remove redundant UNSPEC_STRCMPCC_TO_INT conversions if possible.  */
   if (GET_CODE (*op0) == UNSPEC
-      && XINT (*op0, 1) == UNSPEC_CCU_TO_INT
+      && 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
@@ -852,25 +856,35 @@ s390_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
        }
     }
 
-  /* Remove redundant UNSPEC_CCZ_TO_INT conversions if possible.  */
+  /* Remove redundant UNSPEC_CC_TO_INT conversions if possible.  */
   if (GET_CODE (*op0) == UNSPEC
-      && XINT (*op0, 1) == UNSPEC_CCZ_TO_INT
+      && XINT (*op0, 1) == UNSPEC_CC_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)
+      && CONST_INT_P (*op1))
     {
       enum rtx_code new_code = UNKNOWN;
-      switch (*code)
+      switch (GET_MODE (XVECEXP (*op0, 0, 0)))
        {
-         case EQ: new_code = EQ;  break;
-         case NE: new_code = NE;  break;
-         default: break;
+       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;
        }
@@ -942,10 +956,11 @@ s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem,
                            const0_rtx);
 }
 
-/* Emit a jump instruction to TARGET.  If COND is NULL_RTX, emit an
-   unconditional jump, else a conditional jump under condition COND.  */
+/* 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.  */
 
-void
+rtx
 s390_emit_jump (rtx target, rtx cond)
 {
   rtx insn;
@@ -955,7 +970,7 @@ s390_emit_jump (rtx target, rtx cond)
     target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx);
 
   insn = gen_rtx_SET (VOIDmode, pc_rtx, target);
-  emit_jump_insn (insn);
+  return emit_jump_insn (insn);
 }
 
 /* Return branch condition mask to implement a branch
@@ -971,7 +986,10 @@ s390_branch_condition_mask (rtx code)
 
   gcc_assert (GET_CODE (XEXP (code, 0)) == REG);
   gcc_assert (REGNO (XEXP (code, 0)) == CC_REGNUM);
-  gcc_assert (XEXP (code, 1) == const0_rtx);
+  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)))
     {
@@ -1145,6 +1163,17 @@ s390_branch_condition_mask (rtx code)
         }
       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;
     }
@@ -1204,7 +1233,9 @@ s390_branch_condition_mnemonic (rtx code, int inv)
 
   if (GET_CODE (XEXP (code, 0)) == REG
       && REGNO (XEXP (code, 0)) == CC_REGNUM
-      && XEXP (code, 1) == const0_rtx)
+      && (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);
@@ -1602,6 +1633,11 @@ s390_option_override (void)
   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)
@@ -7334,11 +7370,11 @@ s390_reg_clobbered_rtx (rtx setreg, const_rtx set_insn ATTRIBUTE_UNUSED, void *d
   if (GET_CODE (setreg) == SUBREG)
     {
       rtx inner = SUBREG_REG (setreg);
-      if (!GENERAL_REG_P (inner))
+      if (!GENERAL_REG_P (inner) && !FP_REG_P (inner))
        return;
       regno = subreg_regno (setreg);
     }
-  else if (GENERAL_REG_P (setreg))
+  else if (GENERAL_REG_P (setreg) || FP_REG_P (setreg))
     regno = REGNO (setreg);
   else
     return;
@@ -7361,13 +7397,13 @@ s390_regs_ever_clobbered (int *regs_ever_clobbered)
   rtx cur_insn;
   unsigned int i;
 
-  memset (regs_ever_clobbered, 0, 16 * sizeof (int));
+  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 < 16; i++)
+      for (i = 0; i < 32; i++)
        regs_ever_clobbered[i] = call_really_used_regs[i];
     }
 
@@ -7389,7 +7425,7 @@ s390_regs_ever_clobbered (int *regs_ever_clobbered)
      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++)
+    for (i = 0; i < 32; i++)
       if (!call_really_used_regs[i])
        regs_ever_clobbered[i] = 1;
 
@@ -7455,17 +7491,6 @@ s390_register_info (int clobbered_regs[])
 {
   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.
 
@@ -7474,6 +7499,29 @@ s390_register_info (int clobbered_regs[])
 
   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];
 
@@ -7724,7 +7772,7 @@ s390_init_frame_layout (void)
 {
   HOST_WIDE_INT frame_size;
   int base_used;
-  int clobbered_regs[16];
+  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
@@ -7759,6 +7807,157 @@ s390_init_frame_layout (void)
   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
@@ -7767,7 +7966,7 @@ s390_init_frame_layout (void)
 static void
 s390_update_frame_layout (void)
 {
-  int clobbered_regs[16];
+  int clobbered_regs[32];
 
   s390_register_info (clobbered_regs);
 
@@ -8204,8 +8403,10 @@ s390_emit_prologue (void)
   int offset;
   int next_fpr = 0;
 
-  /* Complete frame layout.  */
+  /* 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
@@ -9353,6 +9554,294 @@ s390_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   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.
 
@@ -11008,6 +11497,11 @@ s390_loop_unroll_adjust (unsigned nunroll, struct loop *loop)
 #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 b0e530f..d53fed7 100644 (file)
@@ -34,7 +34,8 @@ enum processor_flags
   PF_DFP = 16,
   PF_Z10 = 32,
   PF_Z196 = 64,
-  PF_ZEC12 = 128
+  PF_ZEC12 = 128,
+  PF_TX = 256
 };
 
 /* This is necessary to avoid a warning about comparing different enum
@@ -61,6 +62,8 @@ enum processor_flags
        (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
@@ -78,6 +81,8 @@ enum processor_flags
        (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)
@@ -93,23 +98,25 @@ enum processor_flags
 #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__");                \
-    }                                                  \
+#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)
+#define TARGET_DEFAULT             (MASK_64BIT | MASK_ZARCH | MASK_HARD_DFP | MASK_OPT_HTM)
 #else
 #define TARGET_DEFAULT             0
 #endif
index 0141b98..e12d153 100644 (file)
 (define_c_enum "unspec" [
    ; Miscellaneous
    UNSPEC_ROUND
-   UNSPEC_CCU_TO_INT
-   UNSPEC_CCZ_TO_INT
    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
    ; Atomic Support
    UNSPECV_CAS
    UNSPECV_ATOMIC_OP
+
+   ; Transactional Execution support
+   UNSPECV_TBEGIN
+   UNSPECV_TBEGINC
+   UNSPECV_TEND
+   UNSPECV_TABORT
+   UNSPECV_ETND
+   UNSPECV_NTSTG
+   UNSPECV_PPA
   ])
 
 ;;
    (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.
 
 (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"))]
+       (match_operand:CC 1 "nonimmediate_operand" " d,d,c,R,T,d,d"))]
   ""
   "@
    lr\t%0,%1
      (use (reg:SI 0))])
    (parallel
     [(set (match_operand:SI 0 "register_operand" "=d")
-         (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_CCU_TO_INT))
+         (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_STRCMPCC_TO_INT))
      (clobber (reg:CC CC_REGNUM))])]
   ""
 {
                      (match_dup 2)]
                      UNSPEC_TDC_INSN))
    (set (match_operand:SI 0 "register_operand" "=d")
-        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
+        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))]
   "TARGET_HARD_FLOAT"
 {
   operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
                      (match_dup 2)]
                      UNSPEC_TDC_INSN))
    (set (match_operand:SI 0 "register_operand" "=d")
-        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
+        (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
    [(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)))])
 
 
 ;
 (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))
+                   UNSPEC_STRCMPCC_TO_INT))
    (clobber (reg:CC CC_REGNUM))]
   ""
   "#"
 (define_insn_and_split "*cmpint_cc"
   [(set (reg CC_REGNUM)
         (compare (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
-                            UNSPEC_CCU_TO_INT)
+                            UNSPEC_STRCMPCC_TO_INT)
                  (const_int 0)))
    (set (match_operand:SI 0 "register_operand" "=d")
-        (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT))]
+        (unspec:SI [(match_dup 1)] UNSPEC_STRCMPCC_TO_INT))]
   "s390_match_ccmode (insn, CCSmode)"
   "#"
   "&& reload_completed"
 (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)))
+                                   UNSPEC_STRCMPCC_TO_INT)))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_ZARCH"
   "#"
   [(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)
+                              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_CCU_TO_INT)))]
+        (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_STRCMPCC_TO_INT)))]
   "s390_match_ccmode (insn, CCSmode) && TARGET_ZARCH"
   "#"
   "&& reload_completed"
        (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 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"
 (define_insn "*cjump_64"
   [(set (pc)
         (if_then_else
-          (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
+          (match_operator 1 "s390_comparison" [(reg CC_REGNUM)
+                                              (match_operand 2 "const_int_operand" "")])
           (label_ref (match_operand 0 "" ""))
           (pc)))]
   "TARGET_CPU_ZARCH"
 (define_insn "*cjump_31"
   [(set (pc)
         (if_then_else
-          (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
+          (match_operator 1 "s390_comparison" [(reg CC_REGNUM)
+                                              (match_operand 2 "const_int_operand" "")])
           (label_ref (match_operand 0 "" ""))
           (pc)))]
   "!TARGET_CPU_ZARCH"
   "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 ba38e6e..7dedb83 100644 (file)
@@ -104,6 +104,10 @@ mlong-double-64
 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
diff --git a/gcc/config/s390/s390intrin.h b/gcc/config/s390/s390intrin.h
new file mode 100644 (file)
index 0000000..e1a00ce
--- /dev/null
@@ -0,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 e50f2a4..1c85a3e 100644 (file)
@@ -8847,6 +8847,7 @@ instructions, but allow the compiler to schedule those calls.
 * 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::
@@ -14422,6 +14423,120 @@ bit in the processor status word.
 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 edd60ac..f6ab2ba 100644 (file)
@@ -1,3 +1,9 @@
+2013-06-27  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.
+
 2013-06-26  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/29800
diff --git a/gcc/testsuite/gcc.target/s390/htm-1.c b/gcc/testsuite/gcc.target/s390/htm-1.c
new file mode 100644 (file)
index 0000000..e6321de
--- /dev/null
@@ -0,0 +1,37 @@
+/* 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 a = 0;
+uint64_t 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 } } */
diff --git a/gcc/testsuite/gcc.target/s390/htm-nofloat-1.c b/gcc/testsuite/gcc.target/s390/htm-nofloat-1.c
new file mode 100644 (file)
index 0000000..df7e2ba
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=zEC12 -mzarch" } */
+
+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" } } */
diff --git a/gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c b/gcc/testsuite/gcc.target/s390/htm-xl-intrin-1.c
new file mode 100644 (file)
index 0000000..77ceeb7
--- /dev/null
@@ -0,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 247886a..27474d7 100644 (file)
@@ -1,3 +1,10 @@
+2013-06-27  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-20  Iain Sandoe  <iain@codesourcery.com>
            Cesar Philippidis  <cesar@codesourcery.com>
 
index a102e1e..580606f 100644 (file)
    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
@@ -52,4 +58,57 @@ cpu_relax (void)
   __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