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